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

author image

mkyong

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. Read all published posts by

Comments

avatar
newest oldest most voted
sushil kumar verma
Guest
sushil kumar verma

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

Images was created

sushil kumar verma
Guest
sushil kumar verma

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.

Fulano
Guest
Fulano

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

guest
Guest
guest

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

Prabhakar Naidu
Guest
Prabhakar Naidu

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

Prabhakar Naidu
Guest
Prabhakar Naidu

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

RAJIV SARKAR
Guest
RAJIV SARKAR

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

Prabhakar Naidu
Guest
Prabhakar Naidu

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
Guest
Patrik

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.