Docker + Spring Boot examples
In this tutorial, we will show you how to Dockerize a Spring Boot web application (mvc + thymeleaf).
Tested with
- Docker 19.03
- Ubuntu 19
- Java 8 or Java 11
- Spring Boot 2.2.4.RELEASE
- Maven
At the end of the article, we will create a Spring Boot MVC web application and run inside a docker container.
P.S This example is tested with Java 8 and Java 11.
1. Project Directory
1.1 A standard Maven project structure.
See the Dockerfile
at the root of the project? We only need this Dockerfile
text file to dockerize the Spring Boot application.
2. Maven
2.1 Project dependencies. Nothing special here, just some Spring Boot dependencies.
<?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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mkyong</groupId>
<artifactId>docker-spring-boot</artifactId>
<version>1.0</version>
<name>docker-spring-boot</name>
<url></url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<java.version>11</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-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- debugging -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<finalName>spring-boot-web</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
3. Spring Boot
3.1 @SpringBootApplication
to start everything, and also a controller to return a page.
package com.mkyong;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@SpringBootApplication
@Controller
public class StartApplication {
@GetMapping("/")
public String index(final Model model) {
model.addAttribute("title", "Docker + Spring Boot");
model.addAttribute("msg", "Welcome to the docker container!");
return "index";
}
public static void main(String[] args) {
SpringApplication.run(StartApplication.class, args);
}
}
3.2 A thymeleaf page.
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"/>
<link data-th-href="@{/css/main.css?{id}(id=${timestamp})}" rel="stylesheet">
<title>Hello Docker + Spring Boot</title>
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<a class="navbar-brand" href="#">Mkyong.com</div></a>
</nav>
<main role="main" class="container">
<div class="starter-template">
<h1 th:text="${title}">Default title.</h1>
<p th:text="${msg}">Default text.</p>
</div>
</main>
<script data-th-src="@{/js/main.js}"></script>
</body>
</html>
4. Run Spring Boot
4.1 Done, package it with Maven.
$ cd project
$ mvn clean package
4.2 Run the Spring Boot.
$ cd project
$ java -jar target/spring-boot-web.jar
Done, next, we will start this target/spring-boot-web.jar
in a docker container.
4. Docker File
A Dockerfile
is a text file, contains all the commands to assemble the docker image. Review the commands in the Dockerfile
:
4.1 It creates a docker image base on adoptopenjdk/openjdk11:alpine-jre
, an alpine linux with openjdk11
installed. This base image adoptopenjdk/openjdk11:alpine-jre
is just an example, we can find more base images from the official Docker Hub
# For Java 8, try this
# FROM openjdk:8-jdk-alpine
# For Java 11, try this
FROM adoptopenjdk/openjdk11:alpine-jre
4.2 Changed the working directory to /opt/app
WORKDIR /opt/app
4.3 Copy spring-boot-web.jar
to /opt/app/app.jar
ARG JAR_FILE=target/spring-boot-web.jar
# cp spring-boot-web.jar /opt/app/app.jar
COPY ${JAR_FILE} app.jar
4.4 Run the jar file with ENTRYPOINT
.
# java -jar /opt/app/app.jar
ENTRYPOINT ["java","-jar","app.jar"]
4.5 A complete Dockerfile
example.
# For Java 8, try this
# FROM openjdk:8-jdk-alpine
# For Java 11, try this
FROM adoptopenjdk/openjdk11:alpine-jre
# Refer to Maven build -> finalName
ARG JAR_FILE=target/spring-boot-web.jar
# cd /opt/app
WORKDIR /opt/app
# cp target/spring-boot-web.jar /opt/app/app.jar
COPY ${JAR_FILE} app.jar
# java -jar /opt/app/app.jar
ENTRYPOINT ["java","-jar","app.jar"]
5. Dockerize Spring Boot Application
5.1 Go to the folder containing Dockerfile
.
$ cd project
$ pwd
/home/mkyong/projects/docker-spring-boot
$ ls -lsah
total 32K
4.0K drwxr-xr-x 5 mkyong mkyong 4.0K Feb 17 20:04 .
4.0K drwxr-xr-x 6 mkyong mkyong 4.0K Feb 14 13:02 ..
4.0K -rw-r--r-- 1 mkyong mkyong 537 Feb 17 20:04 Dockerfile
4.0K -rw-r--r-- 1 mkyong mkyong 80 Feb 14 13:02 docker-spring-boot.iml
4.0K drwxr-xr-x 2 mkyong mkyong 4.0K Feb 17 19:16 .idea
4.0K -rw-r--r-- 1 mkyong mkyong 2.4K Feb 17 18:36 pom.xml
4.0K drwxr-xr-x 4 mkyong mkyong 4.0K Feb 14 13:02 src
4.0K drwxr-xr-x 6 mkyong mkyong 4.0K Feb 17 19:44 target
5.2 sudo docker build -t name:tag .
$ pwd
/home/mkyong/projects/docker-spring-boot
$ sudo docker build -t spring-boot:1.0 .
Sending build context to Docker daemon 19.12MB
Step 1/5 : FROM adoptopenjdk/openjdk11:alpine-jre
---> 9aa3eab0cec0
Step 2/5 : ARG JAR_FILE=target/spring-boot-web.jar
---> Running in 14b8291509cb
Removing intermediate container 14b8291509cb
---> efc9e83cec99
Step 3/5 : WORKDIR /opt/app
---> Running in 844380f977af
Removing intermediate container 844380f977af
---> 5de2390296cc
Step 4/5 : COPY ${JAR_FILE} app.jar
---> d826c8181a83
Step 5/5 : ENTRYPOINT ["java","-jar","app.jar"]
---> Running in aa572b8d487b
Removing intermediate container aa572b8d487b
---> 468b2f899083
Successfully built 468b2f899083
Successfully tagged spring-boot:1.0
5.3 Start the docker container spring-boot:1.0
, run the /opt/app/app.jar
file during startup.
- Add
run -d
to start the container in detach mode – run the container in the background. - Add
run -p
to map ports.
$ sudo docker run -d -p 8080:8080 -t spring-boot:1.0
Few more examples to start the container
$ sudo docker run -d -p 80:8080 -t spring-boot:1.0
$ sudo docker run -d -p 443:8443 -t spring-boot:1.0
$ sudo docker run -d -p 80:8080 -p 443:8443 -t spring-boot:1.0
Done, we dockerize a Spring Boot application.
6. FAQs
6.1 List all containers
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3e36a2c0c241 spring-boot:1.0 "java -jar app.jar" 13 seconds ago Up 12 seconds 0.0.0.0:8080->8080/tcp elegant_euler
6.2 Stop a container by container id.
$ sudo docker stop 3e36a2c0c241
6.3 How to deploy the container?
The fastest way is to tag and push the image to the official docker hub and pull the container back to the server.
Build an image ‘name:tag’.
$ cd project
$ sudo docker build -t spring-boot:1.0 .
Tag first before push to docker hub.
$ sudo docker image tag spring-boot:1.0 your_id/spring-boot:1.0
$ sudo docker image push your_id/spring-boot:1.0
``
In production server.
```bash
$ sudo docker pull your_id/spring-boot:1.0
$ sudo docker run -d -p 80:8080 -t spring-boot:1.0
6.4 For SSL, declared the certificate (jks or p12) in the application.properties
, start at port 8443
(configurable)
# SSL
server.port=8443
server.ssl.key-store=cert.p12
server.ssl.key-store-password=123
server.ssl.keyStoreType=PKCS12
Starts the docker container and maps https 433
to 8443
.
$ docker run -d -p 443:8443 -t spring-boot:1.0
Note
You may like this docker Java application example.
Download Source Code
$ git clone https://github.com/mkyong/docker-java
$ cd docker-spring-boot
$ mvn clean package
$ java -jar target/spring-boot-web.jar
access http://localhost:8080
//dockerize
// create a docker image
$ sudo docker build -t spring-boot:1.0 .
// run it
$ sudo docker run -d -p 8080:8080 -t spring-boot:1.0
access http://localhost:8080
great article thanks!
What do you think about dockerize spring boot with payara?
Hi, I am trying to follow the same steps, but I am using JSP component for view. After I have deployed, I am getting “Whitelabel Error Page” when I browse the URL.
Im not sure but probably you dindt point the external port in your docker file.
I have created docker image and running the container. I see container running but cannot access the webpage. I am running container on AWS EC2 machine and accessing the webpage with IP:PORT. Am I doing something wrong here ?
Hi, Please check your EC2 Public IP and use that IP to Route the Traffic using that IP. example
pubilcip:8080:8080
Could anyone explain how can I resolve this issue? Thanks
————————————–Docker File—————————
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/webflux-microservice-poc.jar
WORKDIR /opt/app
COPY ${JAR_FILE} app.jar
ENTRYPOINT [“java”,”-jar”,”app.jar”]
————————————-Commands———————–
mvn clean compile install
mvn verify
Get-Content Dockerfile | docker build –
——————————–Error —————————–
Step 4/5 : COPY ${JAR_FILE} app.jar
COPY failed: stat /var/lib/docker/tmp/docker-builder276694828/target/webflux-microservice-poc.jar: no such file or directory
When you run the following command inside your spring project it will generate a jar file with filename.
mvn clean package
Take this jar filename and paste it to the following line of your Dockerfile;
ARG JAR_FILE=target/(your jar file name generated by the, mvn clean package command)
Then try to run the docker build command again. It should work for you now.
what does COPY and WORKDIR do in docker file . will be of great help if explained with examples.
Step 4/5 : COPY ${JAR_FILE} app.jar
COPY failed: stat /var/lib/docker/tmp/docker-builder487659193/target/spring-boot-web.jar: no such file or directory
I was facing same issue. Solution is add “/” before the target/spring-boot-web.jar as below.
ARG JAR_FILE=/target/spring-boot-web.jar
you should create jar first.
use mvn verify and after jar created under target, run docker build command
I also got the same error. Not able to resolve. Could you please explain how did u fix this. Am using windows setup.
—————————————–Docker File—————————
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/webflux-microservice-poc.jar
WORKDIR /opt/app
COPY ${JAR_FILE} app.jar
ENTRYPOINT [“java”,”-jar”,”app.jar”]
————————————-Commands———————–
mvn clean compile install
mvn verify
Get-Content Dockerfile | docker build –
——————————–Error —————————–
Step 4/5 : COPY ${JAR_FILE} app.jar
COPY failed: stat /var/lib/docker/tmp/docker-builder276694828/target/webflux-microservice-poc.jar: no such file or directory
C:\Development\Docker\docker-with-springboot>docker run -d -p 8080:8080 -t springbootapp
2e8efa5a3f9929488791fd6d2b55cc4e062817b2dcb287d9efcf7597032f62d8
docker: Error response from daemon: driver failed programming external connectivity on endpoint frosty_sinoussi (c5838f16079d1a3849798c520f484cbdf8d92c0d394988ac42e4307aa4b850c9): Error starting userland proxy: mkdir /port/tcp:0.0.0.0:8080:tcp:172.17.0.2:8080: input/output error.
Sorry I can’t simulate the above error.
Running on Windows? Try restart the docker and test it again.
https://github.com/docker/for-win/issues/2722
https://stackoverflow.com/questions/49693353/error-response-from-daemon-driver-failed-programming-external-connectivity-on-e?rq=1
I created the image as discussed steps. Images was created . but i was getting error while trying to run the image
Images was created