Part-2 (Installation, Setup and Testing of Java SpringBoot Application in Docker Container)
In the Part-1 we setup the latest Docker Swarm Mode cluster and run basic service. In this part we will build a docker image for a Spring Boot java app and will push the image stored in a local docker repository.Step-2: Build a Java Springboot App and Dockerise it
- Get a sample Java Springboot application
Clone a sample Java Springboot application from my github site:
https://github.com/n1t1nv3rma/springboot-maven.git
nverma@macbook-pro$ pwd
/Users/nverma/Documents/test
nverma@macbook-pro$ls -l
nverma@macbook-pro$
nverma@macbook-pro$ git clone https://github.com/n1t1nv3rma/springboot-maven.git
Cloning into 'springboot-maven'...
remote: Counting objects: 50, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 50 (delta 0), reused 0 (delta 0), pack-reused 47
Unpacking objects: 100% (50/50), done.
Checking connectivity... done.
nverma@macbook-pro$ ls -l
total 0
drwxr-xr-x 6 nverma staff 204 24 Aug 22:54 springboot-mavennverma@macbook-pro$ cd springboot-maven/nverma@macbook-pro$ ls -l
total 16
-rw-r--r-- 1 nverma staff 18 24 Aug 22:54 README.md
-rw-r--r-- 1 nverma staff 2188 24 Aug 22:54 pom.xml
drwxr-xr-x 3 nverma staff 102 24 Aug 22:54 srcnverma@macbook-pro$
If you are familiar with Maven, then you can notice that in the pom.xml file (which is a build file for Maven) is using "spring-boot-maven-plugin" and "docker-maven-plugin" plugins.
As per name the "spring-boot-maven-plugin" is responsible for building my spring boot app and the "docker-maven-plugin" is responsible for packagin the spring boot app into a Docker image based upon my Dockerfile.
The source code for sample Spring Boot application is under the "src/main/java" directory.
Dockerfile is listed under src/main/docker/Dockerfile. Here are it's contents
nverma@macbook-pro$ cat src/main/docker/Dockerfile
FROM frolvlad/alpine-oraclejdk8:slim
VOLUME /tmp
ADD gs-spring-boot-docker-0.1.0.jar app.jar
RUN sh -c 'touch /app.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
So what it has is to use the standard "alpine-oraclejdk8:slim" image from the Docker hub repo. and add our Spring Boot app (a JAR file) into it and run it via Java.
- Build the application and docker image
/Users/nverma/Documents/test/springboot-maven
nverma@macbook-pro$ ls -l
total 16
-rw-r--r-- 1 nverma staff 18 24 Aug 22:54 README.md
-rw-r--r-- 1 nverma staff 2188 24 Aug 22:54 pom.xml
drwxr-xr-x 3 nverma staff 102 24 Aug 22:54 src
Set the Docker env. to point to the “master” VM i.e. the Swarm Mode Cluster master.
nverma@macbook-pro$ eval $(docker-machine env master)
nverma@macbook-pro$ mvn package docker:build
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building gs-spring-boot-docker 0.1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ gs-spring-boot-docker ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ gs-spring-boot-docker ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 3 source files to /Users/nverma/Documents/test/springboot-maven/target/classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ gs-spring-boot-docker ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/nverma/Documents/test/springboot-maven/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ gs-spring-boot-docker ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.18.1:test (default-test) @ gs-spring-boot-docker ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ gs-spring-boot-docker ---
[INFO] Building jar: /Users/nverma/Documents/test/springboot-maven/target/gs-spring-boot-docker-0.1.0.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:1.4.0.RELEASE:repackage (default) @ gs-spring-boot-docker ---
[INFO]
[INFO] --- docker-maven-plugin:0.4.11:build (default-cli) @ gs-spring-boot-docker ---
[INFO] Copying /Users/nverma/Documents/test/springboot-maven/target/gs-spring-boot-docker-0.1.0.jar -> /Users/nverma/Documents/test/springboot-maven/target/docker/gs-spring-boot-docker-0.1.0.jar
[INFO] Copying src/main/docker/Dockerfile -> /Users/nverma/Documents/test/springboot-maven/target/docker/Dockerfile
[INFO] Building image master:5000/gs-spring-boot-docker:1.6
Step 1 : FROM frolvlad/alpine-oraclejdk8:slim
---> ea24082fc934
Step 2 : VOLUME /tmp
---> Using cache
---> 0b7db19ef34d
Step 3 : ADD gs-spring-boot-docker-0.1.0.jar app.jar
---> 854f755a5bb0
Removing intermediate container 1909c71ce1fb
Step 4 : RUN sh -c 'touch /app.jar'
---> Running in 569c609bb1cb
---> 8c1e4c9979ca
Removing intermediate container 569c609bb1cb
Step 5 : ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -jar /app.jar
---> Running in 4d265484903f
---> 4bc97947a91f
Removing intermediate container 4d265484903f
Successfully built 4bc97947a91f
[INFO] Built master:5000/gs-spring-boot-docker:1.6
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 21.539 s
[INFO] Finished at: 2016-08-24T23:10:23+10:00
[INFO] Final Memory: 42M/196M
[INFO] ------------------------------------------------------------------------
nverma@macbook-pro$
We can see that first Maven compiled and built the Sprint Boot App and bundled it into a JAR as “target/gs-spring-boot-docker-0.1.0.jar”. One can test the App locally by running it as “java -jar target/gs-spring-boot-docker-0.1.0.jar” and by hitting the “http://localhost:8080/greet?name=World” url in your browser.
We also noticed that with the help of “docker-maven-plugin” Maven further transformed the Sprint Boot app into a full-fledged Docker image as per the instructions given in the standard Dockerfile under the src/main/docker directory. We should find that image built and present locally on our “master” server.
nverma@macbook-pro$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
master:5000/gs-spring-boot-docker 1.6 e8c983e1ee9e 7 seconds ago 195.3 MB
frolvlad/alpine-oraclejdk8 slim ea24082fc934 2 days ago 167.1 MB
alpine latest 4e38e38c8ce0 1 week ago 4.799 MB
A question might be churning in the mind as to why the docker image is called "master:5000/gs-spring-boot-docker:1.6"? Yes, it is like this for a reason! In this format, the image name reflects the name of the local Docker repository server reachable via “master:5000” fqdn.
But currently we have only named/tagged the image as it lives on the “master:5000” server. But we still need to build a local local Docker repository server and push/server the newly created image from there.
- Build a local Docker repository server and push images into it
We will be building an insecure local registry for ease and learning purposes. Login into the “master” node where we will run this service.
nverma@macbook-pro$ docker-machine ssh master
docker@master:~$
Edit the content of the file “/var/lib/boot2docker/profile” as below:
EXTRA_ARGS='
--label provider=virtualbox
--insecure-registry 0.0.0.0:5000
‘
Restart “docker service”:
docker@master:~$ sudo /etc/init.d/docker restart
Need TLS certs for master,127.0.0.1,10.0.2.15,192.168.99.101
-------------------
docker@master:~$
Verify:
docker@master:~$ docker info | grep -A2 Regis
Registry: https://index.docker.io/v1/
Labels:
provider=virtualbox
Insecure Registries:
0.0.0.0:5000
127.0.0.0/8
docker@master:~$
Once done, just start the Docker repository service as a docker container itself! And that’s the beauty and power of Docker!
docker@master:~$ docker run -d -p 5000:5000 --restart=always --name registry registry:2
docker@master:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2fc0354d46a9 registry:2 "/entrypoint.sh /etc/" 2 minutes ago Up 2 minutes 0.0.0.0:5000->5000/tcp registry
docker@master:~$
That’s it! Lets just push our image into this repository so that all the Swarm Cluster Nodes can fetch the required image from this local server instead of downloading from internet every time.
docker@master:~$ docker push master:5000/gs-spring-boot-docker:1.6
The push refers to a repository [master:5000/gs-spring-boot-docker]
decea895b03e: Pushed
64a80a295fba: Pushed
f3d2c9a5ee9f: Pushed
017f469bdc32: Layer already exists
4fe15f8d0ae6: Layer already exists
1.6: digest: sha256:39129303cdfee6d6b674db97e5ab7a6df77310a2494fc16c2c659ee4e154c7a3 size: 1375
docker@master:~$
- Update all Swarm Nodes to be able to be able to pull images from the local Docker repository server (i.e. Master in this case)
Login into the “worker1” node where we will run this service.
nverma@macbook-pro$ docker-machine ssh worker1
docker@worker1:~$ sudo vi /etc/hosts
Update "/etc/hosts" with the IP address of the repo. server i.e. "master" in our case.
192.168.99.101 master
Edit the content of the file “/var/lib/boot2docker/profile” as below:nverma@macbook-pro$ docker-machine ssh worker1
docker@worker1:~$ sudo vi /etc/hosts
EXTRA_ARGS='
--label provider=virtualbox
--insecure-registry master:5000
‘
Restart “docker service”:
docker@worker1:~$ sudo /etc/init.d/docker restart
Need TLS certs for master,127.0.0.1,10.0.2.16,192.168.99.102
-------------------
docker@worker1:~$
Repeat for all worker nodes.
Ok. Now we have the Docker Swarm Mode cluster built and have the required Application as well as it’s Docker Image available locally. So lets continue our CICD journey by using Go Pipeline, while exploring the potential of Docker Swarm Mode, in next PART-3.