200415_Java_SpringBoot_Container
200415_Java_SpringBoot_Container
April 2020
JUG Switzerland
Java
&
Spring Boot
im
Container
MICHAEL VITZ
Senior Consultant
INNOQ Deutschland GmbH
@michaelvitz
Example Application
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplicatio
<parent> import org.springframework.web.bind.annotation.GetMapping;
<groupId>org.springframework.boot</groupId> import org.springframework.web.bind.annotation.RestController;
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.M4</version> @SpringBootApplication
<relativePath/> @RestController
</parent> public class Application {
<groupId>de.mvitz</groupId> public static void main(String[] args) {
<artifactId>spring-container</artifactId> SpringApplication.run(Application.class, args);
<version>1.0.0-SNAPSHOT</version> }
<properties> @GetMapping
<java.version>11</java.version> public String index() {
</properties> return "Hello JUG Switzerland!";
}
<dependencies> }
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
“Fat”-JAR Container
FROM adoptopenjdk/openjdk11:jdk-11.0.6_10-alpine-slim
WORKDIR /app
USER daemon
WORKDIR /app
https://github.com/fabric8io/docker-maven-plugin
Fabric8 Maven-Docker-Plugin
• + Straightforward Dockerfile
• + No separate step in build process
• +- Only small abstraction
• +- No plugin configuration in POM required
• - “Fat”-JAR
Fabric8 Maven-Docker-Plugin
<configuration>
<images>
<image>
<name>spring-container-fabric8</name>
<build>
<from>adoptopenjdk/openjdk11:jdk-11.0.6_10-alpine-slim</from>
<runCmds>
<run>mkdir -p /app && chown -R daemon /app</run>
</runCmds>
<user>daemon</user>
<workdir>/app</workdir>
<assembly>
<targetDir>/app</targetDir>
<descriptorRef>artifact</descriptorRef>
</assembly>
<cmd>
<exec>
<arg>java</arg>
<arg>-jar</arg>
<arg>/app/${project.artifactId}-${project.version}.jar</arg>
</exec>
</cmd>
<ports>
<port>8080</port>
</ports>
</build>
Fabric8 Maven-Docker-Plugin
• + Additional capabilities (start/stop/watch/…)
• +- Some more abstraction
• - Dockerfile in XML
• - “Fat”-JAR
“Fat”-JAR?
$ du -h target/spring-container-1.0.0-SNAPSHOT.jar
16M target/spring-container-1.0.0-SNAPSHOT.jar
FROM …
maven-dependency-plugin
maven-dependency-plugin
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>copy-dependencies</goal> FROM adoptopenjdk/openjdk11:jdk-11.0.6_10-alpine-slim
</goals>
<configuration> RUN mkdir -p /app/lib && \
<includeScope>runtime</includeScope> chown -R daemon /app
</configuration>
</execution> USER daemon
</executions> WORKDIR /app
</plugin>
COPY ./target/dependency/ /app/lib
COPY ./target/spring-container-*.jar /app/spring-container.ja
CMD [ "java", \
"-classpath", \
"/app/spring-container.jar:/app/lib/*", \
"de.mvitz.spring.container.Application" ]
EXPOSE 8080
https://maven.apache.org/plugins/maven-dependency-plugin/
maven-dependency-plugin
• + Works with every Java application
• + Only downloads dependencies
• + Dockerfile stays clean
• - Not obvious that plugin is required for Image building
jib
jib
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>2.1.0</version>
<configuration>
<to>
<image>spring-container-jib</image>
</to>
</configuration>
</plugin>
./mvnw verify jib:dockerBuild
https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin
jib
• + Works with every Java application
• + Distroless Image
• +- No own Dockerfile
• +- Can be used without Docker daemon
• - Level of abstraction
Spring Boot
Spring Boot Extract
jar xf target/spring-container-1.0.0-SNAPSHOT.jar
Spring Boot Extract
• + Works with current stable Spring Boot version
• + Straightforward script
• +- Separate build step
• - Spring Boot dependent
• - Spring Loader is included by default
Spring Boot Layered JAR
java \
-Djarmode=layertools \
-jar target/spring-container.jar \
extract
Spring Boot Layered JAR
• + Layers are customisable (e.g. layer for company wide dependencies)
• + Straightforward script
• +- Separate build step
• +- Not yet released (Spring Boot 2.3 Feature)
• - Spring Boot dependent
Spring Boot Build Packs
./mvnw spring-boot:build-image
Spring Boot Build Packs
• + No need for configuration
• +- Not yet released (Spring Boot 2.3 Feature)
• - Multiple abstraction layers
• - Loss of control
Zombies
#!/usr/bin/env sh
set -euo pipefail
IFS=$'\n\t'
java \
-XX:+UnlockExperimentalVMOptions \
-XX:+UseJVMCICompiler \
-jar /app/spring-container.jar
CMD ["/app/run.sh"]
EXPOSE 8080
https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/
#!/usr/bin/env sh
set -euo pipefail
IFS=$'\n\t'
exec java \
-XX:+UnlockExperimentalVMOptions \
-XX:+UseJVMCICompiler \
-jar /app/spring-container.jar
CMD ["/app/run.sh"]
EXPOSE 8080
https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/
Additional thoughts
Additional thoughts
• Consider Docker Multi-Stage Builds
• Check and configure JVM Memory Management
• Look at other Solutions
• Containers are not a silver bullet
• https://docs.docker.com/develop/develop-images/dockerfile_best-
practices/
Thanks! Questions? www.innoq.com
Michael Vitz
michael.vitz@innoq.com
+49 151 19116015
@michaelvitz
https://github.com/mvitz/javaspektrum-spring-container