in Payara Kubernetes ~ read.

Your Java EE App on Kubernetes

In previous post we managed to run Payara on Kubernetes. This is of course bit dull without applications deployed. Next we will create an actual aplication, that will deploy with official Payara container. We will use the full profile Payara, just to demonstrate, that microservices can be built using standard distribution.

Let’s see what we will need to have our app in Kubernetes as well:

  • .war Maven project

  • Fabric8 Maven plugin

  • Docker for Windows / Docker tools

Installing Docker tooling

Given my hobby environment (Windows 10 Home), I cannot use the current Docker for Windows installation — remember, there’s no HyperV in Home edition. We need to install Docker Toolbox, its retired ancestor.

Sidecar approach

I assume you don’t upgrade your application server as often as you upgrade your applications. But when you do upgrade your server, you shouldn’t need to rebuild all of your applications. At least I wouldn’t like to do that.

Kubernetes gives you solution to that, called Sidecar containers. Instead of running single image, you put multiple images together, and they can speak to each other via localhost, or share directories.

So we will take Official Payara Docker Image, mount its autodeploy directory, and for our app we will build an image based on busybox, that will just copy our .war file to that folder.


The app-sidecar will be based on busybox, adding just 1MB of binaries to our app package.

Creating Docker images with Maven

One doesn’t need to leave its trusted tools for this fancy new tech! Everything you need to do concerning Docker images and Kubernetes you can achieve with Fabric8 Maven Plugin. Fabric8 is entire CI/CD pipeline for Kubernetes, and I will surely look into it in next posts — first, I need to understand what am I doing before I let magical tools do that for me ;).

The goal build of Fabric8 plugin constructs the Docker image based on image configuration. So this is what the interesting parts of pom.xml look like:

                <name>pdudits/%a:%l</name> (1)
                <alias>app-sidecar</alias> (2)
                    <from>busybox:1</from> (3)
                    <assembly>             (4)
1 The name of docker image. %a stands for artifactId, %l stands for release verson or latest for snapshot
2 we can use this alias for defining kuberenetes resources later
3 Our base image
4 The Maven Assembly Descriptor Name, describing what should be copied into the image (inside directory /maven by default).

To actually run the build you need to have Docker environment configured, as the plugin will call out to Docker. Minikube has this nice feature, that it will reuse Docker daemon from within minikube VM. You therefore doesn’t need to run another VM, just make sure to follow instructions of minikube docker-env before invoking maven:

d:\src\k8se9s\payara-sidecar>minikube docker-env
SET DOCKER_CERT_PATH=d:\src\kubernetes\.minikube\certs
REM Run this command to configure your shell:
REM @FOR /f "tokens=*" %i IN ('minikube docker-env') DO @%i

d:\src\k8se9s\payara-sidecar>@FOR /f "tokens=*" %i IN ('minikube docker-env') DO @%i

That also means, that whatever you build is immediately available for deployment into your Kubernetes cluster.

Kubernetes Resource Descriptors with Maven

fabric8:resource will take YAML files that serve as templates for resource descriptors, add some useful labels to them, and attaches them as build results.

For our sidecar we will create a Deployment. It is a declaration of what Pod should look like with added features like replication — more than one instances of same pod — and rolling upgrade. Especially the rolling upgrade is interesting for us. When you upgrade your app, a new Pod will be created, and when it starts successfully, the trafic will be directed to it, and after that the old pod is stopped.

So let’s see the file:

  replicas: 1
        run: payara
      - name: apps                    (1)
        emptyDir: {}
      - alias: app-sidecar            (2)
        - name: apps                  (3)
          mountPath: /apps
        command: ["sh","-c", "cp -a /maven/*.war /apps; tail -f /dev/null"] (4)
      - image: payara/server-full:171 (5)
        name: payara
        command: ["bin/asadmin", "start-domain", "-v"]
        ports:                        (6)
        - containerPort: 8080
          name: http
        - containerPort: 4848
          name: admin
        - name: apps                  (7)
          mountPath: /opt/payara41/glassfish/domains/domain1/autodeploy
1 That’s the directory shared between Docker images
2 We refer to the image via alias from pom.xml
3 The shared volume is accessible via /apps for container app-sidecar
4 We copy the files. Every container need to have running process, otherwise it is marked as crashed. Therefore we just hang, waiting for input from the void.
5 Payara is the other container in the pod
6 Yes that’s the old version, you’ll soon find out why…​
7 And the files we copied into /apps Payara sees in its autodeploy directory.

Another resource desciptor we’ll add will describe a service. This will give a set of pods that offer same service a common, load balanced IP address inside the cluster, and may expose it to outside world.

In our minikube, it will expose the port of the VM. In the cloud it will integrate with provider’s load balancers.

  - port: 8080
    protocol: TCP
    targetPort: 8080
    run: payara
  type: NodePort

The service exposes port 8080 (the http port) as port 8080 of the service API. The calls will be directed to pods, that have label run equal to payara. And to expose it to outside world, we will use a port of the node Kubernetes runs on — the minikube VM in our case.

Deploying to the cluster

Now that we have run our mvn clean install, we’ll have our docker image pushed, and our resources created.

Next we’ll deploy with mvn fabric8:deploy.

[INFO] <<< fabric8-maven-plugin:3.4.1:deploy (default-cli) < install @ payara-sidecar <<<
[INFO] --- fabric8-maven-plugin:3.4.1:deploy (default-cli) @ payara-sidecar ---
[INFO] F8: Using Kubernetes at in namespace default with manifest d:\src\k8se9s\payara-sidecar\target\classes\META-INF\fabric8\kubernetes.yml
[INFO] Using namespace: default
[INFO] Updating a Service from kubernetes.yml
[INFO] Updated Service: \payara-sidecar\target\fabric8\applyJson\default\service-payara-sidecar.json
[INFO] Updating Deployment from kubernetes.yml
[INFO] Updated Deployment: \payara-sidecar\target\fabric8\applyJson\default\deployment-payara.json
[INFO] F8: HINT: Use the command `kubectl get pods -w` to watch your pods start up

Here we are!

27405216 fca5ba9c 56d0 11e7 9ed1 d77db9216400.png

Our .war that were deploying to Payara now deploys to docker container with payara server inside Kubernetes!

minikube service payara-sidecar

Will open browser with the app. You need to add /payara-sidecar to the path.

P. S.

Look what this does:

>kubectl set image deployment/payara payara=payara/server-full:172
deployment "payara" image updated
27405642 aaa048aa 56d2 11e7 9df9 350547abcdca.png

New pod was started with newer version of application server, and after it started, the old one was removed.

comments powered by Disqus