Docker多阶段构建:如何让阶段依赖其他阶段却不使用其内容
核心问题
是否可以让Docker多阶段构建中的某个阶段依赖一个或多个其他阶段,但不使用这些阶段的任何内容?即,即使阶段X不使用阶段Y的任何内容,能否让阶段X在阶段Y失败时也随之失败?
场景详情
我有一个基于React + JavaScript的单页应用,使用Docker多阶段构建来搭建工作区、执行测试、编译代码,最终生成用Nginx部署的SPA镜像。简化后的Dockerfile如下:
FROM node:16.14.2-bullseye AS build # 复制整个Git仓库(排除.dockerignore中的文件)到工作区 COPY . /app WORKDIR /app # 下载依赖 RUN yarn install --frozen-lockfile # 运行测试 RUN yarn test # 构建应用 RUN yarn build FROM nginx:1.23.1-alpine AS nginx # 将构建产物复制到Nginx的网页根目录 COPY --from=build /app/build /usr/share/nginx/html
yarn test和yarn build执行失败时会返回非零退出码,从而终止构建,这符合预期。
由于测试和构建完全独立,我希望进一步拆分构建流程,让这两个步骤可以并行执行,待全部成功后再构建Nginx镜像。以下是接近需求的配置:
# Stage `workspace` - 包含仓库所有文件并安装好依赖的工作区 FROM node:16.14.2-bullseye AS workspace COPY . /app WORKDIR /app RUN yarn install --frozen-lockfile # Stage `test` - 运行单元测试 FROM workspace AS test RUN yarn test # Stage `compile` - 构建SPA FROM workspace AS compile RUN yarn build # Stage `nginx`- 部署构建好的站点 FROM nginx:1.23.1-alpine AS nginx COPY --from=compile /app/build /usr/share/nginx/html
现在我可以执行docker build --target=test .仅运行测试,docker build --target=compile .仅构建SPA,docker build --target=nginx .生成Nginx镜像。如果compile阶段失败,Nginx镜像的构建也会失败,这是合理的。但如果测试失败,仍然能构建出基于未通过测试代码的Nginx镜像,我希望改变这一现状。
备选方案(均不尽如人意)
- 在构建流水线中先运行测试,再执行Nginx构建:我已经这么做了,但如果有人误删测试步骤,还是能构建镜像。而且在Dockerfile中明确声明预期流程会更合理。
- 在
test阶段创建空占位文件(如touch TESTS_OK),并复制到nginx阶段(COPY --from=test /app/TESTS_OK /):这能明确依赖关系,但向Nginx镜像中复制无关文件的做法略显牵强。 - 使用中间阶段复制
compile和test阶段的文件,再让nginx阶段从中复制所需内容:与上一方案类似,但多了一层间接性(略显繁琐),不过可以避免向Nginx镜像中添加无用文件(这一点较好)。
目前最后一个方案是我相对最能接受的,但这些方案都属于权宜之计。是否有更优的方式来声明某阶段依赖其他阶段成功完成,却无需使用该阶段的任何内容?
内容的提问来源于stack exchange,提问作者gustafc
相关产品推荐
相关产品推荐

