distroless 是什么
distroless 是一类极简运行镜像:里面只有应用本身和它需要的运行时依赖,没有包管理器、没有 shell,也没有常见的排查命令。这样做的直接收益是攻击面小(没有工具可用)与体积小(少装一层发行版)。代价是运维方式要变:不能 docker exec 进去看文件、敲命令,排查要靠日志、指标与专门的调试变体。
基本信息
| 镜像来源 | 官方发布的 gcr.io/distroless/* 系列(static、base、cc、java、python 等) |
|---|---|
| 非 root 变体 | 标签加 -nonroot 后缀,内置非 root 用户 |
| 调试变体 | 标签加 :debug,包含 busybox 等工具,仅用于排查 |
| Linux 内核依赖 | libc 类应用选 cc/base 变体,静态编译程序选 static |
| 时区与证书 | 默认已含受信任根证书;时区数据在部分变体中需要自行补充 |
| 适用平台 | Linux 容器(amd64 与 arm64 均有提供) |
典型使用场景
- Go、Rust 等可静态编译的服务:产物直接放进 static 变体
- Java 服务:选用 java 变体,避免自带整份基础发行版
- Python 服务:选用 python 变体,应用与其依赖在上游阶段装好
- 安全基线要求镜像内无 shell 与包管理器时
- 需要压缩镜像体积、减少扫描告警条目时
多阶段构建示例
多阶段构建示例
# 构建阶段:正常环境,工具齐全
FROM golang:1.23 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /out/app .
# 运行阶段:只有应用本身与最小依赖,并以非 root 运行
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /out/app /app
EXPOSE 8080
ENTRYPOINT ["/app"]排查与核对
排查与核对
# 用调试变体临时替换运行镜像,获得 shell 与常用工具
docker run --rm -it --entrypoint sh gcr.io/distroless/base-debian12:debug
# 确认运行用户与镜像配置
docker image inspect -f '{{.Config.User}} {{.Config.Entrypoint}}' app/web:1.0
# 无法 exec 进容器时,从外部观察:日志、指标、宿主机上的进程信息
docker logs --tail 100 app-web-1
# 体积对比:与切换前的镜像放在一起看
docker images --format 'table {{.Repository}}\t{{.Tag}}\t{{.Size}}' | grep -E 'app/web|golang'变体选择的要点
| 变体 | 适用对象 | 注意 |
|---|---|---|
| static | 静态编译的二进制 | 没有 libc,动态链接程序无法运行 |
| base | 需要 libc 的最小运行环境 | 不含包管理器 |
| cc | 需要 gcc 运行库的应用 | 按上游说明选择对应版本 |
| java | Java 服务 | 注意基础镜像的发行版匹配 |
| python | Python 服务 | 依赖需在上游阶段装好 |
| -nonroot 后缀 | 要求非 root 运行 | 写入目录需提前授权 |
没有 shell 意味着启动命令必须用 exec 形式(JSON 数组),任何依赖 shell 解释的启动脚本都无法执行,这是切换 distroless 时最常见的改造点。
健康检查如果依赖容器内命令(如 curl)会失败:应改为由外部探针请求应用端口,或使用编排平台自带的应用层探测方式。