Creating custom WildFly Images for Docker

This is the second tutorial about Docker. In the first one How to run WildFly with Docker we have learnt how to install Docker on a Linux machine and pull a WildFly image on the top of it. Now we will learn how to deploy applications by using Docker Files.

Coding a simple Dockerfile

First of all, what is a Dockerfile? a Dockerfile has a special mission: automation of Docker image creation. Once, you write build instructions into Dockerfile, you can build your own Docker images with custom environment configuration.

A Dockerfile consists of a set of commands which can be written in a text file named “Dockerfile”. The purpose of our first Docker file will be adding an application named “helloworld.war” in the deployments folder of the standalone installation. This will trigger automatic deployment.

Here we go. Create a file named Dockerfile and include the following instructions:

FROM quay.io/wildfly/wildfly

ADD helloworld.war /opt/jboss/wildfly/standalone/deployments/

Now make sure that the helloworld.war application is in the same folder as the Dockerfile:

$ ls

Dockerfile  helloworld.war

wildfly-centos7 image

The new image quay.io/wildfly/wildfly replaces the image quay.io/wildfly/wildfly-centos7 that is now deprecated.

To build a new Docker image is pretty simple, you have to choose a name (actually a tag) and issue a docker build command:

$ docker build --tag=wildfly-helloworld .

Step 0 : FROM quay.io/wildfly/wildfly

 ---> 365390553f92

Step 1 : ADD helloworld.war /opt/jboss/wildfly/standalone/deployments/

 ---> Using cache

 ---> fc3e0048139e

Successfully built fc3e0048139e

So we have successfully built the wildfly-helloworld image. Let’s check it by issuing a docker images command:

$ docker images | grep wildfly
wildfly-helloworld                            latest        b29f3929de43   10 seconds ago   1.35GB
quay.io/wildfly/wildfly                       latest        8782e46e2c2a   6 weeks ago      1.35GB

So now you can start Docker with just:

$ docker run -p 8080:8080 wildfly-helloworld

The application server will start. Verify that the console that the application has been started:

18:18:47,682 INFO  [org.jboss.as.server] (ServerService Thread Pool -- 28) JBAS0

18559: Deployed "helloworld.war" (runtime-name : "helloworld.war")

Testing the application on Docker

Next step will be testing our application. Out of the box, you should be able to reach WildFly from any available network interface as you can see from the Server logs:

16:50:33,053 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://0.0.0.0:9990/management
16:50:33,053 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://0.0.0.0:9990

Therefore, to test the helloworld application it is sufficient to reach the address localhost:8080/<WebContext>/<Resource>:

wildfly docker

On the other hand, if you want to use the Docker’s IP Address, check the Container Id first:

$ docker ps

CONTAINER ID        IMAGE                       COMMAND                CREATED             STATUS              PORTS                NAMES
b63e7345bf81        wildfly-helloworld:latest   "/opt/jboss/wildfly/   18 minutes ago      Up 18 minutes       9990/tcp, 8080/tcp   cranky_pasteur

And then:

$ docker inspect -f '{{ .NetworkSettings.IPAddress }}' b63e7345bf81

172.17.0.4

Your application is ready to be tested at the address http://172.17.0.4:8080/helloworld/HelloWorld

Deploying applications using the Web Admin console

In order to deploy applications using the Web console we will need to add an user with add-user.sh script which is included in the bin folder of the application server. There are several way to do that, but we can have it done while building our image, so let’s add to our Dockerfile the following command which will create an user in non interactive mode:

FROM quay.io/wildfly/wildfly

RUN /opt/jboss/wildfly/bin/add-user.sh -m -u admin -p Password1! --silent

CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0"]

Now let’s rebuild our image:

$ docker build --tag=wildfly-helloworld .

We will start now the application server. Since we need to access the management interfaces from our host machine, we need to export both ports using the -p option:

$ docker run -p 8080:8080 -p 9990:9990 wildfly-helloworld

Fine. Inspect for the Container ID using docker ps and find the IP Address used by the application server:

$ docker ps
CONTAINER ID   IMAGE                COMMAND                  CREATED              STATUS              PORTS                                                                                            NAMES
3da010da7e93   wildfly-helloworld   "container-entrypoin…"   About a minute ago   Up About a minute   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 0.0.0.0:9990->9990/tcp, :::9990->9990/tcp, 8778/tcp   lucid_hamilton

Now log into the Admin Web console at localhost:9990 and enter the credentials we have included into the Dockerfile

Great! we are into the Docker Admin Console.

From there we can access the Runtime tab and add applications which are hosted on our machine.

wildfly docker

Customize WildFly Configuration on Docker

So far we have learnt about the RUN command to execute the add-user.sh script. We will now use it to run a Command Line Interface (CLI) script that will customize WildFly Configuration.

Here is out minimalist extensions.cli script:

embed-server --std-out=echo  

/system-property=foo:add(value=demo)

quit

Please notice that we use embed-server mode so that we can start the server in embedded mode for the purpose of running the CLI commands. More about WildFly emdedded mode here: How to configure WildFly from the CLI in embedded mode

Next, modify your Dockerfile so that you will fire the jboss-cli.sh command to launch the above script:

FROM quay.io/wildfly/wildfly

COPY config.cli /opt/jboss/wildfly/bin/config.cli

RUN /opt/jboss/wildfly/bin/jboss-cli.sh --file="/opt/jboss/wildfly/bin/config.cli"

Then, build again your Docker image.

$ docker build --tag=wildfly-helloworld .

You will notice that during the Build phase the emdedded mode will startup the server and run the CLI command. At the end of it, run the Image:

$ docker run -p 8080:8080 wildfly-helloworld

Finally, you can check your Server configuration by running the read-resource command on your System Property.

Firstly, grab the Container Id:

$ docker ps
CONTAINER ID   IMAGE                COMMAND                  CREATED          STATUS          PORTS                                                 NAMES
d5fe59a18b22   wildfly-helloworld   "container-entrypoin…"   20 seconds ago   Up 19 seconds   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 8778/tcp   adoring_shtern

Then, run the CLI Command “/system-property=foo:read-resource” on your remote Container:

$ docker exec d5fe59a18b22 /opt/jboss/wildfly/bin/jboss-cli.sh -c "/system-property=foo:read-resource"
{
    "outcome" => "success",
    "result" => {"value" => "demo"}
}

Monitoring the WildFly Image

Finally, we will show how to monitor the WildFly image running in a Docker container. To do that, you need to launch WildFly version of jconsole, which is available in the JBOSS_HOME/bin folder of the application server

Please note that you will need using the same local version of WildFly to connect to the image in the container. This is needed since the wrapper script of jconsole will add some wildfly libraries that must be of the same version as wildFly’s docker image.

You can launch JConsole using JMX over remoting as protocol on port 9990. Here is the URI to be used for the Connection: service:jmx:remote+http://172.17.0.2:9990

Also you need to include in the Username and Password the credentials for your User as indicated in the following picture:

jconsole monitoring wildfly

You will see that in a few seconds you will reach JConsole’s main page:

jconsole monitoring wildfly

Conclusion

This article was a walk though the creation of custom Docker images including application and configuration on top of WildFly runtime Image.