docker · 2024-03-31 0

docker 多阶段构建镜像

多阶段构建是一个新特性,需要 Docker 17.05 或更高版本的守护进程和客户端。对于那些努力优化 Dockerfiles 并使其易于阅读和维护的人来说,多阶段构建非常有用。

多阶段构建

多阶段构建是 Docker 17.05 的新增功能,它可以在一个 Dockerfile 中使用多个 FROM 语句,以创建多个 Stages(阶段)。每个阶段间独立(来源请求),可以通过 COPY --from 来获取其它阶段的文件

docker build

语法:

-f, --file string                   Name of the Dockerfile (default: "PATH/Dockerfile")
-t, --tag stringArray               Name and optionally a tag (format: "name:tag")
    --target string                 Set the target build stage to build

1. 只有最后一个 stage 才会被纳入 image 中

在下方 Dockerfile 中,我们创建了两个阶段。第一个阶段创建 s1.txt,第二个阶段创建 s2.txt,且第二个阶段会被加入最终 Image,其它不会。

# Stage 1
FROM alpine:3.8
WORKDIR /app
RUN echo "Hello, stage 1" > /app/s1.txt

# Stage 2
FROM alpine:3.8
WORKDIR /app
RUN echo "Hello, stage 2" > /app/s2.txt

结果:

zxm@zxm-pc:~/docker-test$ ls
Dockerfile_1
zxm@zxm-pc:~/docker-test$ docker build -f  Dockerfile_1 -t demo:1.0 .
zxm@zxm-pc:~/docker-test$ docker run --rm --name demo_1 demo:1.0 ls /app
s2.txt

2. 阶段间复制文件

使用 COPY --from 指令,可复制前面阶段的文件,也可复制指定镜像的文件。
COPY --from=0 行只将前一阶段的构建工件复制到这个新阶段;FROM 指令的第一个整数从 0 开始,0代表第一阶段。

# Stage 1
FROM alpine:3.8
WORKDIR /app
RUN echo "Hello, stage 1" > /app/s1.txt

# Stage 2
FROM alpine:3.8
WORKDIR /app
COPY --from=0 /app/s1.txt /app
COPY --from=nginx:1.25-alpine /etc/nginx/nginx.conf /app
RUN echo "Hello, stage 2" > /app/s2.txt

结果:

zxm@zxm-pc:~/docker-test$ docker build -f Dockerfile_2 -t demo:2.0 .
zxm@zxm-pc:~/docker-test$ docker run --rm --name demo_2 demo:2.0 ls /app
nginx.conf
s1.txt
s2.txt

3. 阶段命名

使用在 FROM 后加上 as,进行阶段命名。这样就可以 COPY --from 指定阶段名

# Stage 1
FROM alpine:3.8 as build1
WORKDIR /app
RUN echo "Hello, stage 1" > /app/s1.txt

# Stage 2
FROM alpine:3.8 as build2
WORKDIR /app
COPY --from=build1 /app/s1.txt /app
RUN echo "Hello, stage 2" > /app/s2.txt

结果:

zxm@zxm-pc:~/docker-test$ docker build -f Dockerfile_3 -t demo:3.0 .
zxm@zxm-pc:~/docker-test$ docker run --rm --name demo_3 demo:3.0 ls /app
s1.txt
s2.txt

4. 仅构建其中的部分阶段

结果:

# Stage 1
FROM alpine:3.8 as build1
WORKDIR /app
RUN echo "Hello, stage 1" > /app/s1.txt

# Stage 2
FROM alpine:3.8 as build2
WORKDIR /app
COPY --from=build1 /app/s1.txt /app
RUN echo "Hello, stage 2" > /app/s2.txt
zxm@zxm-pc:~/docker-test$ docker build -f Dockerfile_4 --target build1 -t demo:4.0 .
zxm@zxm-pc:~/docker-test$ docker run --rm --name demo_4 demo:4.0 ls /app
s1.txt