使用COPY --from从其他镜像层复制目录失败问题排查
问题:Docker多阶段构建中COPY --from无法找到构建层目录
问题详情
- 执行Docker多阶段构建时,从
build阶段复制/app/dist/siai-spa目录到Nginx层失败,提示file does not exist - 本地机器上构建正常,但CI环境构建失败
- 疑问:构建日志显示中间容器被移除,是否因此导致复制失败?能否保留中间容器确保复制正常?
附Dockerfile代码
FROM node:16.16 as build # USER node WORKDIR /app COPY package.json /app RUN npm install --location=global npm@latest && npm install --silent COPY . . ARG SCRIPT ENV SCRIPT=$SCRIPT ARG API_URL ENV API_URL=$API_URL ARG API_SERVER ENV API_SERVER=$API_SERVER CMD ["/bin/sh", "-c", "envsubst < src/proxy.conf.template.js > src/proxy.conf.js"] RUN npm run ${SCRIPT} FROM nginx:1.23 VOLUME /var/cache/nginx EXPOSE 80 COPY --from=build /app/dist/siai-spa /usr/share/nginx/html COPY ./config/nginx-template.conf /etc/nginx/nginx-template.conf
构建日志片段
b9ed43dcc388: Pull complete Digest: sha256:db345982a2f2a4257c6f699a499feb1d79451a1305e8022f16456ddc3ad6b94c Status: Downloaded newer image for nginx:1.23 ---> 41b0e86104ba Step 15/24 : VOLUME /var/cache/nginx ---> Running in dc0e24ae6e51 Removing intermediate container dc0e24ae6e51 ---> 3b2799dad197 Step 16/24 : EXPOSE 80 ---> Running in f30edd617285 Removing intermediate container f30edd617285 ---> 21985745ce49 Step 17/24 : COPY --from=build /app/dist/siai-spa /usr/share/nginx/html COPY failed: stat app/dist/siai-spa: file does not exist Cleaning up project directory and file based variables 00:00 ERROR: Job failed: exit code 1
原因分析与解决方案
中间容器移除不是问题根源
Docker多阶段构建中,COPY --from=build依赖的是build阶段生成的镜像,而非临时运行的中间容器。中间容器仅用于执行构建指令,完成后自动移除是正常行为,不会影响镜像内的文件存储,因此无需刻意保留中间容器。核心问题:CMD指令执行时机错误
Dockerfile中CMD指令是在容器运行时执行的,而非构建阶段。而RUN npm run ${SCRIPT}是在构建阶段执行的,此时src/proxy.conf.js还未通过envsubst生成——如果前端构建脚本依赖这个配置文件,就会导致构建失败,最终无法生成/app/dist/siai-spa目录。
本地构建正常是因为本地环境可能已提前生成了src/proxy.conf.js,而CI环境是干净的全新环境,没有该文件,因此构建失败。
- 修复方案
将CMD指令替换为RUN指令,确保配置文件替换在构建阶段完成:
# 原CMD指令替换为RUN RUN ["/bin/sh", "-c", "envsubst < src/proxy.conf.template.js > src/proxy.conf.js"] RUN npm run ${SCRIPT}
- 调试手段(可选)
如果需要排查构建过程中的文件状态,可以在构建时添加--rm=false参数,禁止自动移除中间容器:
docker build --rm=false -t your-image-name .
之后通过docker ps -a找到对应中间容器,用docker exec -it <container-id> /bin/sh进入容器查看文件情况,调试完成后手动清理容器即可。
内容的提问来源于stack exchange,提问作者dev5521
相关产品推荐
相关产品推荐

