基于Maven的Github项目的Dockerfile

自从Docker“革命”以来,我一直对为Spring应用程序创建Dockefile感兴趣。 我不是一位热心的从业者,但是创建Dockerfile的原理非常简单。 与Java-或可能是任何编程语言一样,虽然容易实现有效的工作,但是要创建良好的工作要困难得多。

多阶段构建

在Docker中,主要问题之一是最终映像的大小。 即使对于简单的Java应用程序,最终获得超过1 GB的图像也很常见。 从Docker版本17.05开始,可以在单个Dockerfile包含多个构建,并可以将先前构建的输出访问到当前构建中。 这些称为多阶段构建。 最终图像将基于最后的构建阶段。

假设代码托管在Github上,并且它基于Maven。 构建阶段如下:

  1. 从Github克隆代码
  2. 复制上一阶段的文件夹; 使用Maven构建应用
  3. 复制上一个阶段的JAR; java -jar运行它

这是一个开始的构建文件:

FROM alpine/git
WORKDIR /app
RUN git clone https://github.com/spring-projects/spring-petclinic.git (1)

FROM maven:3.5-jdk-8-alpine
WORKDIR /app
COPY --from=0 /app/spring-petclinic /app  (2)
RUN mvn install  (3)

FROM openjdk:8-jre-alpine
WORKDIR /app
COPY --from=1 /app/target/spring-petclinic-1.5.1.jar /app  (4)
CMD ["java -jar spring-petclinic-1.5.1.jar"]  (5)

它映射了以上构建阶段:

  1. 从Github克隆Spring PetClinic git存储库
  2. 复制上一个构建阶段的项目文件夹
  3. 编译应用
  4. 复制上一个构建阶段的JAR
  5. 运行应用

提高可读性

请注意,在先前的构建文件中,构建阶段通过其索引(从0开始)被引用, 例如 COPY --from=0 。 虽然这不是一个真正的问题,但总有一些有意义的语义总是更好的。 Docker允许标记阶段,并在以后阶段引用这些标记。

FROM alpine/git as clone (1)
WORKDIR /app
RUN git clone https://github.com/spring-projects/spring-petclinic.git

FROM maven:3.5-jdk-8-alpine as build  (2)
WORKDIR /app
COPY --from=clone /app/spring-petclinic /app  (3)
RUN mvn install

FROM openjdk:8-jre-alpine
WORKDIR /app
COPY --from=build /app/target/spring-petclinic-1.5.1.jar /app
CMD ["java -jar spring-petclinic-1.5.1.jar"]
  1. 将第一阶段标记为clone
  2. 将第二阶段标记为build
  3. 使用标签引用第一阶段

选择正确的图像

多阶段构建对图像大小管理有很大帮助,但这不是唯一的标准。 开始的图像对最终图像有很大的影响。 初学者通常会使用成熟的操作系统映像(例如Ubuntu) ,而没有充分的理由夸大最终映像的大小。 但是,有轻量级操作系统,非常适合Docker映像,例如Alpine Linux

由于攻击面有限,因此它也非常适合安全目的。

在上面的构建文件中,图像如下:

  1. 高山/ git
  2. 专家:3.5-jdk-8-alpine
  3. openjdk:8-jre-alpine

他们都从高山继承或直接继承。

图像尺寸如下:

REPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE
nfrankel/spring-petclinic       latest              293bd333d60c        10 days ago         117MB
openjdk                         8-jre-alpine        c4f9d77cd2a1        4 weeks ago         81.4MB

JRE和应用程序映像之间的大小差异约为36 MB,这就是JAR本身的大小。

暴露端口

Spring Pet Clinic是一个Web应用程序,因此需要公开将绑定到的HTTP端口。 相关的Docker指令是EXPOSE 。 我选择8080作为端口号,使其与嵌入式Tomcat容器相同,但是可以是任何东西。 最后阶段应修改为:

FROM openjdk:8-jre-alpine
WORKDIR /app
COPY --from=build /app/target/spring-petclinic-1.5.1.jar /app
EXPOSE 8080
CMD ["java -jar spring-petclinic-1.5.1.jar"]

参数化

此时,似乎该构建文件可用于构建具有以下功能的任何 Webapp:

  1. 源代码托管在Github上
  2. 构建工具是Maven
  3. 结果输出是可执行的JAR文件

当然,这非常适合Spring Boot应用程序,但这并不是硬性要求。

参数包括:

  • Github存储库URL
  • 项目名称
  • Maven的artifactIdversion
  • artifactId名称(可能与artifactId不同,具体取决于特定的Maven配置)

让我们使用它们来设计参数化的构建文件。 在Docker中,可以使用ENVARG选项传递参数。 两者都在命令行上使用--build-arg选项设置。 差异如下:

Type

ENV

ARG

Found in the image

Default value

Required

Optional

FROM alpine/git as clone
ARG url (1)
WORKDIR /app
RUN git clone ${url}  (2)

FROM maven:3.5-jdk-8-alpine as build
ARG project  (3)
WORKDIR /app
COPY --from=clone /app/${project} /app
RUN mvn install

FROM openjdk:8-jre-alpine
ARG artifactid
ARG version
ENV artifact ${artifactid}-${version}.jar  (4)
WORKDIR /app
COPY --from=build /app/target/${artifact} /app
EXPOSE 8080
CMD ["java -jar ${artifact}"]  (5)
  1. 必须在命令行中传递url以设置要克隆的Github存储库
  2. url被传递的值替换
  3. 与<1>相同
  4. artifact必须是ENV ,以便保留在最终的应用程序映像中
  5. 在运行时使用artifact

建造

现在可以使用以下命令行来构建Spring Pet Clinic映像:

docker build--build-argurl= https://github.com/spring-projects/spring-petclinic.git \
  --build-argproject= spring-petclinic \
  --build-argartifactid= spring-petclinic \
  --build-argversion= 1.5.1 \
  -t nfrankel/spring-petclinic - < Dockerfile
由于映像不依赖于文件系统,因此无需传递任何上下文,并且可以从标准输入中传递Dockerfile。

要构建另一个应用程序,可以相应地更改参数, 例如

docker build--build-argurl= https://github.com/heroku/java-getting-started.git \
  --build-argproject= java-getting-started \
  --build-argartifactid= java-getting-started \
  --build-argversion= 1.0 \
  -t nfrankel/java-getting-started - < Dockerfile

跑步

运行使用上述命令构建的映像非常简单:

docker run-ti-p8080 :8080 nfrankel/spring-petclinic

不幸的是,它失败并显示以下错误消息: starting container process caused "exec: \"java -jar ${artifact}\": executable file not found in $PATH 。窍门是使用ENTRYPOINT指令。更新后的Dockerfile看起来像根据以下内容:

FROM openjdk:8-jre-alpine
ARG artifactid
ARG version
ENV artifact ${artifactid}-${version}.jar (4)
WORKDIR /app
COPY --from=build /app/target/${artifact} /app
EXPOSE 8080
ENTRYPOINT ["sh", "-c"]
CMD ["java -jar ${artifact}"]  (5)

至此,运行容器将(最终)工作。

第二个映像使用不同的端口,因此命令应为:docker run -ti -p8080:5000 nfrankel / java-getting-started。

思想的食物

外部Git

当前版本会克隆一个存储库,因此不需要将上下文发送到Docker。 一种替代方法是在构建文件外部克隆, 例如在连续集成链中克隆,然后从上下文开始。 这对于在开发人员机器上进行开发期间构建映像很有用。

是否最新版本

对于Git映像,我使用最新版本,而对于JDK和JRE映像,我使用特定的主要版本。 将Java版本固定为主要版本非常重要,而对于Git而言则不那么重要。 这取决于图像的性质。

master建造

克隆后没有更改分支的配置。 这是错误的,因为在大多数情况下,构建是在专用标签( 例如 v1.0.0上执行的。 显然,应该有一个附加的命令-以及一个附加的build参数,以在构建之前签出特定的标签。

跳过测试

Pet Clinic应用程序的构建需要花费大量时间,因为它具有庞大的测试工具。 执行这些测试需要花费时间,Maven必须经历test阶段才能到达install阶段。 根据特定的连续集成链,测试可能早些执行,并且在映像构建期间不得再次执行。

Maven资料库下载

Spring Boot应用程序具有很多依赖性。 构建映像需要很长时间,因为每个应用程序每次都需要下载所有依赖项。 有两种解决方案可以解决这个问题。 它可能是另一篇文章的主题。

这篇文章的完整源代码可以在Github上找到。

翻译自: https://blog.frankel.ch/dockerfile-maven-based-github-projects/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值