核心三点是换掉root、精简内容、锁死行为:以非root用户运行容器,选用Alpine或distroless等最小化可信基础镜像并移除shell,通过多阶段构建剔除构建工具和敏感信息,并在运行时启用--read-only、--cap-drop=ALL等约束。

直接用默认基础镜像上生产,等于把大门敞开再交出钥匙。安全加固不是加一堆花哨功能,而是从源头砍掉攻击路径——核心就三点:换掉 root、精简内容、锁死行为。
用非特权用户替代 root 运行
绝大多数基础镜像默认以 root 启动,一旦容器被突破,攻击者就能在容器内任意提权、写文件、挂载设备,甚至逃逸到宿主机。这不是假设,是已验证的常见攻击链。
- 在 Dockerfile 中显式添加 USER 指令,例如
USER 1001:1001; - 构建前确保基础镜像中已创建该用户(如
adduser -u 1001 -D appuser); - 运行时也建议强制指定用户:
docker run --user 1001:1001,避免 Dockerfile 被覆盖; - 检查镜像中是否存在
setuid/setgid文件(如find / -perm -4000 2>/dev/null),有则清理。
选用最小化且可信的基础镜像
镜像越臃肿,漏洞越多,攻击面越大。Ubuntu 或 CentOS 全量镜像自带大量非运行必需的工具和库,比如 curl、bash、apt,这些都可能被攻击者用于横向移动或下载恶意载荷。
- 优先选 distroless(如
gcr.io/distroless/python3)或 Alpine(如python:3.11-alpine); - 禁用交互式 shell:distroless 镜像默认无 shell,Alpine 可通过
RUN rm -f /bin/sh /bin/bash移除; - 只从官方或企业私有仓库拉取镜像,并启用镜像签名验证(如 Notary 或 Cosign);
- 固定基础镜像标签,避免使用
latest,防止隐性更新引入不兼容或新漏洞。
构建阶段就切断敏感信息与冗余组件
很多风险其实在构建时就埋下了:硬编码密钥、残留构建工具、未清理的缓存、多层叠加的中间文件……这些不会因为“最后删掉”就真正消失。
- 用 多阶段构建:编译阶段用完整环境(如
golang:1.22),运行阶段只 COPY 二进制文件到 distroless 镜像; - 构建密钥绝不进入最终镜像层——用
BUILDKIT的--secret参数或多阶段 COPY 隔离; - 每步 RUN 后立即清理临时文件(如
apt clean && rm -rf /var/lib/apt/lists/*); - 扫描构建产物:CI 流水线中集成
trivy image --severity CRITICAL,高危漏洞直接阻断发布。
运行时补充只读与权限约束
即使镜像本身干净,运行时配置不当仍会放大风险。只读文件系统、限制能力集、禁用特权模式,都是低成本高回报的硬性防护。
- 启动容器时加
--read-only,让根文件系统不可写,阻止运行时植入; - 用
--cap-drop=ALL去掉所有 Linux capabilities,再按需加回(如--cap-add=NET_BIND_SERVICE); - 绝对禁止
--privileged和--pid=host等高危参数; - 挂载卷时明确指定
:ro(只读)或:rw,nosuid,noexec,nodev,防止提权或执行恶意脚本。


















