选择合适的基础镜像

Debian/Ubuntu
CentOS/Fedora
busybox
alpine

动态链接库/静态链接库

处理构建工具-多阶段构建

要想大幅度减少镜像的体积,多阶段构建是必不可少的。多阶段构建的想法很简单:“我不想在最终的镜像中包含一堆 C 或 Go 编译器和整个编译工具链,我只要一个编译好的可执行文件!”

多阶段构建可以由多个 FROM 指令识别,每一个 FROM 语句表示一个新的构建阶段,阶段名称可以用 AS 参数指定,例如:

  1. FROM gcc AS mybuildstage
  2. COPY hello.c .
  3. RUN gcc -o hello hello.c
  4. FROM ubuntu
  5. COPY --from=mybuildstage hello .
  6. CMD ["./hello"]

注意COPY --from=imageName, 在复制文件时,源和目标如果是相对的目录或文件,则都是相对于各自的WORKDIR。

本例使用基础镜像 gcc 来编译程序 hello.c,然后启动一个新的构建阶段,它以 ubuntu 作为基础镜像,将可执行文件 hello 从上一阶段拷贝到最终的镜像中。最终的镜像大小是 64 MB,比之前的 1.1 GB 减少了 95%:

  1. ???? docker images minimage
  2. REPOSITORY TAG ... SIZE
  3. minimage hello-c.gcc ... 1.14GB
  4. minimage hello-c.gcc.ubuntu ... 64.2MB

还能不能继续优化?当然能。在继续优化之前,先提醒一下:

在声明构建阶段时,可以不必使用关键词 AS,最终阶段拷贝文件时可以直接使用序号表示之前的构建阶段(从零开始)。也就是说,下面两行是等效的:

  1. COPY --from=mybuildstage hello .
  2. COPY --from=0 hello .

如果 Dockerfile 内容不是很复杂,构建阶段也不是很多,可以直接使用序号表示构建阶段。一旦 Dockerfile 变复杂了,构建阶段增多了,最好还是通过关键词 AS 为每个阶段命名,这样也便于后期维护。

处理依赖-分层构建

可以通过 docker 镜像分层的原理,将安装依赖的过程放在一层里,然后代码放在最后 COPY 进去,因为一般情况下,都是代码频繁的变动,依赖的软件不会经常变动,这样可以利用 build 时的 cache,加速 build 的过程。