Spring Boot Microservices with Docker | Dockerfile |docker-compose.yml
This article is targeted for those who want to learn more about docker and How they can integrate Docker with their existing applications.
The base application we are going to take is a Spring Boot Application. The spring Boot application will be very simple with one Microservice for “Hello World”.
Contents
- Creating your first Spring Boot Application
- Create a very basic Docker Image and run the Spring Boot Application from Docker
- Finally, upload Spring Boot Docker Image to hub.docker.com
- Run the docker image with and without profiles
- Using docker-compose build and docker-compose up -d
- docker-compose stop and docker-compose rm
- Lab Session
GitHub Repo
Here is the github repository link for the project - https://github.com/rahulwagh/spring-boot-docker.git
Prerequisites
You do not need to be and expert on docker but fair bit of understanding on docker would be sufficient. But apart from that I would recommend the following -
- An IDE of your choice (Intellij, Eclipse, Atom, Sublime etc..)
- Docker installed on your system
1.Creating your first Spring Boot Application
The first step would be to create your Spring Boot Application. Spring Boot is very handy when it comes to bootstrapping, you can go to spring boot initializer (https://start.spring.io/) and fill in the basic information needed for creating Spring Boot Application.
Here are the details which I filled in -
- Group - com.jhooq.demo
- Artifacts - Jhooq-docker-demo
- Project - Gradle Project
- Packaging - Jar
- Java - 11
In the next step, you need to add the dependencies for the REST web service.
Click on the ADD and search for Spring Web(Build web, including RESTful, applications using Spring MVC. Uses Apache Tomcat as the default embedded container.)
Once you have added the required dependencies, click on generate and then you can download your Spring Boot project.
The next step would be to import the complete project into IDE (I would recommend using Intellij or Eclipse).
After importing the project into Intellij it should look like this
But since we are going to create a very simple “Hello World” micro-service, so your web service controller should look like this
1package com.jhooq.docker.ws;
2
3import org.springframework.web.bind.annotation.GetMapping;
4import org.springframework.web.bind.annotation.RestController;
5
6@RestController
7public class JhooqDockerDemoController {
8
9 @GetMapping("/hello")
10 public String hello() {
11 return "Hello - Docker";
12 }
13}</code>
Now after you are done with implementation of web-service, you need to build the complete project and since we are using Gradle then you can use the ./gradlew build task.
1$ ./gradlew build
1> Task :test
22020-09-01 12:01:55.189 INFO 8229 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
3
4BUILD SUCCESSFUL in 6s
55 actionable tasks: 5 executed
While building your spring boot project you should be watchful for BUILD SUCCESSFUL message. Because it tells you that you have build you project successfully.
Now after the successful build of your project now its time to check the jar file. So goto build/libs directory and look for the jar. In my case, the jar has been generated with the name -** Jhooq-Docker-Demo-0.0.1-SNAPSHOT.jar**
Verify your Spring Boot Web service
Alright now its time to verify your Spring Boot Microservice and for that you need to start your Spring Boot Application
1$ java -jar Jhooq-Docker-Demo-0.0.1-SNAPSHOT.jar
Since its a very small Spring Boot Application so it shouldn't take more time to start but once it starts successfully then you should be able to see following message in the console logs
1Started JhooqDockerDemo in 5.039 seconds (JVM running for 5.239)
Lets verify our “Hello World” microservice
1$ curl http://localhost:8080/hello
It should return you back with
1Hello - Docker
If you reached till so far which means you are halfway through and now you can start Containerizing your spring boot application using Docker.
2. Create a very basic Docker Image and run the Spring Boot Application from Docker
Alright so to begin with Containerization you need to create a Dockerfile for your Spring Boot Application. Since its a very basic “hello world” application so we are going to keep our Dockerfile very minimalistic
1FROM openjdk:8-jdk-alpine
2ARG JAR_FILE=build/libs/*.jar
3COPY ${JAR_FILE} app.jar
4ENTRYPOINT ["java","-jar","/app.jar"]
So what we are trying to achieve here in this Dockerfile is -
- Use openjdk 8 image - openjdk:8-jdk-alpine
- Pick the spring boot jar from - build/libs/*.jar
- Copy and rename the jar - app.jar
- Define the entry point - [“java”,”-jar”,”/app.jar”]
3. Finally, upload Spring Boot Docker Image to hub.docker.com
Now we are pretty much ready with our Spring Boot application and its Docker image.
Step 1- Create an account on hub.docker.com
For uploading/publishing any image to hub.docker.com you must have an account on it.
Now after signup you need to Create Repository. After login, you should see the following screen where you can click on Create Repository
For this article we are going to create repository with the name “jhooq-docker-demo”
Step 2 - Build and tag Docker image
We need to be a little careful while building a docker image because we need to tag with the image with the same name.
1$ docker build -t jhooq-docker-demo .
(*Note : The above build command can be used for building docker image if you are using maven as your build tool)
Gradle
In case if you are using Gradle
as your preferred build tool for building your spring boot application then you can use the following command for building your spring boot application -
1docker build --build-arg JAR_FILE=build/libs/\*.jar -t rahulwagh17/jhooq-docker-demo:jhooq-docker-demo .
Suppose you want to build and tag the docker image using gradlew
command then you can use the following command
1./gradlew bootBuildImage --imageName=rahulwagh17/jhooq-docker-demo:jhooq-docker-demo
Maven
Incase if you have using maven
as your preferred build tool then your can acheive the building and tagging the docker image using the following command -
1./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=rahulwagh17/jhooq-docker-demo:jhooq-docker-demo
Either you are using Gradle or Maven here is the docker build output which you can see onto your terminal once you build your docker image successfully -
1Sending build context to Docker daemon 29.37MB
2Step 1/6 : FROM openjdk:8-jdk-alpine
3 ---> a3562aa0b991
4Step 2/6 : ARG JAR_FILE=build/libs/*.jar
5 ---> Using cache
6 ---> 524b6f520504
7Step 3/6 : COPY ${JAR_FILE} app.jar
8 ---> Using cache
9 ---> 1f36fca8ff57
10Step 4/6 : RUN mkdir destination-dir-for-add
11 ---> Using cache
12 ---> 2738ea541520
13Step 5/6 : ADD sample.tar.gz /destination-dir-for-add
14 ---> Using cache
15 ---> 0d33832e0b78
16Step 6/6 : ENTRYPOINT ["java","-jar","/app.jar"]
17 ---> Using cache
18 ---> f173aeaa6f10
19Successfully built f173aeaa6f10
20Successfully tagged jhooq-docker-demo:latest
Now we need to tag the image with docker hub registry name .i.e. rahulwagh17/jhooq-docker-demo
1docker tag jhooq-docker-demo rahulwagh17/jhooq-docker-demo:jhooq-docker-demo
Alright now we need to push the image to hub.docker.com. Refer to the following command for pushing the image
1docker push rahulwagh17/jhooq-docker-demo:jhooq-docker-demo
1The push refers to repository [docker.io/rahulwagh17/jhooq-docker-demo]
274bb8b6f9582: Pushed
335dadcae1f24: Pushed
42eff7c27f0f5: Mounted from rahulwagh17/kubernetes
5ceaf9e1ebef5: Mounted from rahulwagh17/kubernetes
69b9b7f3d56a0: Mounted from rahulwagh17/kubernetes
7f1b5933fe4b5: Mounted from rahulwagh17/kubernetes
8jhooq-docker-demo: digest: sha256:7130c10e24fa94e55060e90977160d7e71483eaecf18f528c0f4a49ad30fe99a size: 1575
Here is screenshot after successful push
To verify that you have pushed your spring boot docker image successfully, you can login to hub.docker.com.
As you can see we have successfully pushed spring boot docker image to Docker Hub.
4. Run the docker image with and without profiles
Let's run the docker image which we have build in the previous step.
1docker run -p 8080:8080 -t rahulwagh17/jhooq-docker-demo:jhooq-docker-demo
Run the docker image using profiles
1docker run -e "SPRING_PROFILES_ACTIVE=prod" -p 8080:8080 -t rahulwagh17/jhooq-docker-demo:jhooq-docker-demo
5. Using docker-compose build and docker-compose up -d
Before we go ahead and start digging into docker-compose there is a couple of question which might pop-up in your mind.
Why we need docker-compose when we have Dockerfile ?
What docker-compose do?
We will answer this question later but the first thing about docker-compose is not shipped along with the Docker. This means you need to install the docker-compose separately onto your machine based on the operating system you are using.
Here is the official docker-compose installation document from Docker
Since I am using Ubuntu, so this is how I installed it on my Ubuntu machine
For Ubuntu
1sudo apt install docker-compose
Mac
There is Docker Desktop for Mac which can be download from here
Windows
For windows also there is Docker Desktop and it can be download from here
So now we have installed docker-compose, next we need to create docker-compose.yml
docker-compose.yml
1version: '3'
2
3services:
4 jhooq-springboot-container:
5 image: jhooq-spring-boot-docker-compose:1
6 build:
7 context: ./
8 dockerfile: Dockerfile
9 volumes:
10 - /data/jhooq-springboot-container
11 ports:
12 - "8080:8080"</code></pre>
1. Understanding the docker-compose.yml
- services - We have defined service with the name jhooq-springboot-container
- Dockerfile - It is using existing Docker and the image build from it
- 8080:8080 - It's port forwarding we are going to forward the docker container port to the host machine(ubuntu).
- volumes - In short, it's a directory to save the image data and this directory can be used by multiple containers. In our case, we are going to create directory /data/jhooq-springboot-container and we are going to store the data for image - jhooq-spring-boot-docker-compose:1
Lets run some docker-compose commands on your terminal
2. Build and tag the image using docker-compose build
1docker-compose build
2```bash
3
4```bash
5Building jhooq-springboot-container
6Step 1/6 : FROM openjdk:8-jdk-alpine
78-jdk-alpine: Pulling from library/openjdk
8Digest: sha256:94792824df2df33402f201713f932b58cb9de94a0cd524164a0f2283343547b3
9Status: Downloaded newer image for openjdk:8-jdk-alpine
10 ---> a3562aa0b991
11Step 2/6 : ARG JAR_FILE=build/libs/*.jar
12 ---> Using cache
13 ---> 524b6f520504
14Step 3/6 : COPY ${JAR_FILE} app.jar
15 ---> Using cache
16 ---> 9a77a2eb4a48
17Step 4/6 : RUN mkdir destination-dir-for-add
18 ---> Using cache
19 ---> 495906d31e45
20Step 5/6 : ADD sample.tar.gz /destination-dir-for-add
21 ---> Using cache
22 ---> 1fcfc28fa92a
23Step 6/6 : ENTRYPOINT ["java","-jar","/app.jar"]
24 ---> Using cache
25 ---> 348e0d3e7309
26Successfully built 348e0d3e7309
27Successfully tagged jhooq-spring-boot-docker-compose:1
As you can see from the logs we have successfully build the image and tagged it with - jhooq-spring-boot-docker-compose:1
3. Run the docker container using docker-compose up -d
After building the image successfully now you can run the container using the following command
1docker-compose up -d
1Creating network "jhooq-k8s_default" with the default driver
2Creating jhooq-k8s_jhooq-springboot-container_1 ... done
Now you can check the status of the container as well as the port on which it running
1docker ps -a
1CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2794e4a93f514 jhooq-spring-boot-docker-compose:1 "java -jar /app.jar" 18 minutes ago Up 18 minutes 0.0.0.0:8080->8080/tcp jhooq-k8s_jhooq-springboot-container_1
As you can see your container is up and running using docker-compose commands.
Let's test our microservice
1curl http://localhost:8080/hello
1Hello - Jhooq-k8s
Now we can answer our question - Why we need docker-compose when we have Dockerfile?
Answer -
- docker-compose is helpful when you want to create more than one container using the same docker-compose.yml
- docker-compose helps you to create multi-container application
- Using docker-compose you can spin desired number of containers but on the other hand it is not possible with simple Dockerfile
- It also helps you to define the volume so that volume can be shared by multiple containers.
Dockerfile - It will hep you manage single container docker-compose - You can manage multiple container using single docker-compose
5. docker-compose scale service
With docker-compose you can scale up the kubernetes services using the same docker-compose.yml. The only thing which you need to be careful is port number because once you start scaling up your services, you will need more ports to run your service.
So to overcome the problem of defining new ports for scaling up the service, docker-compose provides port ranges which can be defined in the docker-compose.yml
Here is docker-compose.yml with port range 8080-8100
1version: '3'
2
3services:
4 jhooq-springboot-container:
5 image: jhooq-spring-boot-docker-compose:1
6 build:
7 context: ./
8 dockerfile: Dockerfile
9 volumes:
10 - /data/jhooq-springboot-container
11 ports:
12 - "8080-8100:8080"
Now you can easily scale up the service.
But before you scale up it is always recommended to build the image once again
1docker-compose build
Here is command to scale up the service
1docker-compose scale jhooq-springboot-container=2
1WARNING: The scale command is deprecated. Use the up command with the --scale flag instead.
2WARNING: The "jhooq-springboot-container" service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash.
3Starting jhooq-k8s_jhooq-springboot-container_1 ... done
4Creating jhooq-k8s_jhooq-springboot-container_2 ... done
Now we have scaled up our service ”jhooq-springboot-container” and its running two containers on port 8080 and 8081.
6. docker-compose stop and docker-compose rm
After you are done with your container and you no longer need that container. So you can use stop and then remove the container.
Here the docker-compose commands which can be used -
1. Stop container using docker-compose stop
1docker-compose stop
1Stopping jhooq-k8s_jhooq-springboot-container_2 ... done
2Stopping jhooq-k8s_jhooq-springboot-container_1 ... done
As you can see it had stopped both the container
2. Remove the container using docker-compose rm
Here is the command to remove
1docker-compose rm
1Going to remove jhooq-k8s_jhooq-springboot-container_2, jhooq-k8s_jhooq-springboot-container_1
1Are you sure? [yN] y
1Removing jhooq-k8s_jhooq-springboot-container_2 ... done
2Removing jhooq-k8s_jhooq-springboot-container_1 ... done
Now we have removed all the container.
7. Lab Session
{#step-6}
Conclusion
What we have learned
- We started with a very basic Spring Boot Application with “Hello World” microservice
- Then we Dockerized the Spring Boot Application using Docker
- We used hub.docker.com to publish our first Spring Boot Docker Image
- Installed the docker-compose on the development machine
- Used docker-compose for Spring Boot Docker image
- Then used the docker-compose scaled service feature for scaling up the Spring Boot service
- Finally used docker-compose stop and docker-compose rm to stop and remove the container.
Learn more On Kubernetes -
- Setup kubernetes on Ubuntu
- Setup Kubernetes on CentOs
- Setup HA Kubernetes Cluster with Kubespray
- Setup HA Kubernetes with Minikube
- Setup Kubernetes Dashboard for local kubernetes cluster
- Setup Kubernetes Dashboard On GCP(Google Cloud Platform)
- How to use Persistent Volume and Persistent Volume Claims in Kubernetes
- Deploy Spring Boot Microservice on local Kubernetes cluster
- Deploy Spring Boot Microservice on Cloud Platform(GCP)
- Setting up Ingress controller NGINX along with HAproxy inside Kubernetes cluster
- CI/CD Kubernetes | Setting up CI/CD Jenkins pipeline for kubernetes
- kubectl export YAML | Get YAML for deployed kubernetes resources(service, deployment, PV, PVC....)
- How to setup kubernetes jenkins pipeline on AWS?
- Implementing Kubernetes liveness, Readiness and Startup probes with Spring Boot Microservice Application?
- How to fix kubernetes pods getting recreated?
- How to delete all kubernetes PODS?
- How to use Kubernetes secrets?
- Share kubernetes secrets between namespaces?
- How to Delete PV(Persistent Volume) and PVC(Persistent Volume Claim) stuck in terminating state?
- Delete Kubernetes POD stuck in terminating state?