Skip to content
60.Docker»50.Dockerfile»LV090-空镜像.md

LV090-空镜像

会不会有这样一个疑问,似乎每个镜像都会基于一个基础镜像,那么最开始的镜像是什么?

一、scratch 简介

1. 什么是 scratch?

scratch 的 docker hub 仓库是:scratch - Official Image | Docker Hub

可以先看一下 docker 的文档中 Base images | Docker Docs 这一部分,中文文档是 基础镜像 | Docker 文档,这里说:

如果您需要完全控制镜像的内容,您可以根据选择的 Linux 发行版创建自己的基础镜像,或使用特殊的 FROM scratch 基础镜像

dockerfile
FROM scratch

scratch 镜像通常用于创建仅包含应用程序所需内容的最小镜像。请参阅 使用 scratch 创建最小基础镜像

scratch 是 Docker 提供的一个特殊“空镜像”,它是一个完全空白的镜像,不包含任何文件系统、shell、包管理器或其他任何内容。它的大小为 0 字节,是一切镜像的起点。其核心特点如下:

  • 空文件系统scratch 是一个完全空白的镜像,不包含任何操作系统、软件包或文件系统。

  • 无基础依赖:没有 Shell(如 /bin/sh)、包管理器(如 apt/apk)或动态链接库(如 glibc)。

  • 最小体积:基于 scratch 的镜像仅包含用户显式添加的文件,是构建极简镜像的理想选择。

  • 内置虚拟镜像scratch 是 Docker 内置的,无需从仓库拉取。

2. 使用 scratch 创建最小基础镜像

保留的最小 scratch 镜像可作为构建容器的起点。使用 scratch 镜像向构建过程发出信号,表明您希望 Dockerfile 中的下一个命令成为镜像中的第一个文件系统层。

scratch 出现在 Docker 的 Docker Hub 上的仓库,但不能拉取、运行或使用名称 scratch 标记任何镜像。相反,我们可以在我们的 Dockerfile 中引用它。例如,要使用 scratch 创建最小容器

dockerfile
# syntax=docker/dockerfile:1
FROM scratch
ADD hello /
CMD ["/hello"]

假设名为 hello 的可执行二进制文件存在于 构建上下文 的根目录中。我们可以使用以下 docker build 命令构建此 Docker 镜像

shell
docker build --tag hello .

要运行新的镜像,请使用 docker run 命令

shell
docker run --rm hello

只要 hello 二进制文件 没有任何运行时依赖项,此示例镜像才能成功执行。计算机程序往往依赖于运行时环境中存在的某些其他程序或资源。例如

  • 编程语言运行时
  • 动态链接的 C 库
  • CA 证书

在构建基础镜像或任何镜像时,这是一个重要的方面。这就是为什么使用 FROM scratch 创建基础镜像对于除小型简单程序以外的任何其他程序都可能很困难的原因。另一方面,将仅包含镜像中所需的内容也很重要,以减小镜像大小和攻击面。

3. 使用 tar 创建完整镜像

通常情况下,首先使用运行我们想要打包为基础镜像的发行版的可运行机器,但这对于某些工具(如 Debian 的 Debootstrap)来说并非必需,也可以用它来构建 Ubuntu 镜像。

例如,要创建一个 Ubuntu 基础镜像:

shell
$ sudo debootstrap focal focal > /dev/null
$ sudo tar -C focal -c . | docker import - focal

sha256:81ec9a55a92a5618161f68ae691d092bf14d700129093158297b3d01593f4ee3

$ docker run focal cat /etc/lsb-release

DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04 LTS"

更多关于创建基础镜像的示例脚本可在 Moby GitHub 仓库 中找到。

二、构建 Ubuntu 镜像实例

1. 编写 dockerfile

dockerfile
# 第一阶段:下载和解压阶段
FROM alpine:latest AS builder

# 安装必要工具
RUN apk add --no-cache wget

# 下载 Ubuntu base rootfs
RUN wget -O /ubuntu-base.tar.gz \
    https://cdimage.ubuntu.com/ubuntu-base/releases/20.04/release/ubuntu-base-20.04.5-base-amd64.tar.gz

# 创建临时目录并解压
RUN mkdir /rootfs && \
    tar -xzf /ubuntu-base.tar.gz -C /rootfs

# 第二阶段:构建最终镜像
FROM scratch

# 从构建阶段复制已解压的文件系统
COPY --from=builder /rootfs/ /

# 设置环境变量
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# 设置工作目录
WORKDIR /root

# 默认命令
CMD ["/bin/bash"]

2. 构建镜像

shell
cd /workspace/tutorial-samples/05-Dockerfile/scratch_sample

# 构建镜像(直接从远端下载)
docker build -t custom-ubuntu-scratch .

3. 运行容器并查看版本

shell
# 运行容器
docker run --rm -it custom-ubuntu-scratch

# 在容器中测试
cat /etc/os-release
ls -la /

参考资料:

关于 docker 的 scratch 镜像与 helloworld - 番茄炒蛋不放糖 - 博客园

go - 创建尽可能小的 Docker 容器 - yexiaoxiaobai - SegmentFault 思否

scratch - Official Image | Docker Hub

Docker 的 scratch 镜像及其使用 1. 什么是 scratch 镜像? scratch 是 - 掘金

莫道桑榆晚 为霞尚满天.