How to create a microservice with Spring Boot and Docker

We will learn how to run a Spring Boot microservice inside a Docker container

In a previous post we learned how to install Docker and how to run a Java Hello Word inside the Docker container. Now we will learn how to run a Spring Boot microservice application within Docker.

Spring Boot Docker

Minimum dependencies of a Spring Boot microservice

The first thing we are going to do is define the dependencies we need. Spring Boot requires at least these dependencies:

1
2
org.springframework.boot:spring-boot-starter-web
org.springframework.boot:spring-boot-starter-test

The configuration for Gradle of these dependencies is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
plugins {
	id 'org.springframework.boot' version '2.1.9.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'dev.experto'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

The configuration for Maven of these dependencies for Spring Boot:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<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>2.1.9.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>dev.experto</groupId>
	<artifactId>springbootdocker</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springbootdocker</name>
	<description>Demo project for Spring Boot with Docker</description>

	<properties>
		<java.version>1.8</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>

Create the Spring Boot microservice

You must create the main class that Spring will start. We annotate the class with @SpringBootApplication The @SpringBootApplication annotation is equivalent to using @Configuration + @EnableAutoConfiguration + @ComponentScan with its default attributes.

1
2
3
4
5
6
7
8
@SpringBootApplication
public class SpringbootdockerApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringbootdockerApplication.class, args);
	}

}

Then you create a rest controller that you write down with _ @ RestController_ The home method maps the base of the URL of your services. You create a Home class and annotate the method with @RequestMapping

1
2
3
4
5
6
7
8
9
@RestController
public class Home {

    @RequestMapping("/")
    public String home() {
        return "Hello Spring Boot with Docker";
    }

}

.
You can run the application from the console. If you use gradle gradle bootRun

If you use maven _ mvn spring-boot:run_ If you use the gradle wrapper ./gradlew bootRun Spring Boot Docker

Open the URL localhost:8080. Spring Boot Docker

Finish the execution of SpringBoot with Gradle by pressing Ctrl + C: Sometimes, although in reality (it happens to me every time: /) gradlew does not end when you press CTRL + C on the console. If you cannot finish gradlew when you press ctrl + c, you will have to open another console and run ./gradlew -stop

Spring Boot Docker

Build your Spring Boot application

Before continuing with the other steps, be sure to make a build of the project to make available the jar file that we will need later.

with gradle Gradle leaves the jar in the \build\libs folder of your project with the name you have in the settings.gradle file gradlew build Spring Boot Docker

Gradle create jar file with the name you have specified in the settings.gradle file. Spring Boot Docker

with maven Maven leave the jar in the \ target folder of your project with the name you have defined in the artifactId tag of your pom.xml file mvnw package Spring Boot Docker

Create a Docker file to run SpringBoot

Well, you already have your Rest service application running. You will now start configuring Docker so that your service runs there. To create the Docker configuration for SpringBoot, create a Dockerfile text file with these instructions:

1
2
3
4
5
6
FROM openjdk:8-jdk-alpine
VOLUME /tmp
EXPOSE 8080
ARG JAR_FILE=build/libs/springbootdocker-0.0.1-SNAPSHOT.jar
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

FROM: Note that in the first line you use a docker image that is already armed with linux and java 8. That is, our service will run on a linux and Java 8 system.

ADD: The ADD instruction copies our application into Docker. Our gradle or maven config leaves the file jar with the name “springbootdocker-0.0.1-SNAPSHOT.jar”. This springbootdocker-0.0.1-SNAPSHOT.jar file is added to the container with the instruction ADD with the name app.jar If the path of your jar application is elsewhere, you must modify it with the correct route. In the event that you have created your app with maven, you must use the path of the maven target.

ENTRYPOINT: Then we execute the file when starting docker with the instruction ENTRYPOINT

Spring Boot Docker

Once the Dockerfile file is defined, you run docker build. The -t parameter defines the name that we will give to the container and that we will use later to execute it.

1
 docker build -t springbootdockerexample .

Look in the console with what happens with your Docker config you created. In each step you see that the linux image with java 8 (FROM) is created, after port 8080 is exposed from the container to the container host (EXPOSE), the jar (ADD) is copied and executed (ENTRYPOINT) .

Spring Boot Docker

Once the build of the docker is finished, you can execute it with the name you gave it.

Running Docker with Spring Boot

Once you have the docker image, you can run it with docker run The -p parameter tells Docker to expose port 8080 of our application that is running inside the container, on port 5000 of the operating system.

1
docker run  -p 5000:8080 springbootdockerexample

Spring Boot Docker

Now you open the URL pointing to the port you told docker. In this case 5000 http://localhost:5000/

Smile your application is working in a Docker container! Spring Boot Docker

Create the Docker image with Spring Boot using Gradle

If you use Gradle you can add a plugin to build the image and execute it directly from the Gradle commands. For this, you modify the build.gradle by adding this plugin https://github.com/palantir/gradle-docker

The new thing you add is what you see in buildscript, then the apply of the plugin and finally a new task docker.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// docker: new plugin 
buildscript {
	dependencies {
		classpath "gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.22.1"
	}
}

plugins {
	id 'org.springframework.boot' version '2.1.9.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'dev.experto'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

// docker: plugin apply  
apply plugin: 'com.palantir.docker'

// docker: new task docker 
docker {
    dependsOn build
    name "${project.name}"
    files bootJar.archivePath
    buildArgs(['JAR_FILE': "${bootJar.archiveName}"])
}

Let’s analyze the new docker task of the gradlew build file that we have modified: - dependsOn build we tell you that this task depends on the build of gradle - name “${project.name}” will be the name of the container, we will give you the name of the project that we have in settings.gradle - files bootJar.archivePath will make the jar file generated by the build available - buildArgs ([‘JAR_FILE’: “$ {bootJar.archiveName}”]) sends as an argument the name of the jar file.

Spring Boot Docker

Running the Docker image with Spring Boot using Gradle

If you have already modified your build file by adding the com.palantir.docker plugin, you can directly execute the build and create your image from gradle. From your console, you will use gradlew build docker to build an image

1
2
gradlew build docker
docker run -p 5000:8080 springbootdocker

Spring Boot Docker

Create the Docker image with Spring Boot using Maven

In the case of using Maven, you must add this plugin if you want to create the image directly from mvn https://github.com/spotify/dockerfile-maven

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>dockerfile-maven-plugin</artifactId>
                <version>1.4.9</version>
                <configuration>
                    <repository>${project.artifactId}</repository>
                    <buildArgs>
                        <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
                    </buildArgs>
                </configuration>
                <executions>
                    <execution>
                        <id>default</id>
                        <phase>install</phase>
                        <goals>
                            <goal>build</goal>
                            <goal>push</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

Your full pom.xml looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<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>2.1.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>dev.experto</groupId>
    <artifactId>springbootdocker</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springbootdocker</name>
    <description>Demo project for Spring Boot with Docker</description>

    <properties>
        <java.version>1.8</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>
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>dockerfile-maven-plugin</artifactId>
                <version>1.4.13</version>
                <configuration>
                    <repository>${project.artifactId}</repository>
                    <buildArgs>
                        <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
                    </buildArgs>
                </configuration>
                <executions>
                    <execution>
                        <id>default</id>
                        <goals>
                            <goal>build</goal>
                            <goal>push</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Running the Docker image with Spring Boot using Maven

Once you have added the https://github.com/spotify/dockerfile-maven plugin you run:

1
2
mvnw dockerfile:build
docker run -p 5000:8080 springbootdocker

Spring Boot Docker

When you execute docker run your app will remain in the url localhost:5000

Spring Boot Docker

A summary of the docker commands that were useful in this post:

  • docker build to create the docker image
  • docker run to run the docker image
  • docker images see the docker images you have available.

As always this code can be found by github and gitlab

https://github.com/gustavopeiretti/springboot-docker-example https://gitlab.com/gustavopeiretti/springboot-docker-example

Conclusion

You learned how to create a Spring Boot Rest application, configure a dockerfile for your application, build your Docker container and run your microservice from the container. You also learned some basic docker commands.