Reputation: 22319
According to https://spring.io/guides/gs/spring-boot-docker/, we can create Docker Images for SpringBoot applications using hard-coded name and version of the application. For instance:
FROM frolvlad/alpine-oraclejdk8:slim
VOLUME /tmp
ADD gs-spring-boot-docker-0.1.0.jar app.jar
RUN sh -c 'touch /app.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
However, changing the name or the version of the app breaks the Docker Build command that you place in your build.gradle task.
task buildDocker(type: Docker, dependsOn: build) {
push = true
applicationName = jar.baseName
dockerfile = file('src/main/docker/Dockerfile')
doFirst {
copy {
from jar
into stageDir
}
}
}
The command gradle buildDocker builds an image by staging the Dockerfile and the executable Jar from the app, and executing "docker build".
Considering the names are static in Dockerfile, How can I change this setup to not break my builds once I change the version, or even the name my SpringBoot application when building the docker image?
Upvotes: 3
Views: 5116
Reputation: 22319
Maven
. Similar approach can be done for Gradle
.docker build -t tests --target builder .
mvn -s settings.xml -Dtest="!*IT,!*IntegrationTest" -P jacoco test
.JAVA_PARAMS
and JAVA_OPTS
for debugging and anything required
The build below will do the following:
#
# Build stage to for building the Jar
#
FROM maven:3.2.5-jdk-8 as builder
MAINTAINER [email protected]
# Only copy the necessary to pull only the dependencies from Intuit's registry
ADD ./pom.xml /opt/server/pom.xml
# As some entries in pom.xml refers to the settings, let's keep it same
ADD ./settings.xml /opt/server/settings.xml
WORKDIR /opt/server/
# Prepare by downloading dependencies
RUN mvn -s settings.xml -B -e -C -T 1C org.apache.maven.plugins:maven-dependency-plugin:3.0.2:go-offline
# Run the full packaging after copying the source
ADD ./src /opt/server/src
RUN mvn -s settings.xml install -P embedded -Dmaven.test.skip=true -Dmaven.javadoc.skip=true -B -e -o -T 1C verify
# Building only this stage can be done with the --target builder switch
# 1. Build: docker build -t config-builder --target builder .
# When running this first stage image, just verify the unit tests
# Overriden them by removing the "!" for integration tests
# 2. docker run --rm -ti config-builder mvn -s settings.xml -Dtest="*IT,*IntegrationTest" test
CMD mvn -s settings.xml -Dtest="!*IT,!*IntegrationTest" -P jacoco test
#
# Build stage with the runtime jar and resources
#
FROM openjdk:8-jre-slim
# Copy from the previous stage
COPY --from=builder /opt/server/target/*.jar /tmp/
# Just rename the built version
RUN mkdir /runtime && \
find /tmp -name "*.jar" ! -name "*sources*" -exec cp -t /runtime {} + && \
mv /runtime/*.jar /runtime/server.jar && \
rm -f /tmp/*.jar
# Port used by the server
EXPOSE 8888
# This is to support HTTPS calls to
RUN apt-get update && apt-get install -y curl ca-certificates
RUN update-ca-certificates && \
mkdir -p /usr/share/ssl/certs && \
chmod 755 /usr/share/ssl/certs
# What to execute on docker run
ENTRYPOINT sh -c "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom \
$JAVA_PARAMS -jar /runtime/server.jar --server.port=8888 $SPRING_BOOT_APP_OPTS"
So, the building the tests can be done as follows:
$ docker build -t generic-dockerfile:tests --target builder .
Sending build context to Docker daemon 16.82MB
Step 1/9 : FROM maven:3.2.5-jdk-8 as builder
---> 95dd59c15f5d
Step 2/9 : MAINTAINER [email protected]
---> Using cache
---> e4edaeb48381
Step 3/9 : ADD ./pom.xml /opt/server/pom.xml
---> Using cache
---> b2d6d834b411
Step 4/9 : ADD ./settings.xml /opt/server/settings.xml
---> Using cache
---> 9b0964db2c9f
Step 5/9 : WORKDIR /opt/server/
---> Using cache
---> 542d0bd9d12f
Step 6/9 : RUN mvn -s settings.xml -B -e -C -T 1C org.apache.maven.plugins:maven-dependency-plugin:3.0.2:go-offline
---> Using cache
---> 3c2d8df6b52e
Step 7/9 : ADD ./src /opt/server/src
---> Using cache
---> 6d48dd3f9f85
Step 8/9 : RUN mvn -s settings.xml install -P embedded -Dmaven.test.skip=true -Dmaven.javadoc.skip=true -B -e -o -T 1C verify
---> Using cache
---> 1c109d2026c4
Step 9/9 : CMD mvn -s settings.xml -Dtest="!*IT,!*IntegrationTest" -P jacoco test
---> Using cache
---> 45eac3094ea4
Successfully built 45eac3094ea4
Successfully tagged generic-dockerfile:tests
Then you can execute the tests:
$ docker run -ti generic-dockerfile:tests
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building spring-cloud-config-server 1.1.6-SNAPSHOT
[INFO] ------------------------------------------------------------------------
You can build the runtime image as usual
$ docker build -t generic-dockerfile .
done.
done.
Removing intermediate container e632d7c310f7
---> e9391a0ca21d
Step 16/16 : ENTRYPOINT sh -c "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom $JAVA_PARAMS -jar /runtime/server.jar --server.port=8888 $SPRING_BOOT_APP_OPTS"
---> Running in 849ba7ad3212
Removing intermediate container 849ba7ad3212
---> 909354984264
Successfully built 909354984264
Successfully tagged generic-dockerfile:latest
Running the application is as simple as the following
$ docker run -ti generic-dockerfile
ThisHost: getLocalHost says localHost="c34b2cedbebf/172.17.0.2" isLoopbackAddress=false
2018-04-19T19:15:41,180 3166 | INFO | internal.util.Version.<clinit>#30 ["background-preinit" {}] HV000001: Hibernate Validator 5.2.5.Final
2018-04-19T19:15:41,470 3456 | INFO | factory.annotation.AutowiredAnnotationBeanPostProcessor.<init>#155 ["main" {svr=c34b2cedbebf}] JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
Upvotes: 1
Reputation: 22319
Backtracking from the Dockerfile, we could just require to add "app.jar". So, from
ADD gs-spring-boot-docker-0.1.0.jar app.jar
to
ADD app.jar app.jar
This leads to the need of renaming or copying the generated executable Jar. This example renames the executable jar to "app.jar", and so, making it easy for building the docker image. A generic task that can be copied to any SpringBoot app to be built in Gradle can be found below.
/**
* Generic support for building docker images for SpringBoot Apps
*/
task buildDocker(type: Docker, dependsOn: build) {
push = false
applicationName = rootProject.name
dockerfile = file('src/main/docker/Dockerfile')
doFirst {
// Rename the app jar to "app.jar" so that the Dockerfile does not require renames
copy {
from "${project.buildDir}/libs"
into stageDir
include "${rootProject.name}-${version}.jar"
rename("${rootProject.name}-${version}.jar", "app.jar")
}
}
doLast {
println "Run the Docker Container"
println "docker run -ti -p 8080:8080 $project.group/$applicationName:$version"
}
}
The final resulting Dockerfile is as follows:
FROM frolvlad/alpine-oraclejdk8:slim
MAINTAINER [email protected]
VOLUME /tmp
ADD app.jar app.jar
RUN sh -c 'touch /app.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
The command "gradle buildDocker" will generate docker images and as bonus, will print the complete command for you to execute the app (note that the default port number is hard-coded and must be changed if you change that value).
Upvotes: 1