Customizing the configuration of the WildFly Docker image

Default configuration is a great place to start with a project. We at JBoss try to make our projects (and products too!) usable out-of-box for as many use cases as we can, but there is no way that one configuration could satisfy everyone’s needs. For example, we ship 4 flavors of the standalone.xml configuration file with WildFly since there are so many different deployment scenarios. But this is still not enough. We need to be able to tweak it at any point. The jboss/wildfly image is not an exception here.

Following the Docker recreate — do not modify principle we do change the configuration by creating a new image (in most cases). This allows us to reuse the images (consider the jboss/wildfly image itself).

Of course this is not the only way to modify the WildFly configuration, so let’s iterate over available options.

Update 24.07.2014

One of the readers brought up that I forgot to mention one great tool: Augeas. I’ve added it now to the list and summary.

TL;DR;

See summary.

Boot time configuration

Using command line parameters (or environment variables) is the simplest way to modify the default configuration. This does not require rebuilding the image but is not persistent. Still, in many cases it is the best approach.

There is one obvious limitation: only a limited set of things can be modified. WildFly allows us to customize parameters with the switches for the standalone.sh or domain.sh startup scripts. The WildFly documentation has a great summary of the available options.

Command line parameters

With the jboss/wildfly image it’s easy to use command line parameters. Just override the default command when launching the container, for example:

docker run -it jboss/wildfly /opt/wildfly/bin/domain.sh -b 0.0.0.0 -Djboss.management.http.port=8888

This launches WildFly in domain mode (instead of standalone), binds the public endpoint to every interface, and exposes the management endpoint on port 8888 (by default bound to 127.0.0.1).

Note
You can create your own image which overrides only the command to run. Use the CMD instruction in Dockerfile.

Environment variables

Specifying environments variables with Docker is easy too:

docker run -it -e JBOSS_LOG_DIR=/opt/wildfly/logs jboss/wildfly

And now all logs will be saved to the /opt/wildfly/logs directory.

Note
You can modify environment variables in Docker images too. Use the ENV instruction in Dockerfile.

Explore the --env-file parameter of docker run if you want to set many environment variables.

sed

Note
This example is available on GitHub.

The sed command may be used in your Dockerfile to modify some (small) parts of the configuration. Please note that WildFly stores configuration in XML format so you will need to be careful when using sed :)

There are possible use cases for sed, for example when you want to disable the coloring on the console:

sed -i 's|named-formatter name="COLOR-PATTERN"|named-formatter name="PATTERN"|' /opt/wildfly/standalone/configuration/standalone.xml

In general no, I do not recommend using sed because using regular expressions may be tricky, especially if you’re not familiar with them.

xmlstarlet

Note
This example is available on GitHub.

The xmlstarlet tool is a set of commands that can be helpful when interacting with XML files. In our case one command is especially useful: xmlstarlet ed which is used to modify XML documents.

Let’s say we want to change the root-logger level to DEBUG:

xmlstarlet ed -L -u "//*[local-name()='root-logger']/*/@name" -v "DEBUG" /opt/wildfly/standalone/configuration/standalone.xml

You can place the above in your Dockerfile and call it done.

Although xmlstarlet is nice at finding (using XPath) and editing attributes or elements, it’s not a great tool to add complex elements. It can become easily very verbose. If you don’t trust sed but still want to tweak some elements, use xmlstarlet instead!

The jboss/wildfly image contains the xmlstarlet utility installed by default (as of July 23rd).

XSLT transformations

Note
This example is available on GitHub.

XSLT transformations are a nice way to execute conditional modifications of the WildFly application server configuration. The WildFly team provides examples of xsl files. You can use Saxon to execute the transformation:

java -jar /usr/share/java/saxon.jar -s:/opt/wildfly/standalone/configuration/standalone.xml -xsl:/opt/wildfly/customization/changeIPAddresses.xsl -o:/opt/wildfly/standalone/configuration/standalone.xml publicIPAddress=0.0.0.0

In this example we change the default binding address of the server for public ports.

For more information about using the Saxon utility from the CLI, please refer to the documentation.

The jboss/wildfly image contains the saxon package installed by default (as of July 23rd).

Using jboss-cli.sh

Note
This example is available on GitHub.

WildFly ships with a powerful CLI. The documentation contains a few examples of how the CLI can be used. Of course the CLI is perfect to modify the server configuration.

To be able to modify the configuration the WildFly server needs to be running. Since at the build time of a Docker image based on jboss/wildfly (in most cases) we do not start WildFly, this can be a problem.

One solution is to boot WildFly, execute the CLI commands and shutdown the server. I used this approach in my example. It adds a new ExampleMySQLDS datasource to the server. The main file that does the job is the execute.sh script:

#!/bin/bash

JBOSS_HOME=/opt/wildfly
JBOSS_CLI=$JBOSS_HOME/bin/jboss-cli.sh
JBOSS_MODE=${1:-"standalone"}
JBOSS_CONFIG=${2:-"$JBOSS_MODE.xml"}

function wait_for_server() {
  until `$JBOSS_CLI -c "ls /deployment" &> /dev/null`; do
    sleep 1
  done
}

echo "=> Starting WildFly server"
$JBOSS_HOME/bin/$JBOSS_MODE.sh -c $JBOSS_CONFIG >dev/null &

echo "=> Waiting for the server to boot"
wait_for_server

echo "=> Executing the commands"
$JBOSS_CLI -c --file=`dirname "$0"`/commands.cli

echo "=> Shutting down WildFly"
if [ "$JBOSS_MODE" = "standalone" ]; then
  $JBOSS_CLI -c ":shutdown"
else
  $JBOSS_CLI -c "/host=*:shutdown"
fi

The script is general purpose and can be reused in some other images. It can modify the configuration for any WildFly operating mode and for any configuration.

The commands.cli file contains commands executed in the CLI.

# Mark the commands below to be run as a batch
batch

# Add MySQL driver
/subsystem=datasources/jdbc-driver=mysql:add(driver-name=mysql,driver-module-name=com.mysql.jdbc,driver-xa-datasource-class-name=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource)

# Add the datasource
data-source add --name=UnifiedPushDS --driver-name=mysql --jndi-name=java:jboss/datasources/ExampleMySQLDS --connection-url=jdbc:mysql://localhost:3306/sample?useUnicode=true&characterEncoding=UTF-8 --user-name=user --password=password --use-ccm=false --max-pool-size=25 --blocking-timeout-wait-millis=5000 --enabled=true

# Execute the batch
run-batch

The CLI approach is very powerful and flexible. The only caveat is that WildFly needs to be running to use the CLI.

Using custom configuration files

Note
This example is available on GitHub.

The last approach is to simply maintain a separate configuration file for WildFly. Just ADD your configuration to the /opt/wildfly/{standalone|domain}/configuration directory and override the default boot command. You can for example remove some subsystems like I did in the example.

This is the simplest and cleanest approach. This way you have full control over the configuration at any time. The bad thing is that you need to maintain the file yourself. If a new version of WildFly will be released — you need to manually apply the changes to the configuration.

Augeas

Note
This example is available on GitHub.

Augeas is a general purpose configuration editing tool. It has plugins (lenses) for many configuration files. If your file isn’t on the list — don’t worry — you can use some generic lenses. In our case it’ll be the Xml lens.

Augeas builds a tree of the file loaded. Just take a look at the example where we change the root-logger (and cosnole-handler) level to DEBUG.

augtool -LA -e <<EOF
set /augeas/load/Xml/lens Xml.lns
set /augeas/load/Xml/incl[2] /opt/wildfly/standalone/configuration/standalone.xml
load
defvar subsystem "/files/opt/wildfly/standalone/configuration/standalone.xml/server/profile/subsystem[#attribute/xmlns='urn:jboss:domain:logging:2.0']"
set $subsystem/console-handler/level/#attribute/name "DEBUG"
set $subsystem/root-logger/level/#attribute/name "DEBUG"
save
EOF

It looks like XPath, but is much simpler. In previous exmaple we modified the attribute but it’s easy to add new elements too. Let’s add a TRACE log level for our pl.goldmann.example category:

set $subsystem/logger[last()+1]/#attribute/category "pl.goldmann.example"
set $subsystem/logger[last()]/level/#attribute/name "TRACE"

The first command adds a new <logger/> element with pl.goldmann.example as the category attribute and the next line adds a new <level/> element under the previously created <logger/> and sets the name atrtibute to TRACE. Isn’t nice?

Augeas is definitely a project worth to become familiar with. Above was just a tiny example of what it can do.

The jboss/wildfly image contains the augeas utility installed by default (as of July 24rd).

Summary

Every approach has pros and cons. Boot time configuration is great if you want to change some exposed parameters. The sed and xmlstarlet options are similar providing a simple way to change some parts of the configuration. But this is not flexible. XSLT transformations are very powerful, but they require some amount of work to write the stylesheets properly. The jboss-cli.sh aproach is very good if you don’t mind starting and stopping WildFly at the build time. Maintaining own configuration file at the first glance looks like a best solution and probably it is in some cases. If you want to do have a powerful yet simple way of changing the configuration — use Augeas.

What’s your approach?

comments powered by Disqus