Cómo crear un microservicio con Spring Boot y Docker

Aprenderemos cómo ejecutar un microservicio Spring Boot dentro de un contenedor Docker.

Spring Boot Docker

Dependencias mínimas de un microservicio Spring Boot

Lo primero que vamos a hacer es definir las dependencias que necesitamos.
Spring Boot requiere al menos estas dependencias:

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

La configuración para Gradle de estas dependencias es la siguiente:

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

group = 'com.gustavopeiretti'
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'
}

La configuración en Maven de estas mismas dependencias:

<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>com.gustavopeiretti</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>

Crear el microservicio Spring Boot

Debes crear la clase principal que iniciará SpringBoot.
Anotamos esa clase con @SpringBootApplication.
La anotación @SpringBootApplication es equivalente a usar @Configuration + @EnableAutoConfiguration + @ComponentScan con sus atributos predeterminados.
Revisa este otro post para más detalles sobre el main class

@SpringBootApplication
public class SpringbootdockerApplication {

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

}

Luego crea un controlador ‘rest controller’ que anotas con @RestController.
Crea una clase Home y anota el método con @RequestMapping.
El método home a continuación mapea el path base de tus servicios.
Aquí puedes leer más sobre los RestController

@RestController
public class Home {

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

}

Puedes ahora ejecutar la aplicación desde la consola.

  • Si utilizas gradle -> gradle bootRun
  • Si utiliza maven -> mvn spring-boot:run
  • Si utiliza el wrapper de gradle -> ./gradlew bootRun

Aquí vemos el inicio con ./gradlew bootRun Spring Boot Docker

Abre la URL localhost:8080. Spring Boot Docker

Para terminar la ejecución de SpringBoot con Gradle, presiona Ctrl + C: Si no puedes terminar gradlew cuando presionas ctrl + c, tendrás que abrir otra consola y ejecutar ./gradlew -stop

Spring Boot Docker

Crea tu aplicación Spring Boot

Antes de continuar con los otros pasos, asegúrese de hacer un build del proyecto para poner a disposición el archivo jar que necesitaremos más tarde.

con gradle

Gradle deja el archivo jar en la carpeta \build\libs de tu proyecto con el nombre que tienes en el archivo settings.gradle

gradlew build Spring Boot Docker

El nombre del archivo jar será el especificado en el archivo settings.gradle. Spring Boot Docker

con maven

Maven deja el archivo jar en la carpeta \target de tu proyecto con el nombre que hayas definido en el artifactId tag de tu archivo pom.xml

mvnw package Spring Boot Docker

Crear un archivo Docker para ejecutar SpringBoot

Bien, ya tienes tu aplicación en ejecución. Ahora comenzarás a configurar Docker para que tu servicio se ejecute allí.
Para crear la configuración Docker para SpringBoot, cree un archivo de texto Dockerfile con estas instrucciones:

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"]

Veamos que estamos haciendo en cada línea:

FROM: En la primera línea le indicamos que genere una imagen docker que ya está preestablecida con linux y Java 8. Es decir, nuestro servicio se ejecutará en un sistema linux y Java 8.

ADD: La instrucción ADD copia nuestra aplicación en Docker.
Nuestra configuración gradle o maven deja el archivo jar de con todo nuestro código con el nombre “springbootdocker-0.0.1-SNAPSHOT. jar”.
Este archivo jar springbootdocker-0.0.1-SNAPSHOT. se agrega al contenedor con la instrucción ADD con el nombre app.jar
Si la ruta de su aplicación jar está en otro lugar, debe modificarla con la ruta correcta. En caso de que haya creado su aplicación con maven, debe usar la ruta del destino maven.

ENTRYPOINT: Luego ejecutamos el archivo al iniciar docker con la instrucción ENTRYPOINT

Spring Boot Docker

Una vez definido el archivo Dockerfile, se ejecuta docker build.
El parámetro -t define el nombre que le daremos al contenedor y que utilizaremos posteriormente para ejecutarlo. El punto final para indicar la ubicación actual, desde donde se corre el comando.

 docker build -t springbootdockerexample .

Busque en la consola lo que sucede con la configuración de Docker que creó.
En cada paso se ve que se genera la imagen de linux con java 8 (FROM), después de que el puerto 8080 es expuesto desde el contenedor al host contenedor (EXPOSE), el jar (ADD) es copiado y ejecutado (ENTRYPOINT).

Spring Boot Docker

Una vez finalizada la construcción del docker, puede ejecutarlo con el nombre que le dio.

Ejecutar Docker con Spring Boot

Una vez que tenga la imagen docker, puede ejecutarlo con docker run
El parámetro -p le dice a Docker que exponga el puerto 8080 de nuestra aplicación que se ejecuta dentro del contenedor, en el puerto 5000 del sistema operativo.

docker run  -p 5000:8080 springbootdockerexample

Spring Boot Docker

Ahora abre la URL que apunta al puerto que le dijo a docker. En este caso 5000 http://localhost:5000/

¡Sonría, tu aplicación está ya funcionando en un contenedor Docker! Spring Boot Docker

Crea la imagen de Docker con Spring Boot usando Gradle

Si usas Gradle puedes agregar un plugin para construir la imagen y ejecutarla directamente desde los comandos de Gradle. Para esto, modifica el build.gradle añadiendo este plugin https://github.com/palantir/gradle-docker

Lo nuevo que se añade es lo que se ve en buildscript, a continuación, el apply del plugin y, finalmente, una nueva tarea ‘docker’.

// 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 = 'com.gustavopeiretti'
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}"])
}

Analicemos la nueva tarea docker del archivo de compilación gradlew que hemos modificado:

  • dependsOn build le decimos que esta tarea depende del build de gradle, deberá ocurrir primero el build.
  • name “${project.name}” será el nombre del contenedor, le daremos el nombre del proyecto que tenemos en settings.gradle
  • files bootJar.archivePath hará que el archivo jar generado por la compilación esté disponible
  • buildArgs ([‘JAR_FILE’: “$ {bootJar.archiveName}"]) envía como argumento el nombre del fichero jar.

Spring Boot Docker

Ejecución de la imágen Docker con Spring Boot usando Gradle

Si ya has modificado tu archivo build añadiendo el plugin com.palantir.docker , puedes ejecutar directamente el build y crear tu imagen desde gradle. Desde su consola, debes usar gradlew build docker para construir una imagen.

gradlew build docker
docker run -p 5000:8080 springbootdocker

Spring Boot Docker

Crear la imagen de Docker con Spring Boot usando Maven

En el caso de usar Maven, debe agregar este plugin si desea crear la imagen directamente desde mvn https://github.com/spotify/dockerfile-maven

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

Tu pom.xml completo se ve así:

<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>com.gustavopeiretti</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>

Ejecución de la imagen Docker con Spring Boot usando Maven

Una vez que haya agregado el plugin https://github.com/spotify/dockerfile-maven ejecuta lo siguiente:

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

Spring Boot Docker

Cuando ejecute docker run su aplicación se iniciará para la url localhost url:5000

Spring Boot Docker

Un resumen de los comandos docker que fueron útiles en este post:

  • docker build para crear la imagen docker
  • docker run para ejecutar la imagen docker
  • docker images ver las imágenes docker que tiene disponibles.

As always this code can be found by GitHub

https://github.com/gustavopeiretti/spring-boot-examples/tree/master/spring-boot-docker-example

Conclusión

Aprendiste a crear una aplicación Spring Boot Rest, configurar un dockerfile para su aplicación, construir su contenedor Docker y ejecutar su microservicio desde el contenedor. También aprendiste algunos comandos básicos de docker.

Hi! If you find my posts helpful, please support me by inviting me for a coffee :)

Ver también