系统环境

  • Docker 版本:19.03.13
  • 操作系统版本:CentOS 7.6

问题描述

在日常使用 Docker 过程中,会经常自己构建一些应用程序的镜像,其中Docker官方提供了多阶段构建镜像功能,使我们在构建镜像时减少部署的镜像的层数,从而减小镜像整体大小,这里在使用Jenkins进行持续集成操作时,尝试使用Java的SpringBoot框架提供的分层构建镜像方案构建镜像,在执行过程中遇到了一些问题,这里先贴出 Dockerfile 内容:

#构建过程镜像
FROM openjdk:8u262
WORKDIR application
COPY target/*.jar application.jar
RUN java -Djarmode=layertools -jar application.jar extract

#构建真正运行部署的镜像
FROM openjdk:8u262
WORKDIR application
COPY --from=0 application/dependencies/ ./
COPY --from=0 application/snapshot-dependencies/ ./
COPY --from=0 application/spring-boot-loader/ ./
COPY --from=0 application/application/ ./
ENV JVM_OPTS="-XX:MaxRAMPercentage=80.0"
ENV JAVA_OPTS=""
ENTRYPOINT ["sh","-c","java $JVM_OPTS $JAVA_OPTS org.springframework.boot.loader.JarLauncher"]

本地Docker执行上面Dockerfile,使用多阶段构建,发现在执行过程中是不存在上述问题。不过将这个镜像放在持续集成工具Jenkins中后,就出现如下错误

Step 1/15 : FROM openjdk:8u262
 ---> 51d6b33ebe8a
Step 2/15 : WORKDIR application
 ---> Running in b0398a3754d7
Removing intermediate container b0398a3754d7
 ---> 408784f98bc2
Step 3/15 : COPY target/*.jar application.jar
 ---> e13bbd838db4
Step 4/15 : RUN java -Djarmode=layertools -jar application.jar extract
 ---> Running in 3a23e82340c3
Removing intermediate container 3a23e82340c3
 ---> d545089f321d
Step 5/15 : FROM openjdk:8u262
 ---> 51d6b33ebe8a
Step 6/15 : WORKDIR application
 ---> Using cache
 ---> 408784f98bc2
Step 7/15 : COPY --from=0 application/dependencies/ ./
 ---> 09fa3826ddd5
Step 8/15 : COPY --from=0 application/snapshot-dependencies/ ./
 ---> b1484b758fad
Step 9/15 : COPY --from=0 application/spring-boot-loader/ ./
failed to export image: failed to create image: failed to get layer sha256:9...3c205: layer does not exist

显示layer does not exist 镜像层不存,导致不能继续构建镜像问题

问题解决

网上搜索相关问题,寻找发生该错误的原因,发现并没与一种很好的说法到底是什么原因导致的该错误的发生,不过大部分人推测可能是因为 Overlay2 存储引擎兼容引擎的一些问题。从地址 https://github.com/moby/moby/issues/37965 参考到,大部分发生 layer does not exist 错误都是在第二阶段复制时发生。所以,有人给了一种解决方案,就是在每次执行 COPY --form 后添加 RUN true 命令

...
COPY --from=0 /a ./
RUN true                ##添加RUN true
COPY --from=0 /b ./
RUN true                ##添加RUN true
COPY --from=0 /c ./
RUN true                ##添加RUN true
...

尝试使用这种方案解决这个问题,在第二阶段构建时的COPY --form后面添加RUN true 命令,修改后的 Dockerfile 如下:

## 构建第一级镜像
FROM openjdk:8u262
WORKDIR application
COPY target/*.jar application.jar
RUN java -Djarmode=layertools -jar application.jar extract

## 构建第二级镜像
FROM openjdk:8u262
WORKDIR application
COPY --from=0 application/dependencies/ ./
RUN true         ##添加RUN true
COPY --from=0 application/snapshot-dependencies/ ./
RUN true         ##添加RUN true
COPY --from=0 application/spring-boot-loader/ ./
RUN true         ##添加RUN true
COPY --from=0 application/application/ ./
RUN true
ENV TZ="Asia/Shanghai"
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ENV JVM_OPTS="-XX:MaxRAMPercentage=80.0"
ENV JAVA_OPTS=""
ENTRYPOINT ["sh","-c","java $JVM_OPTS $JAVA_OPTS org.springframework.boot.loader.JarLauncher"]
文章作者: 鲜花的主人
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 爱吃可爱多
Docker Docker
喜欢就支持一下吧
打赏
微信 微信
支付宝 支付宝