WildFly Swarm microservice development: JAX-RS app deployed to a Docker container

WildFly Swarm is an interesting approach to the ‘small is good’ current trend that is ignoring the traditional, overly large Java EE App Servers, and instead deploying self-contained, executable Jars without needing a whole App Server to execute.

Rather than requiring the whole Java EE stack, WildFly Swarm lets you chose only the implementations of the parts that your service needs to execute. Need JAX-RS? Then pull it in via a Maven dependency. Need JPA? Pull that in too. Any other required transitive dependencies are automatically pulled in via Maven. Pulling in JAX-RS also requires a Servlet container and APIs, but this is pulled in for you via Maven transitive dependencies. The end result is a self-contained, packaged Jar that contains everything it needs to run with a ‘java -jar’ command.

I’ve been spending some time recently looking at getting Weblogic Portal 10.3.6 running in a Docker container (check my work in progress changes on GitHub here). As EE containers go, it’s big. It’s heavy. If you want to describe anything as a monolith, then this is your perfect example. So switching gears I wanted to go to the other extreme and look at how you would build a lightweight Java based service, and WildfFly Swarm looked pretty interesting.

I attended one of the sessions at JavaOne this year giving an intro to Swarm, so it’s been on my todo list to take a look.

Getting started with Swarm is actually pretty easy, as it’s all driven by Maven dependencies and plugins. There’s an easy to follow tutorial here. The example apps showing different WildFly components packaged using Swarm are also worth a look here.

I worked through the examples putting together a JAX-RS helloworld app, and also a Dockerfile to package and deploy it to a Docker container. It was actually pretty easy, and my app ended up looking much like the provided examples.

My example JAX-RS resource is pretty simple, nothing complicated here:

If you’re looking for the different WildFly services that you can package with Swarm, browsing the mvnrepository is a good place to start to quickly grab the mvn deps, or browse the examples or source.

For the Maven war and wildfly-storm plugins:

[code]<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins>/groupId>
<artifactId>maven-war-plugin>/artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<packagingExcludes>WEB-INF/lib/wildfly-swarm-*.jar>/packagingExcludes>
</configuration>
</plugin>
<plugin>
<groupId>org.wildfly.swarm</groupId>
<artifactId>wildfly-swarm-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>[/code]

Next, adding a dependency for the WildFly Swarm JAX-RS:

[code]
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>wildfly-swarm-jaxrs</artifactId>
<version>1.0.0.Alpha5</version>
</dependency>[/code]

To build the self-contained executable Jar, build with ‘mvn package’ – this will build the app as normal to target, but also include a *-swarm.jar – this the self-contained Jar containing all the WildFly dependencies, and can be run standalone with ‘java -jar helloworld-swarm-0.0.1-SNAPSHOT-swarm.jar’

Building a Docker container

Given that we’ve now got a simple, single, self-contained Jar, deploying this into a Docker container is also pretty easy as we have no other dependencies to worry about (we just need a JVM).

An example Dockerfile would look like (scroll to the right):

[code]
FROM java:openjdk-8-jdk
ADD target/helloworld-swarm-0.0.1-SNAPSHOT-swarm.jar /opt/helloworld-swarm.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/opt/helloworld-swarm.jar"]
[/code]

All we’re doing here is:
1. Creating an image based on the official openjdk image from DockerHub

2. Adding our built WildFly Swarm jar containing our app into /opt in the image

3. Exposing port 8080

4. Defining the Entrypoint that executes when the container starts

To create an image based on this Dockerfile:

docker build -t helloworld .

To start a container based on this image:

docker run -d -p 8080:8080 imageid

… this creates a new container based on the new container, runs it as a daemon, with port 8080 in the container exposed to 8080 on the host. Done!

Hit the URL of our endpoint using the IP of the running Docker-Machine:

To watch the logs of the running container, do:

docker logs -f containerid

In this case you see the output as the WildFly Undertow Servlet container starts up, and initializes our JAX-RS based app:

Pretty simple! We’ve got a minimal WildFly server starting up inside a Docker container in about 10s, and our app deploying in 2s. That’s pretty good if you ask me 🙂

 

Video: Docker in 5 minutes

I’ve been spending some time working with Docker recently – it’s incredible technology and understandable why it’s getting so much attention for automating reproducible runtimes.

Here’s a quick 5 min overview covering an overview in 5 mins by Vincent Batts, who works at Red Hat on Docker and OpenShift:

Docker ADD and COPY leave files owned by root by default

By trial and error I worked this out while building a container running Weblogic Portal 10.3.6 (see my Dockerfiles in the 10.3.6updates branch of my fork of oracle/docker: https://github.com/kevinhooke/weblogic-docker/tree/10.3.6updates).

Even if you do a ‘USER oracle’ followed by a COPY or ADD, the files transferred into the image are still owned by root. This was causing me issues as the WLST script could not read the files owned by root (as you’d expect).

This issue and the justification is described in issue 6119. It doesn’t seem that this will be fixed, it seems like it’s ‘working as designed’.