1. Introduction
In this tutorial, we’ll create a Docker image of a Spring Boot application. We’ll then see how to run the generated Docker image. The Spring Boot application will be a simple “Hello World” application. We’ll create multiple containers from the image and will access the Spring Boot application from outside the container.
2. Step 1: Create a Spring Boot application
In this tutorial for demonstration purpose, we’ll create a simple Spring Boot application. The application will have a controller which returns a greeting message when invoked.
Following is the source of pom.xml
:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.learnitweb</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Microservice</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Following is the source of HelloController
:
package com.learnitweb.demo.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/hello") public String index() { return "Greetings from Spring Boot!"; } }
The endpoint can be invoked using the URL http://localhost:8080/hello
.
3. Step 2: Create the Dockerfile
In the same location as pom.xml
, create a new file with name Dockerfile
. Note that the name should be exactly Dockerfile
with no extension.
A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Docker can build images automatically by reading the instructions from a Dockerfile.
Following are the contents of the Dockerfile
:
FROM openjdk:17-jdk-slim MAINTAINER learnitweb.com COPY target/demo-0.0.1-SNAPSHOT.jar demo-0.0.1-SNAPSHOT.jar ENTRYPOINT ["java","-jar","demo-0.0.1-SNAPSHOT.jar"]
Let’s discuss the contents of the Dockerfile briefly.
- The FROM instruction initializes a new build stage and sets the Base Image for subsequent instructions. In our case, openjdk is the image and 17-jdk-slim is the tag.
- The MAINTAINER instruction sets the Author field of the generated images.
- We are copying the file
demo-0.0.1-SNAPSHOT.jar
from thetarget
folder to the Docker image. - An ENTRYPOINT allows you to configure a container that will run as an executable. The syntax of ENTRYPOINT is:
ENTRYPOINT ["executable", "param1", "param2"]
This will allow us to run the “java -jar demo-0.0.1-SNAPSHOT.jar” when a container is created from the image.
4. Step 3: Create a Docker image from the Dockerfile
In the same location as Dockerfile
, run the following command to create the Docker image:
docker build . -t learnitweb/demo:v1
In the command -t learnitweb/demo:v1
refers to the tag provided to the image.
After the image is generated, the image is visible in the ‘images’ section of Docker Desktop.
Alternatively, you can view the images using the ‘docker images’ command.
5. Step 4: Run the Docker image to create container
You can run the image using the following command:
docker run -p 8080:8080 learnitweb/demo:v1
Here, -p 8080:8080
refers to the port mapping. By default, containers are connected to an isolated network within the Docker host. To access a container from local network, you need to configure port mapping explicitly. Here is first 8080 refers to the localhost port, the second 8080 after ‘:’ refer to the port in the container.
Similarly, you can create more containers from the same image:
docker run -p 8081:8080 learnitweb/demo:v1
When you run your container in this way, the terminal is connected to the container. Docker can run your container in detached mode in the background. You can achieve this by using the --detach
option, or its shorthand -d
. When you do so, Docker will start your container as usual but will detach from it, returning control to the terminal prompt.
docker run -d -p 8081:8080 learnitweb/demo:v1
Once the container is started, it is visible in the ‘Containers’ section of Docker Desktop.
Alternatively, you can view the container using docker ps -a
command.
Once the container is running you can access the application running in the container using these endpoints:
http://localhost:8080/hello
http://localhost:8081/hello
6. Drawbacks of this approach
- You need to know the Docker and its concepts. As a developer you need to know creating an image by writing a Dockerfile.
- You need to know the best practices like caching, compression and security related concepts about Docker images.
- As a developer if you are mainly concerned about the Java related technologies then learning Docker is an overhead.
- You can to create and maintain images yourself with lot of manual work.
There are other approaches like using Buildpacks and Google Jib. In the upcoming tutorials, we’ll learn these approaches to create Docker images.
7. Conclusion
In this tutorial, we generated and run a Docker image of Spring Boot application. This is first step to learn Microservices. Hope this was helpful.