├── .gitignore ├── modules └── system │ └── layers │ └── base │ └── com │ └── mysql │ └── driver │ └── main │ ├── mysql-connector-java-5.1.38-bin.jar │ └── module.xml ├── customization ├── execute.sh └── commands.cli ├── bin └── entrypoint.sh ├── Dockerfile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | -------------------------------------------------------------------------------- /modules/system/layers/base/com/mysql/driver/main/mysql-connector-java-5.1.38-bin.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BITFORCE-IT/WildFlyApp/HEAD/modules/system/layers/base/com/mysql/driver/main/mysql-connector-java-5.1.38-bin.jar -------------------------------------------------------------------------------- /modules/system/layers/base/com/mysql/driver/main/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /customization/execute.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Usage: execute.sh [WildFly mode] [configuration file] 4 | # 5 | # The default mode is 'standalone' and default configuration is based on the 6 | # mode. It can be 'standalone.xml' or 'domain.xml'. 7 | 8 | JBOSS_HOME=/opt/jboss/wildfly 9 | JBOSS_CLI=$JBOSS_HOME/bin/jboss-cli.sh 10 | JBOSS_MODE=${1:-"standalone"} 11 | JBOSS_CONFIG=${2:-"$JBOSS_MODE.xml"} 12 | 13 | function wait_for_server() { 14 | until `$JBOSS_CLI -c "ls /deployment" &> /dev/null`; do 15 | sleep 1 16 | done 17 | } 18 | 19 | echo "=> Starting WildFly server" 20 | $JBOSS_HOME/bin/$JBOSS_MODE.sh -c $JBOSS_CONFIG > /dev/null & 21 | 22 | echo "=> Waiting for the server to boot" 23 | wait_for_server 24 | 25 | echo "=> Executing the commands" 26 | $JBOSS_CLI -c --file=`dirname "$0"`/commands.cli 27 | 28 | echo "=> Shutting down WildFly" 29 | if [ "$JBOSS_MODE" = "standalone" ]; then 30 | $JBOSS_CLI -c ":shutdown" 31 | else 32 | $JBOSS_CLI -c "/host=*:shutdown" 33 | fi 34 | 35 | -------------------------------------------------------------------------------- /bin/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Fail fast, including pipelines 4 | set -eo pipefail 5 | 6 | # get the ip address of the container to bind too 7 | host_ip=$(hostname -I) 8 | 9 | # replace our markers in the standalone.xml, which we added over the CLI Command script on container build. 10 | sed -e "s/###DB_HOST###/${DB_HOST}/g" \ 11 | -e "s/###DB_PORT###/${DB_PORT}/g" \ 12 | -e "s/###DB_SCHEMA###/${DB_SCHEMA}/g" \ 13 | -e "s/###DB_USER###/${DB_USER}/g" \ 14 | -e "s/###DB_PASSWORD###/${DB_PASSWORD}/g" \ 15 | -i /opt/jboss/wildfly/standalone/configuration/standalone.xml 16 | 17 | # if the container CMD value is jboss, run wildfly 18 | if [ "$1" = 'jboss' ]; then 19 | echo "Starting application on ${host_ip}" 20 | exec /opt/jboss/wildfly/bin/standalone.sh -b=${host_ip} -bmanagement=${host_ip} -bunsecure=${host_ip} --server-config=standalone.xml -Djboss.server.log.dir=/data/logs -Daws.accessKeyId=${AWS_KEY} -Daws.secretKey=${AWS_SECRET} 21 | fi 22 | 23 | # if the container CMD value is not jboss, run the given CMD value directly on the system 24 | # this allows for example to start the container running a bash shell instead of the wildfly. 25 | exec "$@" 26 | -------------------------------------------------------------------------------- /customization/commands.cli: -------------------------------------------------------------------------------- 1 | connect 2 | batch 3 | 4 | # register the mysql driver modul on name mysql 5 | /subsystem=datasources/jdbc-driver=mysql:add( \ 6 | driver-name=mysql, \ 7 | driver-module-name=com.mysql.driver, \ 8 | driver-xa-datasource-class-name=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource \ 9 | ) 10 | 11 | # add a xa datasource using the mysql driver module. 12 | # instead of writing real connection values we use placeholders, which we can replace 13 | # on the fly when container starts. 14 | xa-data-source add \ 15 | --name=MyCustomDS \ 16 | --driver-name=mysql \ 17 | --jndi-name=java:jboss/datasources/MyCustomDS \ 18 | --user-name=###DB_USER### \ 19 | --password=###DB_PASSWORD### \ 20 | --use-ccm=false \ 21 | --max-pool-size=25 \ 22 | --blocking-timeout-wait-millis=5000 \ 23 | --enabled=true 24 | /subsystem=datasources/xa-data-source=MyCustomDS/xa-datasource-properties=ServerName:add(value=###DB_HOST###) 25 | /subsystem=datasources/xa-data-source=MyCustomDS/xa-datasource-properties=PortNumber:add(value=###DB_PORT###) 26 | /subsystem=datasources/xa-data-source=MyCustomDS/xa-datasource-properties=DatabaseName:add(value=###DB_SCHEMA###) 27 | 28 | # add a new periodic file handler for custom log file 29 | /subsystem=logging/periodic-rotating-file-handler=CUSTOM-LOG:add(level=DEBUG, file={"relative-to"=>"jboss.server.log.dir", "path"=>"custom.log"}, suffix=".yyyy-MM-dd", formatter="%d{MM-dd-yyyy HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n", append=false, autoflush=true) 30 | 31 | # bind a logger category to your custom log handler 32 | /subsystem=logging/logger=com.my.application.category:add(use-parent-handlers=true,handlers=["CUSTOM-LOG"]) 33 | 34 | run-batch 35 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jboss/wildfly:13.0.0.Final 2 | MAINTAINER BITFORCE-IT GmbH René Mertins r.mertins@bitforce-it.de 3 | 4 | # go root to do copy and rights stuff 5 | USER root 6 | 7 | # create folders and copy data into 8 | RUN mkdir /start 9 | ADD bin/ /start 10 | ADD customization /opt/jboss/wildfly/customization/ 11 | ADD modules/ /opt/jboss/wildfly/modules 12 | 13 | # set owner ship and rights 14 | RUN chown -R jboss:jboss /start 15 | RUN chown -R jboss:jboss /opt/jboss/wildfly/modules 16 | RUN chown -R jboss:jboss /opt/jboss/wildfly/customization 17 | RUN chmod 775 /opt/jboss/wildfly/customization/execute.sh 18 | RUN chmod 775 /start/entrypoint.sh 19 | 20 | # switch back to app user 21 | USER jboss 22 | 23 | # set exposed ports for NAT 24 | EXPOSE 8080 25 | EXPOSE 9990 26 | 27 | # provide mount able volume path 28 | VOLUME /data/logs 29 | 30 | # setup environment 31 | ENV DB_HOST 10.0.0.1 32 | ENV DB_PORT 3306 33 | ENV DB_USER db_user 34 | ENV DB_PASSWORD db_password 35 | ENV DB_SCHEMA db_schema 36 | ENV AWS_KEY AKXXXXXXXXXXXXXXXXXX 37 | ENV AWS_SECRET fDEXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 38 | 39 | # add management user to jboss wildfly 10 application server 40 | RUN /opt/jboss/wildfly/bin/add-user.sh admin password --silent 41 | # run our app service customization script using standalone mode with standalone.xml configuration 42 | RUN /opt/jboss/wildfly/customization/execute.sh standalone standalone.xml 43 | 44 | RUN rm -rf /opt/jboss/wildfly/standalone/configuration/standalone_xml_history/current 45 | 46 | # copy the application 47 | # ADD Application.ear /opt/jboss/wildfly/standalone/deployments/Application.ear 48 | 49 | # NOTE!!! 50 | # Do frequently changing stuff at the end of a dockerfile, because if there is no change in previous steps the cache is used. 51 | # Is one step changing something, all following steps have to be redone. 52 | 53 | # set the entry point to custom script 54 | ENTRYPOINT ["/start/entrypoint.sh"] 55 | 56 | # define pseudo command, which is recognized by entry point script 57 | CMD ["jboss"] 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JBoss Wildfly application image example 2 | This is a Docker image based on jboss/wildfly official image. 3 | Enhancing it with a useful configuration and deployment process. 4 | This image is designed to make it as simple as possible to start, configure, 5 | deploy and run a JEE application on Wildfly application server. 6 | 7 | It shows how to enable runtime configuration over environment variables, to make 8 | it really easy to deploy huge amounts of this image. 9 | 10 | ## Usage 11 | First clone this repository. 12 | 13 | git clone https://github.com/BITFORCE-IT/WildflyApp 14 | 15 | Then enter the repository directory "WildflyApp" 16 | 17 | Copy your JEE application package (.ear,.war,.sar) into the repository folder. 18 | 19 | Open the "Dockerfile" with your favorite text editor. Uncomment and change 20 | the ADD my application line. To copy your application package into the image. 21 | 22 | ADD Application.ear /opt/jboss/wildfly/standalone/deployments/Application.ear 23 | 24 | Build the image running the build command inside the repository folder. 25 | 26 | docker build -t my-wildlfy-app . 27 | 28 | Then run it with the run command. 29 | 30 | docker run my-wildfly-app 31 | 32 | > Doing this will start the Wildfly server, trying to deploy your application. 33 | > Which will in most cases work. But this image also setups a data source which 34 | > tries to connect to a MySQL db. That will give you some errors or probably let the 35 | > application server crash. This is no mistake! Further configuration and customization 36 | > is explained later. 37 | 38 | ## Structure 39 | This image has the following structure: 40 | 41 | 1. bin/ 42 | 43 | scripting stuff is located, that is copied to /start and made runnable 44 | 45 | 1. entrypoint.sh 46 | 47 | is the entry point shell script of this image 48 | 49 | 2. customization/ 50 | 51 | Wildfly configuration stuff is in here, which is run at image build phase 52 | 53 | 1. execute.sh 54 | 55 | this script is run by Dockerfile on image build. It starts 56 | the application server, enters the CLI and runs a command script 57 | to configure Wildfly for your needs. 58 | Thanks to [this blog post](https://goldmann.pl/blog/2014/07/23/customizing-the-configuration-of-the-wildfly-docker-image/) 59 | 60 | 2. commands.cli 61 | 62 | Wildfly configuration commands file, which can be used with the 63 | Wildfly CLI to configure the Wildfly for your needs. 64 | 65 | 3. modules/ 66 | 67 | this folder is copied over the Wildfly modules folder. Place your modules 68 | like jdbc drivers in here and use the correct folder structure. 69 | For example a MySQL driver jar would end up in `modules/system/layers/base/com/mysql` 70 | 71 | 4. Dockerfile 72 | 73 | The Dockerfile himself. 74 | 75 | ## Description 76 | What happens here? 77 | 78 | It's very simple. This image does two things. 79 | 80 | 1. It builds a Docker image based on jboss/wildfly. In the build process 81 | the application server is started one time and the CLI is used to configure 82 | the application server. Doing this it places placeholders in the configuration file 83 | which are later replaced by environment variables during start up. 84 | 85 | 2. On start, the image uses his own entry point script, which checks environment 86 | and replaces placeholders with environment variables in the configuration file and then 87 | starts the application server. 88 | 89 | The result is, that you have an image which you can easily setup during build 90 | phase by simple editing of commands.cli file and fine-tune to current environment during 91 | start. 92 | 93 | ### Configure Wildfly during build phase 94 | The Wildfly application server in this image is configured over his CLI 95 | during the build phase. This is done by calling the customization/execute.sh script 96 | inside the Dockerfile. 97 | 98 | RUN /opt/jboss/wildfly/customization/execute.sh standalone standalone.xml 99 | 100 | It accepts two parameters: 101 | 102 | - start in **standalone** or **domain** mode 103 | - used configuration filename 104 | 105 | When not given any parameters the defaults are **standalone** mode with **standalone.xml** 106 | configuration. 107 | 108 | > This example is tested with standalone mode and standalone.xml file. 109 | > When using domain mode or other configuration file, look through Dockerfile 110 | > , entrypoint.sh and execute.sh for hardcoded configuration file names and command names. 111 | > Change them to your according needs. 112 | 113 | The execute.sh script will start the Wildfly and waits till it is up and running in default configuration 114 | like it comes from JBoss. Then it uses the Wildfly CLI to run the commands.cli file. After this it stops 115 | Wildfly again. 116 | 117 | In this example, 4 different common tasks are done over CLI. 118 | 119 | 1. It registers the MySQL driver module which was copied into Wildfly 120 | 2. Creates an XA data source using the MySQL driver and placing placeholders instead 121 | of real parameters. 122 | 3. It adds a periodic log file handler 123 | 4. It adds a logger category using the new periodic log file handler. 124 | 125 | These are all very common steps, which nearly every JEE app needs to run. 126 | A good place to learn something about CLI and find some examples in the JBoss docs. 127 | 128 | [CLI Recipes Wildfly Docs](https://docs.jboss.org/author/display/WFLY8/CLI%20Recipes) 129 | 130 | [CLI Recipes AS71 *still works*](https://docs.jboss.org/author/display/AS71/CLI%20Recipes) 131 | 132 | You can do any kind of configuration here. The outcome of the CLI is printed out 133 | to the Docker build process standard out, so you can see errors or success message during build. 134 | 135 | ### Execution 136 | When the image is build and ready to run, it uses its own entry point 137 | script to run the application server. 138 | This entry point checks the environment for usable variables and replaces 139 | them in the application server’s configuration file. 140 | 141 | The same way can be used to alter other configurations as well. 142 | 143 | In this example 5 different placeholders for the database connection are 144 | placed in the standalone.xml during build phase by the commands.cli script. 145 | 146 | These placeholders are: 147 | 148 | 1. \#\#\#DB_HOST\#\#\# 149 | 150 | hostname or IP address of the MySQL server host 151 | 152 | 153 | 2. \#\#\#DB_PORT\#\#\# 154 | 155 | TCP Port number on which the MySQL server is listening 156 | 157 | 158 | 3. \#\#\#DB_SCHEMA\#\#\# 159 | 160 | the default database schema to apply to 161 | 162 | 163 | 4. \#\#\#DB_USER\#\#\# 164 | 165 | the user name to use for connecting the database 166 | 167 | 168 | 5. \#\#\#DB_PASSWORD\#\#\# 169 | 170 | the password of the user for connecting the database 171 | 172 | 173 | To make sure these environment variables exist, they are all defined 174 | with default values in Dockerfile like this: 175 | 176 | ENV DB_HOST 10.0.0.1 177 | ENV DB_PORT 3306 178 | ENV DB_USER db_user 179 | ENV DB_PASSWORD db_password 180 | ENV DB_SCHEMA db_schema 181 | 182 | Now when you run the image you can overwrite all of this values by 183 | supplying these variables to the run command. 184 | 185 | docker run -e DB_HOST=192.168.0.100 -e DB_USER=dbuser -e DB_PASSWORD=password -e DB_SCHEMA=myDB my-wildfly-app 186 | 187 | When you have looked in the Dockerfile, you will have recognized that 188 | there are two more environment variables defined. 189 | 190 | ENV AWS_KEY AKXXXXXXXXXXXXXXXXXX 191 | ENV AWS_SECRET fDEXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 192 | 193 | This is an example for passing in AWS credentials to the application 194 | server environment. They are used in the entry point script and placed 195 | as Java properties. 196 | 197 | exec /opt/jboss/wildfly/bin/standalone.sh -b=${host_ip} -bmanagement=${host_ip} -bunsecure=${host_ip} --server-config=standalone.xml -Djboss.server.log.dir=/data/logs -Daws.accessKeyId=${AWS_KEY} -Daws.secretKey=${AWS_SECRET} 198 | 199 | They are set to the properties: aws.accessKeyId and aws.secretKey. 200 | When you are using the correct credentials provider for your AWS connection 201 | these values are used. 202 | 203 | ### Logging Volume 204 | The Dockerfile defines a mountable volume, which is passed to the 205 | application server as base log directory. 206 | This way you get your application server logs, where you want them, 207 | outside of the container. 208 | 209 | Definition of volume in Dockerfile: 210 | 211 | VOLUME /data/logs 212 | 213 | And in the entrypoint.sh it is passed to the application server by: 214 | 215 | -Djboss.server.log.dir=/data/logs 216 | 217 | ## Example 218 | To use everything included in this example, you need to do. 219 | 220 | 1. Place a JEE application archive as described in usage chapter. 221 | 222 | This application should include a persistence unit using the 223 | "MyCustomDS" data source and uses the AWS Java SDK. 224 | 225 | 2. Provide all environment variables in the docker run command 226 | 227 | 228 | Full command example using all environment parameters, volumes and ports. 229 | 230 | docker run --name my-app --rm -e DB_HOST=192.168.0.100 -e DB_PORT=3306 -e DB_USER=user -e DB_PASSWORD=password -e DB_SCHEMA=example -e AWS_KEY=XXXXXXXXXXXXXXXXXXXX -e AWS_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -p 8080:8080 -p 9990:9990 -v /mnt/logs:/data/logs wildfly-app 231 | 232 | Parameter description: 233 | 234 | - \-\-name 235 | 236 | defines a custom name for the container instance. 237 | A container is easer to identify by a custom name then by the auto 238 | generated one from Docker. 239 | 240 | - \-\-rm 241 | 242 | tells docker to remove this container after it stops to keep the cache clean. 243 | 244 | - \-e 245 | 246 | defines an environment variable. This parameter needs to be followed 247 | by case sensitive property name and value, seperated by equals sign. 248 | 249 | - \-p 250 | 251 | defines the network NAT rules for binding Docker host ports to 252 | container ports. 253 | 254 | - \-v 255 | 256 | maps a local directory to the provided volume mount of the container. 257 | 258 | 259 | ## Links and References 260 | Following a list of Webpages of all used software and knowledge resources 261 | we used to build this example. 262 | 263 | [Wildfly application server](http://wildfly.org/) 264 | 265 | [Official Wildfly Docker Image](https://hub.docker.com/r/jboss/wildfly/) 266 | 267 | [Official Wildfly Docker Git Repo](https://github.com/jboss-dockerfiles/wildfly) 268 | 269 | [Blog Post *Customizing the configuration of the WildFly Docker image*](https://goldmann.pl/blog/2014/07/23/customizing-the-configuration-of-the-wildfly-docker-image/) 270 | 271 | [Blog Post *Logging with the WildFly Docker image*](https://goldmann.pl/blog/2014/07/18/logging-with-the-wildfly-docker-image/) 272 | 273 | [AWS Java SDK](https://aws.amazon.com/de/sdk-for-java/) 274 | 275 | [Docker Reference](https://docs.docker.com/engine/reference/builder/) 276 | 277 | [Best practices for writing Dockerfiles](https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/) --------------------------------------------------------------------------------