So, you’d like to start using Docker for Java EE applications?
A typical Java EE application consists of an application server, such as WildFly, and a database, such as MySQL. In addition, you might have a separate front-end tier, say Apache, for load balancing a number of application server. A caching layer, such as Infinispan, may be used to improve overall application performance. Messaging system, such as ActiveMQ, may be used for processing queues. Both the caching and messaging components could be setup as a cluster for further scalability.
This Tech Tip will show some simple Docker recipes to configure your containers that use application server and database. Subsequent blog will cover more advanced recipes that will include front-end, caching, messaging, and clustering.
Lets get started!
Docker Recipe #1: Setup Docker using Docker Machine
If Docker is not already setup on your machine, then as a first step, you need to set it up. If you are on a recent version of Linux then you already have Docker. Or optionally can be installed as:
sudo apt-get install docker.io
On Mac and Windows, this means installing boot2docker which is a Tinycore Linux VM and comes with Docker host. Then you need to configure ssh keys and certificates.
Fortunately, this is extremely simplified using Docker Machine. It takes you from zero-to-Docker on a host with a single command. This host could be your laptop, in the cloud, or in your data center. It creates servers, installs Docker on them, then configures the Docker client to talk to them.
This recipe is explained in detail in Docker Machine to Setup Docker Host.
Docker Recipe #2: Application Server + In-memory Database
One of the cool features of Java EE 7 is the default database resource. This allows you to not worry about creating a JDBC resource in an application server-specific before your application is accessible. Any Java EE 7 compliant application server will map the default JDBC resource name (
java:comp/DefaultDataSource) to the application server-specific resource in the bundled database server.
For example, WildFly comes bundled with H2 in-memory database. This database is ready to be used as soon as WildFly is ready to accept your requests. This simplifies your development efforts and allows you to do a rapid prototyping. The default JDBC resource is mapped to
java:jboss/datasources/ExampleDS which is then mapped to the JDBC URL of
In such a case, the Database server is another application running inside the Application server.
Here is the command that runs Java EE 7 application in WildFly:
docker run -it -p 8080:8080 arungupta/javaee7-hol
If you want to run a typical Java EE 7 application using WildFly and H2 in-memory database, then this Docker recipe is explained in detail in Java EE 7 Hands-on Lab on WildFly and Docker.
Docker Recipe #3: Two Containers on Same Host Using Linking
The previous recipe gets you started rather quickly but becomes a bottleneck soon as the database is only in-memory. This means that any changes made to your schema and data are lost after the application server shuts down. In this case, you need to use a database server that resides outside the application server. For example, MySQL as the database server and WildFly as the application server.
To keep things simple, both the database server and application server can run on the same host.
Docker Container Links are used to link the two containers. Creating a link between two containers creates a conduit between a source container and a target container and securely transfer information about source container to target container. In our case, target container (WildFly) can see information about source container (MySQL). The important part to understand here is that none of this information needs to be publicly exposed by the source container, and is only made available to the target container.
Here are the commands that start the MySQL and WildFly containers and link them:
docker run --name mysqldb -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql -e MYSQL_DATABASE=sample -e MYSQL_ROOT_PASSWORD=supersecret -d mysql docker run --name mywildfly --link mysqldb:db -p 8080:8080 -d arungupta/wildfly-mysql-javaee7
WildFly and MySQL linked on two Docker containers explains how to set up this recipe.
Docker Recipe #4: Two Containers on Same Host Using Fig
The previous recipe require you to run the containers in a specific order. Running multi-container applications can quickly become challenging if each tier of your application is sitting in a container. Fig (deprecated in favor of Docker Compose) is a Docker Orchestration Tool that:
- Define multiple containers in a single configuration file
- Create dependencies between two containers by creating links between them
- Start containers in the right sequence
The entry point for Fig is a configuration file as shown:
mysqldb: image: mysql:latest environment: MYSQL_DATABASE: sample MYSQL_USER: mysql MYSQL_PASSWORD: mysql MYSQL_ROOT_PASSWORD: supersecret mywildfly: image: arungupta/wildfly-mysql-javaee7 links: - mysqldb:db ports: - 8080:8080
and all the containers can be started as:
fig up -d
Docker orchestration using Fig explains this recipe in detail.
Fig is only receiving updates. Its code base is used as basis for Docker Compose. This is explained in the next recipe.
Docker Recipe #5: Two Containers on Same Host Using Compose
Docker Compose is a tool for defining and running complex applications with Docker. With Compose, you define a multi-container application in a single file, then spin your application up in a single command which does everything that needs to be done to get it running.
The application configuration file is the same format as from Fig. The containers can be started as:
docker-compose up -d
This recipe is explained in detail in Docker Compose to Orchestrate Containers.
Docker Recipe #6: Two Containers on Different Hosts using IP Address
In the previous recipe, the two containers are running on the same host. These two could easily communicate using Docker linking. But simple container linking does not allow cross-host communication.
Running containers on the same host means you cannot scale each tier, database or application server, independently. This is where you need to run each container on a separate host.
MySQL container can start as:
docker run --name mysqldb -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql -e MYSQL_DATABASE=sample -e MYSQL_ROOT_PASSWORD=supersecret -p 5306:3306 -d mysql
JDBC resource can be created as:
data-source add --name=mysqlDS --driver-name=mysql --jndi-name=java:jboss/datasources/ExampleMySQLDS --connection-url=jdbc:mysql://$MYSQL_HOST:$MYSQL_PORT/sample?useUnicode=true&characterEncoding=UTF-8 --user-name=mysql --password=mysql --use-ccm=false --max-pool-size=25 --blocking-timeout-wait-millis=5000 --enabled=true
And WildFly container can start as:
docker run --name mywildfly -e MYSQL_HOST=<IP_ADDRESS> -e MYSQL_PORT=5306 -p 8080:8080 -d arungupta/wildfly-mysql-javaee7
Complete details for this recipe is explained in Docker container linking across multiple hosts.
Docker Recipe #7: Two Containers on Different Hosts using Docker Swarm
Docker Swarm is native clustering for Docker. It turns a pool of Docker hosts into a single, virtual host. It picks-up where Docker Machine leaves off by optimizing host resource utilization and providing failover services. Specifically, Docker Swarm allows users to create resource pools of hosts running Docker daemons and then schedule Docker containers to run on top, automatically managing workload placement and maintaining cluster state.
More details about this recipe are coming in a subsequent blog.
Docker Recipe #8: Deploy Java EE Application from Eclipse
Last recipe will deal with how to deploy your existing applications to a Docker container.
There are a couple of ways by which these applications can be deployed:
- Use Docker volumes + Local deployment: Here a directory on your local machine is mounted as a Docker Volume. WildFly Docker container is started by mapping that directory to the deployment directory as:
docker run -it -p 8080:8080 -v /Users/arungupta/tmp/deployments:/opt/jboss/wildfly/standalone/deployments/:rw jboss/wildfly
Configure JBoss Tools to deploy WAR files to this directory.
- Use WildFly management API + Remote deployment: Start WildFly Docker container, and additionally expose the management port 9990 as:
docker run -it -p 8080:8080 -p 9990:9990 arungupta/wildfly-management
Configure JBoss Tools to use a remote WildFly server and deploy using management APIs.
This recipe is explained in detail at Deploy to WildFly and Docker from Eclipse.
Docker Recipe #9: Test Java EE Applications using Arquillian Cube
Arquillian Cube allows you to control the lifecycle of Docker images as part of the test lifecyle, either automatically or manually. Cube uses Docker REST API to talk to the container. It uses the remote adapter API, for example WildFly in this case, to talk to the application server. Docker configuration is specified as part of the maven-surefire-plugin as:
<configuration> <systemPropertyVariables> <arquillian.launch>wildfly-docker</arquillian.launch> <arq.container.wildfly-docker.configuration.username>admin</arq.container.wildfly-docker.configuration.username> <arq.container.wildfly-docker.configuration.password>Admin#70365</arq.container.wildfly-docker.configuration.password> <arq.extension.docker.serverVersion>1.15</arq.extension.docker.serverVersion> <arq.extension.docker.serverUri>http://127.0.0.1:2375</arq.extension.docker.serverUri> <arq.extension.docker.dockerContainers> wildfly-docker: image: arungupta/javaee7-samples-wildfly exposedPorts: [8080/tcp, 9990/tcp] await: strategy: polling sleepPollingTime: 50000 iterations: 5 portBindings: [8080/tcp, 9990/tcp] </arq.extension.docker.dockerContainers> </systemPropertyVariables> </configuration>
Complete details about this recipe are available on Run Java EE Tests on Docker using Arquillian Cube.
What other recipes are you using to deploy your Java EE applications using Docker?