- “FROM指令初始化一个新的构建阶段” - “可以给一个新的构建阶段命名”
这让我想知道:一个构建阶段到底是什么?
FROM alpine as stage1
RUN apk add your_tool
FROM alpine as stage2
RUN your_tool some args
由于第二阶段未安装your_tool
,因此您将收到错误。
从构建中输出哪个阶段?默认情况下是最后一个阶段,但您可以使用docker image build --target stage1 .
更改它,以构建具有名称stage1
的阶段,例如此示例。经典的docker build将从Dockerfile的顶部运行,直到完成目标阶段。Buildkit会构建依赖关系图并同时构建阶段,仅在需要时才构建,因此不要依赖于此排序来控制类似测试工作流程之类的东西在您的Dockerfile中(buildkit可以看到测试阶段中没有任何内容需要在您的发布阶段中使用,并跳过构建测试)。
多阶段的价值在于什么?通常,它用于将构建环境与运行时环境分开。它允许您在docker内执行整个构建。这有两个优点。
首先,您不需要外部Makefile和各种编译器和其他工具安装在主机上来编译二进制文件,然后使用COPY
行将其复制到映像中,任何人都可以使用docker构建您的映像。
其次,生成的映像不包括所有编译器或其他构建时间工具,这些工具在运行时不需要,从而导致映像更小且更安全。典型的示例是具有maven和完整JDK的Java应用程序进行构建,具有仅包含jar文件和JRE的运行时。
如果每个阶段都制作一个单独的映像,如何将jar文件从构建阶段传递到运行阶段?这来自COPY
命令的新选项--from
。一个过度简化的多阶段构建如下:
FROM maven as build
COPY src /app/src
WORKDIR /app/src
RUN mvn install
FROM openjdk:jre as release
COPY --from=build /app/src/target/app.jar /app
CMD java -jar /app/app.jar
COPY --from=build
,我们能够将在构建阶段生成的构件添加到发布阶段中,而不会包含第一阶段中的任何其他内容(例如JDK或Maven之类的编译工具层不会被添加到我们的第二阶段)。
FROM x as y
和 COPY --from=y /a /b
如何协同工作?FROM x as y
定义了一个镜像名称,在本次构建过程中持续有效,这里是 y
。在 Dockerfile 的后续任何位置,您都可以使用 y
代替镜像名称,并将其作为输入。因此,您可以这样说:FROM upstream as mybuilder
RUN apk add common_tools
FROM mybuilder as stage2
RUN some_tool arg2
FROM mybuilder as stage3
RUN some_tool arg3
FROM minimal_base as release
COPY --from=stage2 /bin2 /
COPY --from=stage3 /bin3 /
stage2
和stage3
都是FROM mybuilder
,这是第一阶段的输出。
COPY --from=y
允许您更改复制内容的上下文,使其成为另一个镜像而不是构建上下文。它不必是另一个阶段。因此,例如,您可以执行以下操作在映像中获取docker二进制文件:FROM alpine
COPY --from=docker:stable /usr/local/bin/docker /usr/local/bin/
更多关于此内容的文档可在以下链接找到:https://docs.docker.com/develop/develop-images/multistage-build/
docker
现在支持在docker build
执行期间使用多个阶段。Dockerfile
中定义具有不同图像的多个阶段,并使用多个FROM
定义:# Build stage
FROM microsoft/aspnetcore
# ..do a build with a dev image for creating ./app artifact
# Publish - use a hardened, production image
FROM alpine:latest
CMD ["./app"]
FROM node as builder
RUN npm install ...
# whatever you need to build your files
FROM nginx as production
COPY --from=builder /final.js /var/www/html
这个 Dockerfile 的最终结果是一个基于 nginx
的小型镜像,只包含最终的 .js 文件,不包含所有不必要的东西,如 node.js 和 npm 依赖项。
builder
是第一阶段,production
是第二阶段。在这种情况下,第一阶段将在过程结束时被丢弃,但您也可以选择使用 docker build --target=builder
构建特定的阶段。一个新的 FROM
引入了一个新的、独立的阶段。它们本质上是独立的 Dockerfiles,但可以使用 COPY --from
共享数据。