Skip to content

Docker 安全

容器并非天然隔离的沙箱,错误配置可能带来严重风险。本文聚焦镜像与运行时层面的安全基线。

以非 root 用户运行

默认容器内进程以 root(uid 0)运行,一旦容器逃逸将威胁宿主机。Dockerfile 中显式切换用户:

dockerfile
# 创建非 root 用户
RUN addgroup -S app && adduser -S app -G app
USER app

# 或直接使用 UID
USER 1000

运行时强制(即使镜像未设置):

bash
docker run --user 1000:1000 myapp

注意:非 root 用户写某些目录(如 /var/run)会失败,需在 Dockerfile 中 chown 相应目录。

最小化基础镜像

基础镜像越大,攻击面越大。优先选择:

  • alpine:轻量,但使用 musl libc,部分二进制不兼容。
  • slim:官方精简版(如 python:3.12-slim)。
  • distroless:仅含运行时与 CA 证书,几乎无 shell,极难被植入后门。
  • scratch:完全空镜像,适合静态编译二进制(Go/Rust)。
dockerfile
FROM gcr.io/distroless/static-debian12
COPY server /server
USER nonroot:nonroot
ENTRYPOINT ["/server"]

只读文件系统与降权

bash
# 根文件系统只读,仅 tmpfs 可写
docker run --read-only --tmpfs /tmp myapp

# 禁止特权模式(默认即为 false,注意不要设 true)
docker run --privileged=false myapp

# 删除 Linux 能力(capabilities),仅保留必要项
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myapp

资源限制

防止单一容器耗尽宿主机资源:

bash
docker run -d \
  --cpus 2 \
  --memory 512m \
  --memory-swap 512m \
  --pids-limit 200 \
  myapp

Compose 中:

yaml
services:
  app:
    deploy:
      resources:
        limits:
          cpus: "2"
          memory: 512M

镜像漏洞扫描

构建后扫描镜像,发现已知 CVE:

bash
# Trivy(开源,推荐)
trivy image myapp:v1

# 仅扫描高危及以上
trivy image --severity HIGH,CRITICAL myapp:v1

# Docker Scout(官方)
docker scout cves myapp:v1

CI 中建议将扫描失败设为构建阻断条件(见 容器与 CI/CD 集成)。

其他加固项

  • 固定基础镜像 digestFROM node:20-alpine@sha256:xxxx,防止底层被悄然变更。
  • 不使用 --privileged,确需设备访问用 --device
  • 限制内核能力--cap-drop ALL + 按需 --cap-add
  • 启用用户命名空间重映射(userns-remap),降低 root 逃逸影响。
  • ** secrets 管理**:敏感配置用 Docker/Swarm secret 或外部密钥管理,勿写进镜像。
  • 更新 Docker 版本:及时修补 daemon 已知漏洞。

最佳实践清单

  1. 非 root 运行 + 只读根文件系统。
  2. 最小化基础镜像(distroless / scratch)。
  3. 每次构建跑漏洞扫描。
  4. 限制 CPU/内存/PID。
  5. 固定镜像 digest,定期更新基础镜像。
  6. 密钥不进镜像,使用 secret 机制。