bash
FROM ubuntu:24.04 AS ubuntu
RUN rm -rf /etc/localtime
RUN rm -f /usr/lib/apt/methods/mirror
RUN usermod -s /usr/sbin/nologin sync
RUN usermod -s /usr/sbin/nologin ubuntu
RUN apt remove -y --allow-remove-essential --auto-remove login
FROM scratch
LABEL "org.opencontainers.image.ref.name"="ubuntu"
LABEL "org.opencontainers.image.version"="24.04"
ENV PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
CMD ["/bin/bash"]
COPY --from=ubuntu / /
这个 Dockerfile 中两个FROM
指令的关系是多阶段构建中的 "基础阶段" 与 "最终阶段",通过 "阶段复用" 实现镜像精简和定制化,具体关系和作用如下:
1. 两个 FROM
的角色与关系
阶段 | FROM 指令 |
角色定位 | 与另一阶段的关系 |
---|---|---|---|
第一阶段 | FROM ubuntu:24.04 AS ubuntu |
基础构建阶段 (命名为ubuntu ) |
基于官方ubuntu:24.04 镜像进行预处理,为最终阶段提供 "净化后的基础文件系统" |
第二阶段 | FROM scratch |
最终镜像阶段 | 以空镜像(scratch )为起点,仅复制第一阶段处理后的文件系统,构建极小化最终镜像 |
2. 核心交互: COPY --from=ubuntu / /
两个阶段通过COPY --from=ubuntu / /
指令建立连接:
-
第一阶段(
ubuntu
)对官方ubuntu:24.04
进行修改(如删除/etc/localtime
、修改用户shell
、移除login
工具等),生成一个 "预处理后的 Ubuntu 文件系统"。 -
第二阶段(
scratch
)是完全空白的镜像,通过COPY
指令将第一阶段的整个根目录(/
)复制到当前阶段,相当于 "继承" 了第一阶段的文件系统,但不包含第一阶段的构建历史和冗余层。
3. 这样设计的目的
(1)精简最终镜像体积
官方ubuntu:24.04
镜像包含大量冗余文件(如login
工具、不必要的配置文件),第一阶段通过rm
和apt remove
清理这些文件,再复制到scratch
阶段,避免最终镜像携带无用内容。
(2)定制基础环境
第一阶段的修改(如修改用户shell
为nologin
、删除/etc/localtime
)会被保留到最终镜像中,实现对基础系统的定制化,而无需在最终阶段重复执行这些操作。
(3)隔离构建依赖
多阶段构建可以将 "构建工具" 和 "运行时环境" 分离。例如,若第一阶段需要安装编译工具(如gcc
),完成编译后,仅将产物复制到最终阶段,避免最终镜像包含编译工具。(本例中未体现编译过程,但核心逻辑一致)
4. 与单阶段构建的区别
如果用单阶段构建(仅FROM ubuntu:24.04
),rm
和apt remove
的操作会产生新的镜像层,但原文件仍可能残留在底层镜像中(Docker 镜像的 "写时复制" 特性)。而通过scratch
阶段复制,能彻底丢弃底层冗余,实现真正的精简。
总结
两个FROM
指令通过 "多阶段构建" 形成 "预处理→复制→再加工" 的流水线:
-
第一阶段(
ubuntu
)负责 "净化和定制基础系统"; -
第二阶段(
scratch
)负责 "继承净化后的系统,并继续安装应用依赖",最终产出一个精简、定制化的镜像。 这种设计是 Docker 最佳实践之一,尤其适合需要极小化镜像和定制基础环境的场景。这种设计是 Docker 最佳实践之一,尤其适合需要极小化镜像和定制基础环境的场景。