Main Tutorials

Docker + Spring Boot examples

docker spring boot

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.

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.

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
         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.

App.java

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.

index.html

<!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

output

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.

Dockerfile

# 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.

Terminal

$ 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 .

Terminal

$ 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.
Terminal

$ sudo docker run -d -p 8080:8080 -t spring-boot:1.0

output

Few more examples to start the container

Terminal

$ 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)

application.properties

# 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

References

About Author

author image
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

Subscribe
Notify of
16 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
lewis
11 months ago

great article thanks!

Luis Loureiro
2 years ago

What do you think about dockerize spring boot with payara?

Kishor Kumar
3 years ago

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.

Milson
1 year ago
Reply to  Kishor Kumar

Im not sure but probably you dindt point the external port in your docker file.

Swapnil
3 years ago

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 ?

Atul
3 years ago
Reply to  Swapnil

Hi, Please check your EC2 Public IP and use that IP to Route the Traffic using that IP. example
pubilcip:8080:8080

Prabhakar Naidu
3 years ago

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

Patrik
3 years ago

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.

RAJIV SARKAR
3 years ago

what does COPY and WORKDIR do in docker file . will be of great help if explained with examples.

Fulano
4 years ago

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

Prabhakar Naidu
3 years ago
Reply to  Fulano

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

guest
4 years ago
Reply to  Fulano

you should create jar first.
use mvn verify and after jar created under target, run docker build command

Prabhakar Naidu
3 years ago
Reply to  guest

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

sushil kumar verma
4 years ago

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.

sushil kumar verma
4 years ago

I created the image as discussed steps. Images was created . but i was getting error while trying to run the image

Images was created