1. 什么是 ****scratch ****镜像?
scratch 是 Docker 提供的一个特殊“空镜像”,其核心特点如下:
- 空文件系统:
scratch是一个完全空白的镜像,不包含任何操作系统、软件包或文件系统。 - 无基础依赖:没有 Shell(如
/bin/sh)、包管理器(如apt/apk)或动态链接库(如glibc)。 - 最小体积:基于
scratch的镜像仅包含用户显式添加的文件,是构建极简镜像的理想选择。 - 内置虚拟镜像:
scratch是 Docker 内置的,无需从仓库拉取。
2. ****scratch ****镜像的典型用途
- 静态编译的二进制程序:如 Go、Rust 等语言编译的静态可执行文件,无需依赖系统库。
- 极致轻量化:适合需要最小化镜像体积的场景(如微服务、嵌入式设备)。
- 安全敏感环境:减少攻击面,避免因系统组件漏洞导致的风险。
3. 如何使用 ****scratch ****镜像?
3.1 准备工作:静态编译程序
scratch 镜像无法直接运行动态链接的程序,因此需确保程序是静态编译的(不依赖外部库)。
示例:Go 程序静态编译
// main.go
package main
import "fmt"
func main() {
fmt.Println("Hello from scratch!")
}
编译命令:
# 静态编译(生成独立二进制文件)
GOOS=linux GOARCH=amd64 go build -o hello -ldflags="-s -w" main.go
-ldflags="-s -w":移除调试信息,进一步减小体积。- 输出文件
hello是一个独立的二进制文件,可直接运行。
3.2 编写 Dockerfile
基于 scratch 的 Dockerfile 非常简单,仅需将二进制文件复制到镜像中。
示例 Dockerfile:
FROM scratch
COPY hello /hello
CMD ["/hello"]
FROM scratch:从空白镜像开始。COPY hello /hello:将本地编译的hello文件复制到镜像的根目录。CMD ["/hello"]:指定默认运行/hello。
3.3 构建和运行镜像
构建镜像:
docker build -t hello-scratch .
-t hello-scratch:为镜像命名。
运行容器:
docker run --rm hello-scratch
--rm:容器退出后自动删除。- 输出:
Hello from scratch!
验证镜像大小:
docker images hello-scratch
- 输出示例:
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-scratch latest 1a2b3c4d5e6f 10 seconds ago 1.2MB
- 镜像大小仅为
1.2MB(仅包含hello二进制文件)。
4. 注意事项
- 必须静态编译:
-
- 动态链接的程序(如 Python、Java)无法直接在
scratch中运行,需手动添加依赖库或选择其他基础镜像(如alpine)。
- 动态链接的程序(如 Python、Java)无法直接在
- 调试困难:
-
scratch镜像没有 Shell 或调试工具,建议先在本地开发环境测试程序,再迁移到scratch。
- 与 Alpine 的区别:
-
FROM scratch是完全空白的,而FROM alpine基于 Alpine Linux,已包含基本的 Shell 和包管理器(apk)。
5. 适用场景对比
| 场景 | 推荐基础镜像 | 原因 |
|---|---|---|
| 静态编译的 Go 程序 | FROM scratch | 极简体积,无依赖,适合微服务或嵌入式设备。 |
| 需要 Shell 的程序 | FROM alpine | Alpine 提供 sh和 apk,便于调试和安装依赖。 |
| 动态链接的程序 | FROM ubuntu/FROM debian | 需操作系统支持动态库,体积较大。 |
6. 总结
-
核心优势:
scratch镜像通过完全空白的环境,实现了镜像的极致轻量化和安全性。 -
关键步骤:
- 静态编译程序(如 Go)。
- 编写 Dockerfile 复制二进制文件。
- 构建并运行镜像。
-
适用语言:Go、Rust 等支持静态编译的语言。
通过合理使用 scratch 镜像,可以显著优化 Docker 镜像的体积和安全性,尤其适合云原生和微服务架构。