2. Building pingme with a Dockerfile
Let’s start with the source code, it can be cloned down from git clone https://stream2stream@bitbucket.org/stream2stream/pingme.git
Once you have the code, navigate into the folder, execute the command
mvn package
To run the code enter
java -jar target/pingme.jar
To run the code you would simply execute the command java -jar target/pingme.jar
again. But it will fail because pingme is already running on port 8080
.
Without changing the code, there are two possible options
Create a container with java installed into it and copy the jar from the host into the running container, or build our own image that contains the app and everything needed to run our app.
Using a Java container and copying the jar into it
Begin by making sure you are still in the maven project directory for the pingme application - there should be a pom.xml file in the directory.
Execute the following commands
docker pull openjdk:alpine
docker run -d --name openjdk:18-ea-11-alpine3.15
docker tag openjdk:18-ea-11-alpine3.15 openjdk:alpine11
docker run -dit -p 8080:8080 --name jdk openjdk:alpine11 cat
docker cp ./target/pingme.jar jdk:/home/
docker exec -it jdk sh
cd /home
java -jar ./pingme.jar
Any images tagged with alpine is a lightweight version of the required image. This is a JDK 11 alpine version.
In your browser enter the URL localhost:8082/api/status
, and you should a Healthy
response back.
There are a lot of steps here to make this work, and any one of these could stop us from reaching our goal.
Line 3. creates an image in our registry called openjdk:alpine11
. This is an easier name for us to work with.
Line 4. the cat command at the end stops the container from exiting, it’s waiting for keyboard input. Since it is running in detached mode (-d
) as a daemon, the cat command will stop it from terminating (exiting).
Line 5. copies pingme.jar
from the host into the container to the location /home
.
Building our own image
An easier option than the above is to build your own image.
Building your own image can only take place if you know your applications runtime environment and the steps to ensuring that the environment is in place. This may require you to go through the steps above to ensure you have a good understanding the environment requirements. For example, using OpenJDK:alpine directly from hub.docker gives us the the wrong version of java (1.8), this is why we used the tag 18-ea-11-alpine3.15
A docker file (Dockerfile) is a template (cookie cutter) that is used to create images.
Docker images are constructed from image layers. This makes the whole image a more manageable component because the build tool is able to determine how much of an image needs to be changed/updated by looking at the differences between the layers. The other benefit is that when you pull an image from the registry, docker looks at the image layers and sees if any corresponding image layers already exist on your machine. If they do exist, then it only pulls those image layers that are necessary to give you a complete application image. So in our example, we pulled the openjdk:alpine
image for our application and not the ubuntu
image. If we had started with the ubuntu
image, we would then need to install the required JDK manually.
Here is the Dockerfile we will be working with
Dockerfile reference can be found here
Each command in the docker will create an image layer. An excellent explanation of image layers can be found here.
Line 1.
pull the initial layer required for our container environment
Line 3.
Create a layer that creates a directory /home/java_app
in the image
Line 5.
Copy the file pingme.jar
from the host folder ./target
(this folder must be relative to where the docker build
was run). The file is copied into the image folder /home/java_app
Line 7.
Open port 8080
on the container
Line 9.
When the container is running execute the command java -jar /home/java_app/pingme.jar
Build the file with docker build
.
The docker build
command will consume the Dockerfile
(indicated by the last argument, the location of where the Dockerfile is, it must be a subdirectory from where the docker build is run). As it processes the file, docker build will check its cache to see if any of the statements are already available in its cache. If they are, they will be used to build the complete image. If they are not, the build process will build the image layer.
Once the image has been built, it can be used like any other image that you acquired using docker pull
.
Be careful that you do not build your application in the Dockerfile
. Docker build will only rebuild the image if the Dockerfile
or things referenced in the host have changed. So any chnages in a git repo would not cause a rebuild.