为什么 docker 需要构建所有前面的阶段?

Why docker needs to build all the previous stages?

我需要在一个共同的基础上构建 2 个阶段

$ ls
Dockerfile  dev  other  prod

$ cat Dockerfile
FROM scratch as dev
COPY dev /

FROM scratch as other
COPY other /

FROM scratch as prod
COPY --from=dev /env /
COPY prod /

如您所见,prod 阶段不依赖于 other 阶段,但无论如何它都会构建它

$ docker build . --target prod
Sending build context to Docker daemon  4.096kB
Step 1/7 : FROM scratch as dev
 ---> 
Step 2/7 : COPY dev /
 ---> 64c24f1f1d8c
Step 3/7 : FROM scratch as other
 ---> 
Step 4/7 : COPY other /
 ---> 9b0753ec4353
Step 5/7 : FROM scratch as prod
 ---> 
Step 6/7 : COPY --from=dev /dev /
 ---> Using cache
 ---> 64c24f1f1d8c
Step 7/7 : COPY prod /
 ---> 9fe8cc3d3ac1
Successfully built 9fe8cc3d3ac1

为什么 Docker 需要构建 other 层?

如何在没有 other 的情况下构建 prod?我必须使用另一个 Docker 文件吗?

docker build 有两个不同的后端。 “经典”后端的工作方式与您描述的完全相同:它 运行 遍历整个 Docker 文件,直到到达最后阶段,因此即使某个阶段未使用,它仍会被执行。较新的 BuildKit backend 可以进行一些依赖性分析并确定从未使用过的阶段并根据您的要求跳过它。

Docker 的最新版本使用 BuildKit 作为它们的默认后端。稍旧的版本有可用的 BuildKit,但它不是默认的。您可以通过 运行ning

启用它
export DOCKER_BUILDKIT=1

在您的 shell 环境中 运行 docker build

(最佳做法通常是在所有环境中 运行 相同的 Docker 图像,并对单独的组件使用单独的 Docker 文件。这避免了关于哪个阶段的任何问题正好得到 运行.)