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 🙂
HI i having issues when bringing the container up.
[org.wildfly.extension.undertow] (MSC service thread 1-2) WFLYU
T0012: Started server default-server.
2018-03-15 19:00:22,209 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-4) MSC000001
: Failed to start service org.wildfly.undertow.listener.default: org.jboss.msc.service.StartE
xception in service org.wildfly.undertow.listener.default: WFLYUT0082: Could not start ‘defau
lt’ listener.
at org.wildfly.extension.undertow.ListenerService.start(ListenerService.java:181)
at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControll
erImpl.java:2032)
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.ja
va:1955)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.net.SocketException: Protocol family unavailable
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Net.java:433)
at sun.nio.ch.Net.bind(Net.java:425)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
at org.xnio.nio.NioXnioWorker.createTcpConnectionServer(NioXnioWorker.java:179)
at org.xnio.XnioWorker.createStreamConnectionServer(XnioWorker.java:310)
at org.wildfly.extension.undertow.HttpListenerService.startListening(HttpListenerServ
ice.java:106)
at org.wildfly.extension.undertow.ListenerService.start(ListenerService.java:169)
… 5 more
2018-03-15 19:00:22,214 ERROR [org.jboss.as.controller.management-operation] (Controller Boot
Thread) WFLYCTL0013: Operation (“add”) failed – address: ([
(“subsystem” => “undertow”),
(“server” => “default-server”),
(“http-listener” => “default”)
]) – failure description: {“WFLYCTL0080: Failed services” => {“org.wildfly.undertow.listener.
default” => “WFLYUT0082: Could not start ‘default’ listener.
Caused by: java.net.SocketException: Protocol family unavailable”}}
2018-03-15 19:00:22,255 INFO [org.jboss.as.controller] (Controller Boot Thread) WFLYCTL0183:
Service status report
WFLYCTL0186: Services which failed to start: service org.wildfly.undertow.listener.def
ault: WFLYUT0082: Could not start ‘default’ listener.
2018-03-15 19:00:22,284 INFO [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Res
uming server
2018-03-15 19:00:22,298 ERROR [org.jboss.as] (Controller Boot Thread) WFLYSRV0026: WildFly Sw
arm 2018.3.3 (WildFly Core 3.0.8.Final) started (with errors) in 1564ms – Started 97 of 105 s
ervices (1 services failed or missing dependencies, 16 services are lazy, passive or on-deman
d)
2018-03-15 19:00:22,302 ERROR [stderr] (main) java.lang.RuntimeException: org.jboss.msc.servi
ce.StartException in service org.wildfly.undertow.listener.default: WFLYUT0082: Could not sta
rt ‘default’ listener.
2018-03-15 19:00:22,304 ERROR [stderr] (main) at org.wildfly.swarm.spi.api.ClassLoading.wit
hTCCL(ClassLoading.java:45)
2018-03-15 19:00:22,305 ERROR [stderr] (main) at org.wildfly.swarm.container.runtime.Server
BootstrapImpl.bootstrap(ServerBootstrapImpl.java:113)
2018-03-15 19:00:22,305 ERROR [stderr] (main) at org.wildfly.swarm.Swarm.start(Swarm.java:3
98)
2018-03-15 19:00:22,306 ERROR [stderr] (main) at org.wildfly.swarm.Swarm.main(Swarm.java:74
2)
2018-03-15 19:00:22,306 ERROR [stderr] (main) at sun.reflect.NativeMethodAccessorImpl.invok
e0(Native Method)
2018-03-15 19:00:22,307 ERROR [stderr] (main) at sun.reflect.NativeMethodAccessorImpl.invok
e(NativeMethodAccessorImpl.java:62)
2018-03-15 19:00:22,307 ERROR [stderr] (main) at sun.reflect.DelegatingMethodAccessorImpl.i
nvoke(DelegatingMethodAccessorImpl.java:43)
2018-03-15 19:00:22,308 ERROR [stderr] (main) at java.lang.reflect.Method.invoke(Method.jav
a:498)
2018-03-15 19:00:22,309 ERROR [stderr] (main) at org.wildfly.swarm.bootstrap.MainInvoker.in
voke(MainInvoker.java:53)
2018-03-15 19:00:22,309 ERROR [stderr] (main) at org.wildfly.swarm.bootstrap.Main.run(Main.
java:132)
2018-03-15 19:00:22,309 ERROR [stderr] (main) at org.wildfly.swarm.bootstrap.Main.main(Main
.java:85)
2018-03-15 19:00:22,310 ERROR [stderr] (main) Caused by: org.jboss.msc.service.StartException
in service org.wildfly.undertow.listener.default: WFLYUT0082: Could not start ‘default’ list
ener.
2018-03-15 19:00:22,310 ERROR [stderr] (main) at org.wildfly.extension.undertow.ListenerSer
vice.start(ListenerService.java:181)
2018-03-15 19:00:22,315 ERROR [stderr] (main) at org.jboss.msc.service.ServiceControllerImp
l$StartTask.startService(ServiceControllerImpl.java:2032)
2018-03-15 19:00:22,316 ERROR [stderr] (main) at org.jboss.msc.service.ServiceControllerImp
l$StartTask.run(ServiceControllerImpl.java:1955)
2018-03-15 19:00:22,316 ERROR [stderr] (main) at java.util.concurrent.ThreadPoolExecutor.ru
nWorker(ThreadPoolExecutor.java:1142)
2018-03-15 19:00:22,316 ERROR [stderr] (main) at java.util.concurrent.ThreadPoolExecutor$Wo
rker.run(ThreadPoolExecutor.java:617)
2018-03-15 19:00:22,317 ERROR [stderr] (main) at java.lang.Thread.run(Thread.java:745)
2018-03-15 19:00:22,317 ERROR [stderr] (main) Caused by: java.net.SocketException: Protocol f
amily unavailable
2018-03-15 19:00:22,318 ERROR [stderr] (main) at sun.nio.ch.Net.bind0(Native Method)
2018-03-15 19:00:22,319 ERROR [stderr] (main) at sun.nio.ch.Net.bind(Net.java:433)
2018-03-15 19:00:22,320 ERROR [stderr] (main) at sun.nio.ch.Net.bind(Net.java:425)
2018-03-15 19:00:22,320 ERROR [stderr] (main) at sun.nio.ch.ServerSocketChannelImpl.bind(Se
rverSocketChannelImpl.java:223)
2018-03-15 19:00:22,321 ERROR [stderr] (main) at sun.nio.ch.ServerSocketAdaptor.bind(Server
SocketAdaptor.java:74)
2018-03-15 19:00:22,321 ERROR [stderr] (main) at org.xnio.nio.NioXnioWorker.createTcpConnec
tionServer(NioXnioWorker.java:179)
2018-03-15 19:00:22,323 ERROR [stderr] (main) at org.xnio.XnioWorker.createStreamConnection
Server(XnioWorker.java:310)
2018-03-15 19:00:22,323 ERROR [stderr] (main) at org.wildfly.extension.undertow.HttpListene
rService.startListening(HttpListenerService.java:106)
2018-03-15 19:00:22,323 ERROR [stderr] (main) at org.wildfly.extension.undertow.ListenerSer
vice.start(ListenerService.java:169)
2018-03-15 19:00:22,324 ERROR [stderr] (main) … 5 more
2018-03-15 19:00:22,324 ERROR [stderr] (main) java.lang.RuntimeException: org.jboss.msc.servi
ce.StartException in service org.wildfly.undertow.listener.default: WFLYUT0082: Could not sta
rt ‘default’ listener.
2018-03-15 19:00:22,324 ERROR [stderr] (main) at org.wildfly.swarm.spi.api.ClassLoading.wit
hTCCL(ClassLoading.java:45)
2018-03-15 19:00:22,325 ERROR [stderr] (main) at org.wildfly.swarm.container.runtime.Server
BootstrapImpl.bootstrap(ServerBootstrapImpl.java:113)
2018-03-15 19:00:22,325 ERROR [stderr] (main) at org.wildfly.swarm.Swarm.start(Swarm.java:3
98)
2018-03-15 19:00:22,326 ERROR [stderr] (main) at org.wildfly.swarm.Swarm.main(Swarm.java:74
2)
2018-03-15 19:00:22,326 ERROR [stderr] (main) at sun.reflect.NativeMethodAccessorImpl.invok
e0(Native Method)
2018-03-15 19:00:22,326 ERROR [stderr] (main) at sun.reflect.NativeMethodAccessorImpl.invok
e(NativeMethodAccessorImpl.java:62)
2018-03-15 19:00:22,327 ERROR [stderr] (main) at sun.reflect.DelegatingMethodAccessorImpl.i
nvoke(DelegatingMethodAccessorImpl.java:43)
2018-03-15 19:00:22,327 ERROR [stderr] (main) at java.lang.reflect.Method.invoke(Method.jav
a:498)
2018-03-15 19:00:22,327 ERROR [stderr] (main) at org.wildfly.swarm.bootstrap.MainInvoker.in
voke(MainInvoker.java:53)
2018-03-15 19:00:22,328 ERROR [stderr] (main) at org.wildfly.swarm.bootstrap.Main.run(Main.
java:132)
2018-03-15 19:00:22,328 ERROR [stderr] (main) at org.wildfly.swarm.bootstrap.Main.main(Main
.java:85)
2018-03-15 19:00:22,328 ERROR [stderr] (main) Caused by: org.jboss.msc.service.StartException
in service org.wildfly.undertow.listener.default: WFLYUT0082: Could not start ‘default’ list
ener.
2018-03-15 19:00:22,329 ERROR [stderr] (main) at org.wildfly.extension.undertow.ListenerSer
vice.start(ListenerService.java:181)
2018-03-15 19:00:22,329 ERROR [stderr] (main) at org.jboss.msc.service.ServiceControllerImp
l$StartTask.startService(ServiceControllerImpl.java:2032)
2018-03-15 19:00:22,329 ERROR [stderr] (main) at org.jboss.msc.service.ServiceControllerImp
l$StartTask.run(ServiceControllerImpl.java:1955)
2018-03-15 19:00:22,330 ERROR [stderr] (main) at java.util.concurrent.ThreadPoolExecutor.ru
nWorker(ThreadPoolExecutor.java:1142)
2018-03-15 19:00:22,330 ERROR [stderr] (main) at java.util.concurrent.ThreadPoolExecutor$Wo
rker.run(ThreadPoolExecutor.java:617)
2018-03-15 19:00:22,331 ERROR [stderr] (main) at java.lang.Thread.run(Thread.java:745)
2018-03-15 19:00:22,331 ERROR [stderr] (main) Caused by: java.net.SocketException: Protocol f
amily unavailable
2018-03-15 19:00:22,331 ERROR [stderr] (main) at sun.nio.ch.Net.bind0(Native Method)
2018-03-15 19:00:22,332 ERROR [stderr] (main) at sun.nio.ch.Net.bind(Net.java:433)
2018-03-15 19:00:22,332 ERROR [stderr] (main) at sun.nio.ch.Net.bind(Net.java:425)
2018-03-15 19:00:22,332 ERROR [stderr] (main) at sun.nio.ch.ServerSocketChannelImpl.bind(Se
rverSocketChannelImpl.java:223)
2018-03-15 19:00:22,332 ERROR [stderr] (main) at sun.nio.ch.ServerSocketAdaptor.bind(Server
SocketAdaptor.java:74)
2018-03-15 19:00:22,333 ERROR [stderr] (main) at org.xnio.nio.NioXnioWorker.createTcpConnec
tionServer(NioXnioWorker.java:179)
2018-03-15 19:00:22,333 ERROR [stderr] (main) at org.xnio.XnioWorker.createStreamConnection
Server(XnioWorker.java:310)
2018-03-15 19:00:22,333 ERROR [stderr] (main) at org.wildfly.extension.undertow.HttpListene
rService.startListening(HttpListenerService.java:106)
2018-03-15 19:00:22,334 ERROR [stderr] (main) at org.wildfly.extension.undertow.ListenerSer
vice.start(ListenerService.java:169)
2018-03-15 19:00:22,334 ERROR [stderr] (main) … 5 more
2018-03-15 19:00:22,345 INFO [org.wildfly.swarm] (Thread-2) WFSWARM0027: Shutdown requested
2018-03-15 19:00:22,357 INFO [org.jboss.as.server] (Thread-3) WFLYSRV0220: Server shutdown h
as been requested via an OS signal
2018-03-15 19:00:22,357 INFO [org.wildfly.extension.undertow] (MSC service thread 1-4) WFLYU
T0004: Undertow 1.4.18.Final stopping
2018-03-15 19:00:22,389 INFO [org.jboss.as] (MSC service thread 1-1) WFLYSRV0050: WildFly Swarm 2018.3.3 (WildFly Core 3.0.8.Final) stopped in 33ms
C:\DEV\TESTCODE\microservice>docker logs -f helloworld
Error response from daemon: No such container: helloworld
Are you passing ip4 or ip6 params, like -Djava.net.preferIPv4Stack=false java.net.preferIPv6Addresses=true or some combination? See if this helps: https://developer.jboss.org/thread/241488