关于 writing-dockerfiles
这项技能为应用开发者提供生产级 Dockerfile 的编写与优化指导,涵盖多阶段构建、安全加固、缓存和语言专属模式。
主要功能
- 01多阶段构建指导
- 02按语言选择基础镜像
- 03BuildKit 缓存与密钥挂载
- 04安全加固与非 root 用户
- 05Dockerfile 校验与镜像分析
适用场景
- 01为应用编写生产级 Dockerfile
- 02用多阶段构建缩小镜像
- 03避免凭据留在镜像层中
- 04应用语言专属容器模式
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ancoleman/ ai-design-components --skill writing-dockerfiles安装后在 Claude Code 中输入/writing-dockerfiles确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
outputs.yamlexamples/go-microservice.Dockerfilenodejs-express.Dockerfilepython-fastapi.Dockerfilerust-actix.Dockerfilereferences/base-image-selection.mdbuildkit-features.mdgo-dockerfiles.mdjava-dockerfiles.mdnodejs-dockerfiles.mdpython-dockerfiles.mdrust-dockerfiles.mdsecurity-hardening.mdscripts/analyze_image_size.shvalidate_dockerfile.py详细介绍
编写 Dockerfile
编写适用于生产环境的 Dockerfile,采用多阶段构建、安全加固和针对语言的优化。
何时使用此技能
在以下情况调用:
- “为 [Python/Node.js/Go/Rust] 应用编写 Dockerfile”
- “优化此 Dockerfile 以减小镜像体积”
- “为……使用多阶段构建”
- “通过非 root 用户加固 Dockerfile 安全性”
- “使用 distroless 基础镜像”
- “添加 BuildKit 缓存挂载”
- “防止机密泄漏到 Docker 层中”
快速决策框架
回答以下三个问题,以确定采用哪种方案:
1. 使用哪种语言?
- Python → 参见
references/python-dockerfiles.md - Node.js → 参见
references/nodejs-dockerfiles.md - Go → 参见
references/go-dockerfiles.md - Rust → 参见
references/rust-dockerfiles.md - Java → 参见
references/java-dockerfiles.md
2. 安全性是否至关重要?
- 是 → 使用 distroless 运行时镜像(参见
references/security-hardening.md) - 否 → 使用 slim/alpine 基础镜像
3. 镜像体积是否至关重要?
- 是(<50MB)→ 多阶段构建 + distroless + 静态链接
- 否(<500MB)→ 多阶段构建 + slim 基础镜像
核心概念
多阶段构建
将构建环境与运行时环境分离,以尽可能减小最终镜像体积。
模式:
# Stage 1: Build
FROM build-image AS builder
RUN compile application
# Stage 2: Runtime
FROM minimal-runtime-image
COPY --from=builder /app/binary /app/
CMD ["/app/binary"]
优势:
- 镜像体积缩小 80-95%(不包括构建工具)
- 提升安全性(生产环境中不包含编译器)
- 部署更快
- 更好地利用层缓存
基础镜像选择
决策矩阵:
| 语言 | 构建阶段 | 运行时阶段 | 最终体积 |
|---|---|---|---|
| Go(静态) | golang:1.22-alpine | gcr.io/distroless/static-debian12 | 10-30MB |
| Rust(静态) | rust:1.75-alpine | scratch | 5-15MB |
| Python | python:3.12-slim | python:3.12-slim | 200-400MB |
| Node.js | node:20-alpine | node:20-alpine | 150-300MB |
| Java | maven:3.9-eclipse-temurin-21 | eclipse-temurin:21-jre-alpine | 200-350MB |
Distroless 镜像(由 Google 维护):
gcr.io/distroless/static-debian12→ 静态二进制文件(2MB)gcr.io/distroless/base-debian12→ 使用 libc 的动态二进制文件(20MB)gcr.io/distroless/python3-debian12→ Python 运行时(60MB)gcr.io/distroless/nodejs20-debian12→ Node.js 运行时(150MB)
完整比较请参见 references/base-image-selection.md。
BuildKit 功能
启用 BuildKit,以使用高级缓存和安全功能:
export DOCKER_BUILDKIT=1
docker build .
# OR
docker buildx build .
主要功能:
--mount=type=cache→ 持久化包管理器缓存--mount=type=secret→ 注入机密,而不将其存储在各层中--mount=type=ssh→ 转发 SSH Agent,以访问私有仓库- 并行执行各阶段
- 改进层缓存
详细模式请参见 references/buildkit-features.md。
层优化
按变化频率从低到高排列 Dockerfile 指令:
# 1. Base image (rarely changes)
FROM python:3.12-slim
# 2. System packages (rarely changes)
RUN apt-get update && apt-get install -y build-essential
# 3. Dependencies manifest (changes occasionally)
COPY requirements.txt .
RUN pip install -r requirements.txt
# 4. Application code (changes frequently)
COPY . .
# 5. Runtime configuration (rarely changes)
CMD ["python", "app.py"]
BuildKit 缓存挂载:
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements.txt
缓存会在各次构建之间保留,从而避免重复下载。
安全加固
基本安全实践:
1. 非 root 用户
# Debian/Ubuntu
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
USER appuser
# Alpine
RUN adduser -D -u 1000 appuser && chown -R appuser:appuser /app
USER appuser
# Distroless (built-in)
USER nonroot:nonroot
2. 机密管理
# ❌ NEVER: Secret in layer history
RUN git clone https://${GITHUB_TOKEN}@github.com/private/repo.git
# ✅ ALWAYS: BuildKit secret mount
RUN --mount=type=secret,id=github_token \
TOKEN=$(cat /run/secrets/github_token) && \
git clone https://${TOKEN}@github.com/private/repo.git
使用以下命令构建:
docker buildx build --secret id=github_token,src=./token.txt .
3. 漏洞扫描
# Trivy (recommended)
trivy image myimage:latest
# Docker Scout
docker scout cves myimage:latest
4. 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
全面的安全加固模式请参见 references/security-hardening.md。
.dockerignore 配置
创建 .dockerignore,以排除不必要的文件:
# Version control
.git
.gitignore
# CI/CD
.github
.gitlab-ci.yml
# IDE
.vscode
.idea
# Testing
tests/
coverage/
**/*_test.go
**/*.test.js
# Build artifacts
node_modules/
dist/
build/
target/
__pycache__/
# Environment
.env
.env.local
*.log
这样可以缩小构建上下文,并防止机密泄漏。
特定语言的模式
Python 快速参考
三种方案:
- pip(简单) → 单阶段构建,使用 requirements.txt
- poetry(生产环境) → 多阶段构建,使用虚拟环境
- uv(最快) → 速度比 pip 快 10-100 倍
示例:Poetry 多阶段构建
FROM python:3.12-slim AS builder
RUN --mount=type=cache,target=/root/.cache/pip \
pip install poetry==1.7.1
COPY pyproject.toml poetry.lock ./
RUN poetry export -f requirements.txt --output requirements.txt
RUN --mount=type=cache,target=/root/.cache/pip \
python -m venv /opt/venv && \
/opt/venv/bin/pip install -r requirements.txt
FROM python:3.12-slim
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
USER 1000:1000
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0"]
完整模式请参见 references/python-dockerfiles.md 和 examples/python-fastapi.Dockerfile。
Node.js 快速参考
关键模式:
- 使用
npm ci(而不是npm install)进行可复现构建 - 多阶段:构建阶段 → 仅保留生产依赖
- 内置
node用户(UID 1000) - Alpine 变体体积最小(约 180MB,而非 1GB)
示例:Express 多阶段构建
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
npm ci
COPY . .
RUN npm run build
RUN npm prune --omit=dev
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
USER node
CMD ["node", "dist/index.js"]
请参阅 references/nodejs-dockerfiles.md,了解 npm/pnpm/yarn 模式,以及 examples/nodejs-express.Dockerfile。
Go 快速参考
尽可能精简的镜像:
- 静态二进制文件(CGO_ENABLED=0)+ distroless = 10-30MB
- 使用
-ldflags="-s -w"剥离符号 - 同时缓存
/go/pkg/mod和构建缓存
示例:Distroless 静态镜像
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod \
go mod download
COPY . .
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o main .
FROM gcr.io/distroless/static-debian12
COPY --from=builder /app/main /app/main
USER nonroot:nonroot
ENTRYPOINT ["/app/main"]
请参阅 references/go-dockerfiles.md 和 examples/go-microservice.Dockerfile。
Rust 快速参考
超小型静态二进制文件:
- musl 静态链接 → 无 libc 依赖
- scratch 基础镜像(额外开销为 0 字节)
- 最终镜像:5-15MB
示例:Scratch 基础镜像
FROM rust:1.75-alpine AS builder
RUN apk add --no-cache musl-dev
WORKDIR /app
# Cache dependencies
COPY Cargo.toml Cargo.lock ./
RUN --mount=type=cache,target=/usr/local/cargo/registry \
mkdir src && echo "fn main() {}" > src/main.rs && \
cargo build --release --target x86_64-unknown-linux-musl && \
rm -rf src
# Build application
COPY src ./src
RUN --mount=type=cache,target=/usr/local/cargo/registry \
cargo build --release --target x86_64-unknown-linux-musl
FROM scratch
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/app /app
USER 1000:1000
ENTRYPOINT ["/app"]
请参阅 references/rust-dockerfiles.md 和 examples/rust-actix.Dockerfile。
包管理器缓存挂载
BuildKit 缓存挂载位置:
| 语言 | 包管理器 | 缓存挂载目标 |
|---|---|---|
| Python | pip | --mount=type=cache,target=/root/.cache/pip |
| Python | poetry | --mount=type=cache,target=/root/.cache/pypoetry |
| Python | uv | --mount=type=cache,target=/root/.cache/uv |
| Node.js | npm | --mount=type=cache,target=/root/.npm |
| Node.js | pnpm | --mount=type=cache,target=/root/.local/share/pnpm/store |
| Go | go mod | --mount=type=cache,target=/go/pkg/mod |
| Rust | cargo | --mount=type=cache,target=/usr/local/cargo/registry |
持久化缓存可避免在不同构建中重复下载包。
验证与测试
验证 Dockerfile 质量:
# Lint Dockerfile
python scripts/validate_dockerfile.py Dockerfile
# Scan for vulnerabilities
trivy image myimage:latest
# Analyze image size
docker images myimage:latest
docker history myimage:latest
比较优化结果:
# Before optimization
docker build -t myapp:before .
# After optimization
docker build -t myapp:after .
# Compare
bash scripts/analyze_image_size.sh myapp:before myapp:after
请参阅 scripts/validate_dockerfile.py,了解自动化 Dockerfile 检查。
与相关技能集成
上游(提供输入):
testing-strategies→ 在容器化之前测试应用程序security-hardening→ 在 Docker 层之前加固应用程序安全性
下游(使用 Dockerfile):
building-ci-pipelines→ 在 CI 中构建并推送 Docker 镜像kubernetes-operations→ 将容器部署到 K8s 集群infrastructure-as-code→ 使用 Terraform/Pulumi 部署容器
并行(相关上下文):
secret-management→ 注入运行时密钥(K8s 密钥、密钥库)observability→ 收集容器日志和指标
常见模式快速参考
1. 静态二进制文件(Go/Rust)→ 最小镜像
- 构建:特定语言的构建器镜像
- 运行时:
gcr.io/distroless/static-debian12或scratch - 体积:5-30MB
2. 解释型语言(Python/Node.js)→ 针对生产环境优化
- 构建:安装依赖、构建产物
- 运行时:相同基础镜像,仅保留生产依赖
- 体积:150-400MB
3. JVM(Java)→ 优化运行时
- 构建:使用完整 JDK 的 Maven/Gradle
- 运行时:仅包含 JRE 的镜像(alpine 变体)
- 体积:200-350MB
4. 安全关键型场景 → 最大限度加固
- 基础镜像:Distroless 镜像
- 用户:非 root 用户(nonroot:nonroot)
- 密钥:BuildKit 密钥挂载
- 扫描:在 CI 中使用 Trivy/Docker Scout
5. 开发 → 快速迭代
- 基础镜像:完整语言镜像(而非 slim)
- 卷:挂载源代码
- 热重载:特定语言的工具
- 本技能不涵盖此内容(请参阅 Docker Compose 文档)
应避免的反模式
❌ 绝不:
- 使用
latest标签(会导致构建结果不可预测) - 在生产环境中以 root 身份运行
- 在 ENV 变量或镜像层中存储密钥
- 安装不必要的软件包
- 合并无关的 RUN 命令(会破坏缓存)
- 跳过 .dockerignore(导致构建上下文臃肿)
✅ 始终:
- 固定精确的镜像版本(使用
python:3.12.1-slim,而非python:3) - 创建并使用非 root 用户
- 使用 BuildKit 密钥挂载存储凭据
- 尽量减少镜像层和镜像体积
- 按照从最少变更到最频繁变更的顺序排列命令
- 创建 .dockerignore 文件
其他资源
基础镜像仓库:
- Google Distroless:
gcr.io/distroless/* - Docker Hub 官方镜像:
python:*、node:*、golang:* - Red Hat UBI:
registry.access.redhat.com/ubi9/*
漏洞扫描器:
- Trivy(推荐):
trivy image myimage:latest - Docker Scout:
docker scout cves myimage:latest - Grype:
grype myimage:latest
参考文档:
references/base-image-selection.md→ 完整的基础镜像对比references/buildkit-features.md→ 高级 BuildKit 模式references/security-hardening.md→ 全面的安全指南references/目录中的语言专属参考文档examples/目录中的可运行示例