scratch是docker最精简基础镜像,大小约0b,无shell、libc、包管理器等任何组件;仅适用于静态编译的二进制(如cgo_enabled=0的go程序),可最小化攻击面、加速启动并杜绝继承漏洞。

Scratch 空镜像(scratch)是 Docker 官方提供的最精简基础镜像——它完全为空,不包含任何操作系统文件、shell、包管理器或标准库。用它构建容器底座,能实现真正“零冗余”的运行环境,特别适合静态编译的二进制程序(如 Go、Rust 生成的单文件可执行体)。但它的“极致纯净”也意味着:没有 /bin/sh,不能 apt install,甚至 echo 都无法直接运行。
为什么选 scratch 而不是 alpine?
alpine 镜像约 5 MB,自带 busybox、musl libc 和包管理;scratch 镜像大小为 0 B(实际拉取后仅几百字节元数据),彻底剥离所有运行时依赖。这意味着:
- 攻击面最小:无 shell、无用户、无动态链接器,连
execve以外的基础系统调用都极少暴露 - 启动最快:无需解压文件系统层,容器进程即为 PID 1,毫秒级启动
- 镜像最可信:不继承任何上游镜像的漏洞或配置漂移,完全由你控制二进制内容
适用场景与硬性前提
scratch 只接受静态链接的可执行文件。常见验证方式:
- Go 编译时加
-ldflags '-extldflags "-static"'或设CGO_ENABLED=0 - Rust 使用
target=x86_64-unknown-linux-musl并启用static=true - C/C++ 用
gcc -static编译,再用file your_binary确认输出含statically linked - 运行
ldd your_binary应提示not a dynamic executable
典型 Dockerfile 写法
以 Go Web 服务为例,采用多阶段构建,确保最终镜像只含二进制:
FROM golang:1.22-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o /app/server . FROM scratch COPY --from=builder /app/server /server EXPOSE 8080 CMD ["/server"]
注意:CMD 必须用数组格式(exec 形式),不可写成 CMD /server(shell 形式会尝试调用 /bin/sh,而 scratch 中不存在)。
调试与验证技巧
因 scratch 容器无法 exec 进入,调试需前置设计:
- 构建阶段加入健康检查:在 builder 阶段运行
./server && echo "build ok" - 启动时加简单日志:二进制内打印监听地址、PID、启动时间等关键信息到 stdout
- 用
docker run --rm -it <image> strace -c true</image>会失败(无 strace),但可确认是否报no such file or directory(通常是动态链接未清除) - 检查镜像内容:
docker export $(docker create <image>) | tar -t | head -n 10</image>,应只看到/server一个文件
scratch 不是万能底座,而是特定场景下的终极减法。它把控制权完全交还给开发者——你交付的不是“一个带环境的程序”,而是“一段可直接由内核调度的机器指令”。只要你的程序满足静态链接前提,它就是目前 Docker 生态中最干净、最可控、最接近裸金属效率的运行底座。











