使用 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 这使用MavenGradle 也可以采用类似的方法。 这会运行测试用例,然后构建运行时映像 支持从运行测试中分离下载依赖项 单独构建测试阶段docker build -t tests --target builder . 默认使用代码覆盖率运行单元测试 从开关 mvn -s settings.xml -Dtest="!*IT,!*IntegrationTest" -P jacoco test 运行集成测试。 支持提供JAVA_PARAMSJAVA_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/maven/eclipse工程相互转化

Gradle 构建错误:无法从 https://repo1.maven.org/maven2/io/fabric/tools/gradle/maven-metadata.xml 加载 Maven 元数

Gradle Maven部署,转化

jenkins+gradle/maven+sonar+pipline

如何为 IntelliJ IDEA 项目禁用或启用 Gradle / Maven 自动导入?

收到致命警报:protocol_version 构建失败 Gradle/Maven