LabHub
学习 学习路径 课程

构建镜像

用多阶段把体积削下来

在 LabHub 中继续学习

本实验在真正的 VM 中运行

这个环境不是 Pod,而是由 KubeVirt 启动的虚拟机。Linux 内核独立运行,systemd 真正管理服务,docker 也不是模拟工具,而是真正的 Docker 引擎。通过 docker run 启动的容器会成为实际进程,docker execdocker logs 也都能照常工作。

过去,这个实验在 Pod 中运行。由于该环境放弃了所有内核权限,启动容器的步骤无法进行,因此只能学习直接解开镜像归档的变通方法。现在不再需要绕路了。

有两点需要了解。

目标

只把构建器阶段生成的产物移入最终镜像,并通过体积数值确认如何用小得多的镜像交付相同产物。

为什么重要

镜像体积不是美观问题,而是部署速度和回滚速度的问题。每当节点扩容或进行回滚时,都要重新拉取相应大小的镜像。而缩小体积最有力的手段并非压缩或清理,而是“不应进入最终镜像的内容,从一开始就不要在那个阶段创建”。镜像层无法倒退,一旦违反这一原则,之后无论怎样删除都无法恢复原来的体积。

步骤

  1. 创建 /root/build3,并在 /root/build3/Dockerfile 中创建两个阶段。第一阶段使用 python:3.12-alpine,命名为 builder,并向 /out/app.txt 写入 built-in-builder。第二阶段使用 alpine:3.20。构建为 labhub/ms:v1
  2. 修改最终阶段,使其只将构建器中的 /out/app.txt 复制到 /app/app.txt,并构建为 labhub/ms:v2。运行并读取该文件时,必须得到 built-in-builder
  3. /root/build3/fat.Dockerfile 中编写一个以单阶段生成相同产物的版本(基础镜像为 python:3.12-alpine),并构建为 labhub/ms:fat
  4. 只构建第一阶段,生成 labhub/ms:builder 镜像。镜像中必须存在 /out/app.txt
  5. Dockerfile 的最终阶段添加一行,直接从 busybox:1.36 镜像将 /bin/busybox 复制到 /app/busybox,并构建为 labhub/ms:v3
  6. 运行 labhub/ms:v3,确认其中没有 python3。镜像体积必须小于 60MB。
  7. 创建 /root/build3/scratch.Dockerfile,在 FROM scratch 之上仅放入 busybox:1.36/bin/busybox,并以数组格式指定 ENTRYPOINT,使其原样输出作为参数传入的字符串。构建为 labhub/ms:scratch;传入 scratch-works 时,必须输出该字符串。
  8. /root/build3/size.md 中按实际值写入以下四行。
fat_mb=<labhub/ms:fat 크기(MB)>
slim_mb=<labhub/ms:v3 크기(MB)>
scratch_mb=<labhub/ms:scratch 크기(MB)>
reduction_pct=<(fat_mb - scratch_mb) / fat_mb * 100 의 정수부>

参考

创建两个阶段

创建 /root/build3,并在 /root/build3/Dockerfile 中创建两个阶段。第一阶段使用 python:3.12-alpine,命名为 builder,并向 /out/app.txt 写入 built-in-builder。第二阶段使用 alpine:3.20。构建为 labhub/ms:v1

写两次 FROM,并为前一个阶段命名。之后会在 COPY 中引用该名称。

只取出构建产物

修改最终阶段,使其只将构建器中的 /out/app.txt 复制到 /app/app.txt,并构建为 labhub/ms:v2。运行并读取该文件时,必须得到 built-in-builder

只选择并复制构建器阶段生成的文件。如果复制整个阶段,就失去了使用多阶段构建的意义。

与单阶段镜像比较体积

/root/build3/fat.Dockerfile 中编写一个以单阶段生成相同产物的版本(基础镜像为 python:3.12-alpine),并构建为 labhub/ms:fat

请与将相同产物直接留在较重基础镜像上的版本比较。体积应减少 30% 以上。

只构建中间阶段

只构建第一阶段,生成 labhub/ms:builder 镜像。镜像中必须存在 /out/app.txt

调试时,可以单独将构建器阶段生成为镜像。有一个选项可以在到达最终阶段前停止。

直接从其他镜像复制

Dockerfile 的最终阶段添加一行,直接从 busybox:1.36 镜像将 /bin/busybox 复制到 /app/busybox,并构建为 labhub/ms:v3

--from 不仅可以接收阶段名称,也可以直接指定镜像引用。

不保留构建工具

运行 labhub/ms:v3,确认其中没有 python3。镜像体积必须小于 60MB。

请实际运行,确认仅用于构建的运行时已从最终阶段消失。

放到空白基础镜像上

创建 /root/build3/scratch.Dockerfile,在 FROM scratch 之上仅放入 busybox:1.36/bin/busybox,并以数组格式指定 ENTRYPOINT,使其原样输出作为参数传入的字符串。构建为 labhub/ms:scratch;传入 scratch-works 时,必须输出该字符串。

scratch 中没有 Shell,因此 ENTRYPOINT 必须使用数组格式。还必须选择静态链接的二进制文件。

体积报告

/root/build3/size.md 中按实际值写入以下四行。

测量并填写三个镜像的实际体积,然后计算缩减率。1MB = 1048576 字节。