Dockerfile 技巧——镜像的多阶段构建
这一节来聊聊多阶段构建,以及为什么要使用它。
C语言例子
假如有一个C的程序,我们想用Docker去做编译,然后执行可执行文件。
#include <stdio.h>void main(int argc, char *argv[]){printf("hello %s\n", argv[argc - 1]);}
本地测试(如果你本地有C环境)
$ gcc --static -o hello hello.c$ lshello hello.c$ ./hello dockerhello docker$ ./hello worldhello world$ ./hello friendshello friends$
构建一个Docker镜像,因为要有C的环境,所以我们选择gcc这个image
FROM gcc:9.4COPY hello.c /src/hello.cWORKDIR /srcRUN gcc --static -o hello hello.cENTRYPOINT [ "/src/hello" ]CMD []
build和测试
$ docker build -t hello .Sending build context to Docker daemon 5.12kBStep 1/6 : FROM gcc:9.4---> be1d0d9ce039Step 2/6 : COPY hello.c /src/hello.c---> Using cache---> 70a624e3749bStep 3/6 : WORKDIR /src---> Using cache---> 24e248c6b27cStep 4/6 : RUN gcc --static -o hello hello.c---> Using cache---> db8ae7b42affStep 5/6 : ENTRYPOINT [ "/src/hello" ]---> Using cache---> 7f307354ee45Step 6/6 : CMD []---> Using cache---> 7cfa0cbe4e2aSuccessfully built 7cfa0cbe4e2aSuccessfully tagged hello:latest$ docker image lsREPOSITORY TAG IMAGE ID CREATED SIZEhello latest 7cfa0cbe4e2a 2 hours ago 1.14GBgcc 9.4 be1d0d9ce039 9 days ago 1.14GB$ docker run --rm -it hello dockerhello docker$ docker run --rm -it hello worldhello world$ docker run --rm -it hello friendshello friends$
可以看到镜像非常的大,1.14GB
实际上当我们把hello.c编译完以后,并不需要这样一个大的GCC环境,一个小的alpine镜像就可以了。
这时候我们就可以使用多阶段构建了。
FROM gcc:9.4 AS builderCOPY hello.c /src/hello.cWORKDIR /srcRUN gcc --static -o hello hello.cFROM alpine:3.13.5COPY --from=builder /src/hello /src/helloENTRYPOINT [ "/src/hello" ]CMD []
Note
上面的Dockerfile中第一阶段用于构建,第二阶段用于执行。第一阶段通过AS来取别名,在第二阶段的COPY中就可以使用--from=builder来引用第一阶段编译出来的hello文件
测试
$ docker build -t hello-apline -f Dockerfile-new .Sending build context to Docker daemon 5.12kBStep 1/8 : FROM gcc:9.4 AS builder---> be1d0d9ce039Step 2/8 : COPY hello.c /src/hello.c---> Using cache---> 70a624e3749bStep 3/8 : WORKDIR /src---> Using cache---> 24e248c6b27cStep 4/8 : RUN gcc --static -o hello hello.c---> Using cache---> db8ae7b42affStep 5/8 : FROM alpine:3.13.5---> 6dbb9cc54074Step 6/8 : COPY --from=builder /src/hello /src/hello---> Using cache---> 18c2bce629fbStep 7/8 : ENTRYPOINT [ "/src/hello" ]---> Using cache---> 8dfb9d9d6010Step 8/8 : CMD []---> Using cache---> 446baf852214Successfully built 446baf852214Successfully tagged hello-apline:latest$ docker image lsREPOSITORY TAG IMAGE ID CREATED SIZEhello-alpine latest 446baf852214 2 hours ago 6.55MBhello latest 7cfa0cbe4e2a 2 hours ago 1.14GBdemo latest 079bae887a47 2 hours ago 125MBgcc 9.4 be1d0d9ce039 9 days ago 1.14GB$ docker run --rm -it hello-alpine dockerhello docker$ docker run --rm -it hello-alpine worldhello world$ docker run --rm -it hello-alpine friendshello friends$
可以看到这个镜像非常小,只有6.55MB
