解决 Docker 多阶段构建 layer does not exist 错误

解决 Docker 多阶段构建 layer does not exist 错误

文章目录

  !版权声明:本博客内容均为原创,每篇博文作为知识积累,写博不易,转载请注明出处。


系统环境:

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

一、问题描述

我们在日常使用 Docker 过程中,会经常自己构建一些应用程序的镜像,其中 Docker 官方提供了多阶段构建镜像功能,使我们在构建镜像时减少部署的镜像的层数,从而减小镜像整体大小。

本人这里在使用 Jenkins 进行持续集成操作时,尝试使用 Java 的 SpringBoot 框架提供的分层构建镜像方案构建镜像,在执行过程中遇到了一些问题,这里先贴出 Dockerfile 内容:

 1## 构建过程镜像
 2FROM openjdk:8u262
 3WORKDIR application
 4COPY target/*.jar application.jar
 5RUN java -Djarmode=layertools -jar application.jar extract
 6
 7## 构建真正运行部署的镜像
 8FROM openjdk:8u262
 9WORKDIR application
10COPY --from=0 application/dependencies/ ./
11COPY --from=0 application/snapshot-dependencies/ ./
12COPY --from=0 application/spring-boot-loader/ ./
13COPY --from=0 application/application/ ./
14ENV JVM_OPTS="-XX:MaxRAMPercentage=80.0"
15ENV JAVA_OPTS=""
16ENTRYPOINT ["sh","-c","java $JVM_OPTS $JAVA_OPTS org.springframework.boot.loader.JarLauncher"]

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

 1Step 1/15 : FROM openjdk:8u262
 2 ---> 51d6b33ebe8a
 3Step 2/15 : WORKDIR application
 4 ---> Running in b0398a3754d7
 5Removing intermediate container b0398a3754d7
 6 ---> 408784f98bc2
 7Step 3/15 : COPY target/*.jar application.jar
 8 ---> e13bbd838db4
 9Step 4/15 : RUN java -Djarmode=layertools -jar application.jar extract
10 ---> Running in 3a23e82340c3
11Removing intermediate container 3a23e82340c3
12 ---> d545089f321d
13Step 5/15 : FROM openjdk:8u262
14 ---> 51d6b33ebe8a
15Step 6/15 : WORKDIR application
16 ---> Using cache
17 ---> 408784f98bc2
18Step 7/15 : COPY --from=0 application/dependencies/ ./
19 ---> 09fa3826ddd5
20Step 8/15 : COPY --from=0 application/snapshot-dependencies/ ./
21 ---> b1484b758fad
22Step 9/15 : COPY --from=0 application/spring-boot-loader/ ./
23failed 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 命令。

1COPY --from=0 /a ./
2RUN true                ##添加RUN true
3COPY --from=0 /b ./
4RUN true                ##添加RUN true
5COPY --from=0 /c ./
6RUN true                ##添加RUN true
7...

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

 1## 构建第一级镜像
 2FROM openjdk:8u262
 3WORKDIR application
 4COPY target/*.jar application.jar
 5RUN java -Djarmode=layertools -jar application.jar extract
 6
 7## 构建第二级镜像
 8FROM openjdk:8u262
 9WORKDIR application
10COPY --from=0 application/dependencies/ ./
11RUN true         ##添加RUN true
12COPY --from=0 application/snapshot-dependencies/ ./
13RUN true         ##添加RUN true
14COPY --from=0 application/spring-boot-loader/ ./
15RUN true         ##添加RUN true
16COPY --from=0 application/application/ ./
17RUN true
18ENV TZ="Asia/Shanghai"
19RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
20ENV JVM_OPTS="-XX:MaxRAMPercentage=80.0"
21ENV JAVA_OPTS=""
22ENTRYPOINT ["sh","-c","java $JVM_OPTS $JAVA_OPTS org.springframework.boot.loader.JarLauncher"]

然后执行持续集成构建,确实不会再发送上述错误了。遇到相同错误的朋友可以添加 RUN true 尝试一下。

---END---


  !版权声明:本博客内容均为原创,每篇博文作为知识积累,写博不易,转载请注明出处。