:imagesdir: images
= A Simple Java EE Docker Example
In this post we will play a bit with docker in the context of Java EE. Here is what we will do:
* Create, build and run a docker image;
* the image will start a wildfly server within a JavaEE sample application deployed;
* show some docker commands;
* start multiple containers to see the same app running on different ports.
== Introduction
I will not introduce docker as there are already many good references on the subject. To create this post I’ve read the following tutorials:
. Docker User guide footnoteref:[Docker User guide, https://docs.docker.com/engine/userguide/];
. Docker instalation tutorial footnoteref:[docker instalation, https://docs.docker.com/engine/installation/linux/ubuntulinux/]
. Working with docker images footnoteref:[Working with docker images, https://docs.docker.com/engine/userguide/containers/dockerimages/];
. this great post, Docker begginers tutorial footnote:[https://blog.talpor.com/2015/01/docker-beginners-tutorial/];
. Arun Gupta’s tech tips: http://blog.arungupta.me/getting-started-with-docker/[#39^], http://blog.arungupta.me/create-own-docker-image-techtip57/[#57], http://blog.arungupta.me/javaee7-lab-wildfly-docker/[#61] and http://blog.arungupta.me/wildfly-javaee7-mysql-link-two-docker-container-techtip65/[#65^].
== Pre requisites
To run this tutorial you will need:
* A docker daemon running on your host machine
** after installing docker add this lines in *‘etc\default\docker‘* file: *DOCKER_OPTS="-H tcp://127.0.0.1:2375 -H unix:///var/run/docker.sock"*
** after that, restart your machine and try to run the command: _docker -H tcp://127.0.0.1:2375 –version_
the output must be something like: _Docker version 1.4.1, build 5bc2ff8_
* http://download.jboss.org/wildfly/8.2.0.Final/wildfly-8.2.0.Final.zip[A wildfly 8.2.0 installation(unziped)^];
* http://oracle.com/technetwork/java/javase/downloads/index.html[jdk-8u25-linux-x64.tar.gz file^];
* car-service.war https://github.com/rmpestano/javaee-docker-sample/tree/master/java_ee/car-service.war[available here];
* Dockerfile https://github.com/rmpestano/javaee-docker-sample/tree/master/java_ee/Dockerfile[available here^].
== Creating the Docker image
Docker images represent/describe the container itself. As I got limited internet access (3g from my cellphone) I have created an image using resources from my local machine. So the image will only work if it is build in a directory containing the following files:
image::docker-01.png[]
* *wildfly-8.2.0.Final*: the application server
* *car-service.war*: the app we will deploy
* *Dockerfile*: the file describing this container
* *jdk-8u25-linux-x64.tar.gz*: the java version we will install in the container
NOTE: It is not good practice to use fixed resources in a docker container as it will only work if the files are present during the image build. The best approach is to install everything from scratch and download necessary files. https://github.com/rmpestano/spring-vs-ejb-vs-cdi-benchmark/blob/docker/docker/wildfly/Dockerfile[Here is an example of docker file] that download/install/deploy an app into wildfly 10 without using local files.
Here is our Dockerfile content:
----
FROM ubuntu <1>
MAINTAINER Rafael Pestano
# setup WildFly
COPY wildfly-8.2.0.Final /opt/wildfly <2>
# install example app on wildfy
COPY car-service.war /opt/wildfly/standalone/deployments/ <3>
# setup Java
RUN mkdir /opt/java <4>
COPY jdk-8u25-linux-x64.tar.gz /opt/java/ <4>
# change dir to Java installation dir
WORKDIR /opt/java/ <5>
RUN tar -zxf jdk-8u25-linux-x64.tar.gz <4>
# setup nvironment variables
RUN update-alternatives --install /usr/bin/javac javac /opt/java/jdk1.8.0_25/bin/javac 100 <4>
RUN update-alternatives --install /usr/bin/java java /opt/java/jdk1.8.0_25/bin/java 100 <4>
RUN update-alternatives --display java <4>
RUN java -version
# Expose the ports we're interested in
EXPOSE 8080 9990 <6>
# Set the default command to run on boot
# This will boot WildFly in the standalone mode and bind to all interface
CMD ["/opt/wildfly/bin/standalone.sh", "-c", "standalone-full.xml", "-b", "0.0.0.0"] <7>
----
<1> The image inherits from ubuntu, an image which installs Ubuntu OS. Ubuntu image is installed when you follow the docker instalation tutorial footnoteref:[docker instalation].
<2> Next we copy the server to the folder _/opt/wildfly_ inside the container we are creating. COPY is a command available in Dockerfile DSL.
All commands can be found in Dockerfile reference guide footnote:[https://docs.docker.com/engine/reference/builder/].
<3> Next we copy our app war inside the application server;
<4> After, we setup Java by unziping it to _/opt/java_ inside the container and setting up environment variables. A better approach would be using apt-get.
<5> Change current directory to run next commands;
<6> Later I use _EXPOSE 8080 9990_ to tell docker the ports that can be exposed by the container. Remember, a container is the instantiation of a Docker image. When we run an image (docker run) we can specify which ports are accessible to the host machine.
<7> Finally we specify the default command.
NOTE: This command will be fired everytime our container is stated.
== Building the image
After describing our image we have to build it. Run the following command from the parent folder containing the Dockerfile:
====
docker -H tcp://127.0.0.1:2375 build -t javaee_sample java_ee/
====
* *-H* flag specify docker daemon address(we are using tcp to communicate with daemon);
* *build* is the command itself;
* *-t* specify the name of the tag to identify the image (javaee_sample in this case);
* *java_ee/* is the folder containing the Dockerfile describing our image.
More docker commands http://blog.arungupta.me/docker-common-commands-cheatsheet-techtip59/[can be found here^]. Here is the output of the command:
image::docker-02.png[]
After that we can see the created image by listing images installed:
====
docker -H tcp://127.0.0.1:2375 images
====
image::docker-03.png[]
== Starting the container
The container can be started with the command:
====
docker -H tcp://127.0.0.1:2375 run -p 8180:8080 javaee_sample
====
* *-p* specifies the container port(8080) to be exposed on the host machine. Port 8180 in this case (_EXPOSE_ Dockerfile command);
* *run* is the command itself;
* *javaee_sample* is the name of the image.
The output of command is wildfly starting because we set it as initial command (CMD Dockerfile command):
image::docker-04.png[]
== Running multiple containers
We can instantiate many container as we want since their ports don’t conflict in the host machine. I will start two more containers exposing port _8080_ to _8280_ and _8380_ respectively:
----
docker -H tcp://127.0.0.1:2375 run -p 8280:8080 javaee_sample
docker -H tcp://127.0.0.1:2375 run -p 8380:8080 javaee_sample
----
To list started containers we can use the command
====
docker -H tcp://127.0.0.1:2375 ps
====
Here is the output:
----
rmpestano@rmpestano-ubuntu:~/docker /images$ docker -H tcp://127.0.0.1:2375 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7b9079806e69 javaee_sample:latest /opt/wildfly/bin/st 27 seconds ago Up 27 seconds 9990/tcp, 0.0.0.0:8280->8080/tcp suspicious_lovelace
d4975e825751 javaee_sample:latest /opt/wildfly/bin/st 28 seconds ago Up 28 seconds 9990/tcp, 0.0.0.0:8380->8080/tcp loving_hopper
96e58eb65126 javaee_sample:latest /opt/wildfly/bin/st 42 seconds ago Up 42 seconds 9990/tcp, 0.0.0.0:8180->8080/tcp clever_cori
----
And now we can access the three apps in the browser at the same time:
image::docker-05.png[]
You can stop the container by its ID or by name with *docker -H tcp://127.0.0.1:2375 stop suspicious_lovelace*.
Remember that all data will be lost when the container is stopped. Use Docker volumes footnote:[https://docs.docker.com/engine/userguide/containers/dockervolumes] for persistent data.
For any feedback and comments, see the original post: https://rpestano.wordpress.com/2015/01/10/a-simple-java-ee-docker-example/.