解决 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---
!版权声明:本博客内容均为原创,每篇博文作为知识积累,写博不易,转载请注明出处。