使用 Gradle/Maven 的 SpringBoot 应用程序的通用 Docker 映像和 Dockerfile
Posted
技术标签:
【中文标题】使用 Gradle/Maven 的 SpringBoot 应用程序的通用 Docker 映像和 Dockerfile【英文标题】:Generic Docker Image and Dockerfile for SpringBoot Apps using Gradle/Maven 【发布时间】:2016-09-21 21:55:28 【问题描述】:根据https://spring.io/guides/gs/spring-boot-docker/,我们可以使用应用程序的硬编码名称和版本为 SpringBoot 应用程序创建 Docker 映像。例如:
src/main/docker/Dockerfile
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"]
但是,更改应用程序的名称或版本会破坏您在 build.gradle 任务中放置的 Docker Build 命令。
build.gradle
task buildDocker(type: Docker, dependsOn: build)
push = true
applicationName = jar.baseName
dockerfile = file('src/main/docker/Dockerfile')
doFirst
copy
from jar
into stageDir
命令 gradle buildDocker 通过暂存应用程序中的 Dockerfile 和可执行 Jar 并执行“docker build”来构建映像。
问题
考虑到 Dockerfile 中的名称是静态的,如何更改此设置以在更改版本后不破坏我的构建,甚至在构建 docker 映像时更改我的 SpringBoot 应用程序的名称?
【问题讨论】:
【参考方案1】:从 Dockerfile 回溯,我们可以只需要添加“app.jar”。所以,从
ADD gs-spring-boot-docker-0.1.0.jar app.jar
到
ADD app.jar app.jar
这导致需要重命名或复制生成的可执行 Jar。此示例将可执行 jar 重命名为“app.jar”,因此可以轻松构建 docker 映像。可以在下面找到可以复制到要在 Gradle 中构建的任何 SpringBoot 应用程序的通用任务。
build.gradle
/**
* 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"
最终生成的Dockerfile如下:
src/main/docker/Dockerfile
FROM frolvlad/alpine-oraclejdk8:slim
MAINTAINER Marcello_deSales@intuit.com
VOLUME /tmp
ADD app.jar app.jar
RUN sh -c 'touch /app.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
命令“gradle buildDocker”将生成 docker 镜像,并且作为奖励,将打印完整的命令以供您执行应用程序(请注意,默认端口号是硬编码的,如果您更改该值,则必须更改)。
【讨论】:
【参考方案2】:适用于带有 Maven 的 SpringBoot 应用程序的通用多阶段 Dockerfile
我使用多阶段构建而不是维护多个 dockerfile https://docs.docker.com/develop/develop-images/multistage-build 为 Springboot 应用程序开发了新版本的通用 Dockerfile 这使用Maven
。 Gradle
也可以采用类似的方法。
这会运行测试用例,然后构建运行时映像
支持从运行测试中分离下载依赖项
单独构建测试阶段docker build -t tests --target builder .
默认使用代码覆盖率运行单元测试
从开关 mvn -s settings.xml -Dtest="!*IT,!*IntegrationTest" -P jacoco test
运行集成测试。
支持提供JAVA_PARAMS
和JAVA_OPTS
用于调试和所需的任何内容
如果您在 Docker Swarm 或 Kubernetes Helm 中部署此映像。
提供 settings.xml 以指向您的 Maven 存储库服务器(公共或私有)
下面的构建将执行以下操作:
#
# Build stage to for building the Jar
#
FROM maven:3.2.5-jdk-8 as builder
MAINTAINER marcello.desales@gmail.com
# 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"
构建和运行测试
按照多阶段构建规范,我们现在可以只生成测试映像 对于多种类型的测试(单元、集成),您可以拆分执行。因此,构建测试可以如下完成:
$ 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 marcello.desales@gmail.com
---> 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
然后你就可以执行测试了:
$ docker run -ti generic-dockerfile:tests
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building spring-cloud-config-server 1.1.6-SNAPSHOT
[INFO] ------------------------------------------------------------------------
您还可以覆盖 CMD 参数以运行上述 Dockerfile 中记录的集成测试。
构建并运行应用程序
您可以像往常一样构建运行时映像
$ 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
运行应用程序就这么简单
$ 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
【讨论】:
我创建了github.com/intuit/unmazedboot,让 SpringBoot 开发人员的生活更轻松、更简单! Dockerfile 中的 3 行代码 :)以上是关于使用 Gradle/Maven 的 SpringBoot 应用程序的通用 Docker 映像和 Dockerfile的主要内容,如果未能解决你的问题,请参考以下文章
Gradle 构建错误:无法从 https://repo1.maven.org/maven2/io/fabric/tools/gradle/maven-metadata.xml 加载 Maven 元数
jenkins+gradle/maven+sonar+pipline