docker-build-strategies
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDocker Build Strategies
Docker 构建策略
Overview
概述
This skill provides rules and patterns for writing and reviewing production-quality Dockerfiles. Apply it when the main task is image-build quality: multi-stage builds, cache behavior, non-root execution, build context hygiene, and runtime image size.
本技能提供编写和审查生产级 Dockerfile 的规则与模式。当主要任务是镜像构建质量时应用:多阶段构建、缓存行为、非 root 执行、构建上下文卫生和运行时镜像体积。
When to use this skill
何时使用本技能
Activate this skill when:
- Creating a new Dockerfile for any language or framework
- Optimizing an existing Dockerfile for size, speed, or security
- Reviewing a Dockerfile for best-practice compliance
- Adding a file to a project
.dockerignore
在以下情况下激活本技能:
- 为任何语言或框架创建新的 Dockerfile
- 优化现有 Dockerfile 的体积、速度或安全性
- 审查 Dockerfile 是否符合最佳实践
- 为项目添加 文件
.dockerignore
Do not use this skill when
不应使用本技能的情况
Do not use this skill when:
- The project has no Docker setup yet and the main need is a first-pass scaffold
- The main task is wiring services together in
compose.yaml - The main task is debugging Compose startup ordering, networking, or development overrides
在以下情况下不应使用本技能:
- 项目尚无 Docker 配置,主要需求是初步脚手架搭建
- 主要任务是在 中编排服务
compose.yaml - 主要任务是调试 Compose 启动顺序、网络或开发覆盖配置
Core guidance
核心指导
Multi-stage builds
多阶段构建
Use multi-stage builds when the project has a build step or when build-time dependencies differ from runtime. Separate build-time dependencies from the runtime image.
- Name every stage explicitly (,
FROM ... AS build).FROM ... AS runtime - Use the smallest appropriate base for the runtime stage: ,
distroless, oralpinevariants.slim - Copy only the final artifact into the runtime stage with .
COPY --from=build - Use when copying from a prior stage or adding static files — it improves cache reuse by making the COPY independent of previous layers.
COPY --link
See for language-specific patterns (Go, Node, Python, Java).
references/multi-stage-builds.md当项目有构建步骤,或构建时依赖与运行时依赖不同时,使用多阶段构建。将构建时依赖与运行时镜像分离。
- 显式命名每个阶段(、
FROM ... AS build)。FROM ... AS runtime - 为运行时阶段使用最小的合适基础镜像:、
distroless或alpine变体。slim - 使用 仅将最终产物复制到运行时阶段。
COPY --from=build - 从先前阶段复制或添加静态文件时使用 ——它使 COPY 独立于之前的层,从而提高缓存复用。
COPY --link
参见 了解各语言(Go、Node、Python、Java)的特定模式。
references/multi-stage-builds.mdLayer caching
层缓存
Order Dockerfile instructions from least-frequently-changed to most-frequently-changed.
- Place dependency manifests (,
package.json,go.mod) and install steps before copying application source code.requirements.txt - Use BuildKit cache mounts for package manager caches:
- Go:
RUN --mount=type=cache,target=/go/pkg/mod go build ... - Node:
RUN --mount=type=cache,target=/root/.npm npm ci - Python:
RUN --mount=type=cache,target=/root/.cache/pip pip install ...
- Go:
- Pin base image tags to a specific version or digest — never use in production.
latest - Combine related commands with
RUNto reduce layer count, but keep logically distinct steps separate for cache granularity.&&
See for detailed cache invalidation rules and cache mount patterns.
references/layer-caching.md按从“最不常变更”到“最常变更”的顺序排列 Dockerfile 指令。
- 在复制应用源码之前,放置依赖清单(、
package.json、go.mod)和安装步骤。requirements.txt - 使用 BuildKit 缓存挂载来管理包管理器缓存:
- Go:
RUN --mount=type=cache,target=/go/pkg/mod go build ... - Node:
RUN --mount=type=cache,target=/root/.npm npm ci - Python:
RUN --mount=type=cache,target=/root/.cache/pip pip install ...
- Go:
- 将基础镜像标签固定到特定版本或摘要——生产环境中绝不使用 。
latest - 使用 合并相关的
&&命令以减少层数,但将逻辑上独立的步骤分开以保留缓存粒度。RUN
参见 了解详细的缓存失效规则和缓存挂载模式。
references/layer-caching.mdBuild secrets and SSH access
构建密钥与 SSH 访问
Never bake credentials into the image. Use BuildKit secrets and SSH mounts so credentials are available only during the specific step that needs them, and never persist in any layer or output.
RUNdocker history- Do NOT pass credentials through or
ARG. Both end up in the image layers and are inspectable viaENV.docker history - Do NOT credential files into the build context:
COPY,.npmrc,.pypirc,.netrc, Mavenpip.conf,settings.xml, cloud credentials (.env,~/.aws/credentials, service-account JSON files,~/.config/gcloud/), secret-manager tokens (~/.azure/), package-registry tokens (~/.vault-token), TLS keys (~/.cargo/credentials.toml,*.pem),*.p12, SSH keys (kubeconfig,id_rsa,id_dsa,id_ed25519). Even when the final stage does not copy them forward, they live in intermediate layers and the build cache.id_ecdsa - Do NOT echo, write, or expand the secret value inside a command in a way that persists it to a layer or emits it to build logs. Access the secret file (e.g.,
RUN, or directly via the mount/run/secrets/<id>) — nevertarget=, never substitute it into a shell argument that will be logged withecho "$(cat /run/secrets/X)".--progress=plain - Use for package manager registry credentials:
RUN --mount=type=secretThe secret is available only inside thatdockerfileRUN \ npm ci --omit=dev, never written to a layer. UseRUNwhen the build will always need the credential (e.g., all packages come from a private registry, so missing the secret should fail the build immediately); userequired=trueonly when the secret is optional (the build can succeed with public packages alone).required=false - Use for fetching private Git repositories or modules. The build container has no
RUN --mount=type=sshby default — populate it inside the sameknown_hosts:RUNDo NOT usedockerfileRUN \ mkdir -p -m 0700 /root/.ssh && \ ssh-keyscan github.com >> /root/.ssh/known_hosts && \ git clone git@github.com:org/private-repo.gitas a shortcut — it disables host-key verification entirely.StrictHostKeyChecking=nopins the known fingerprint at build time.ssh-keyscan - Invoke buildx with the secret and SSH sources:
Alternatively, pass the key file directly without an agent:bash
# Ensure an SSH agent is running with the key loaded (or use --ssh default=<key-file>): eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_ed25519 docker buildx build \ --secret id=npmrc,src=$HOME/.npmrc \ --ssh default \ ..--ssh default=$HOME/.ssh/id_ed25519 - exclusions of
.dockerignoreand credential files are defense in depth, not the primary mechanism — keep them, but do not rely on them as your only protection..env
See for per-language patterns (npm, pip, Maven, Go ).
references/multi-stage-builds.mdGOPRIVATE切勿将凭据固化到镜像中。使用 BuildKit secrets 和 SSH 挂载,使凭据仅在需要它的特定 步骤期间可用,并且绝不会持久化到任何层或 输出中。
RUNdocker history- 不要通过 或
ARG传递凭据。两者都会写入镜像层,并可通过ENV检查。docker history - 不要将凭据文件 到构建上下文中:
COPY、.npmrc、.pypirc、.netrc、Mavenpip.conf、settings.xml、云凭据(.env、~/.aws/credentials、服务账号 JSON 文件、~/.config/gcloud/)、secret-manager 令牌(~/.azure/)、软件包仓库令牌(~/.vault-token)、TLS 密钥(~/.cargo/credentials.toml、*.pem)、*.p12、SSH 密钥(kubeconfig、id_rsa、id_dsa、id_ed25519)。即使最终阶段没有向前复制它们,它们仍会存在于中间层和构建缓存中。id_ecdsa - 不要在 命令中以会持久化到层或输出到构建日志的方式 echo、写入或展开密钥值。要访问密钥文件(例如
RUN,或直接通过挂载/run/secrets/<id>)——绝不target=,绝不将其替换到会被echo "$(cat /run/secrets/X)"记录的 shell 参数中。--progress=plain - 使用 处理包管理器仓库凭据:
RUN --mount=type=secret该 secret 仅在该dockerfileRUN \ npm ci --omit=dev内可用,绝不会写入层。当构建始终需要该凭据时使用RUN(例如所有包都来自私有仓库,缺少 secret 应立即失败);仅在 secret 可选时使用required=true(仅使用公共包也可成功构建)。required=false - 使用 获取私有 Git 仓库或模块。构建容器默认没有
RUN --mount=type=ssh——请在同一known_hosts中填充:RUN不要将dockerfileRUN \ mkdir -p -m 0700 /root/.ssh && \ ssh-keyscan github.com >> /root/.ssh/known_hosts && \ git clone git@github.com:org/private-repo.git作为捷径——它会完全禁用主机密钥验证。StrictHostKeyChecking=no会在构建时固定已知指纹。ssh-keyscan - 使用 secret 和 SSH 源调用 buildx:
或者,无需 agent 直接传入密钥文件:bash
# Ensure an SSH agent is running with the key loaded (or use --ssh default=<key-file>): eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_ed25519 docker buildx build \ --secret id=npmrc,src=$HOME/.npmrc \ --ssh default \ .。--ssh default=$HOME/.ssh/id_ed25519 - 对
.dockerignore和凭据文件的排除是纵深防御,而非主要机制——保留它们,但不要将其作为唯一保护。.env
参见 了解各语言(npm、pip、Maven、Go )的特定模式。
references/multi-stage-builds.mdGOPRIVATE.dockerignore
.dockerignore
Always generate a alongside the Dockerfile. Exclude:
.dockerignore- ,
.git/,.github/,.vscode/.idea/ - ,
node_modules/,__pycache__/,.venv/(when rebuilt in the build stage)vendor/ - ,
*.md,LICENSEdocs/ - Build outputs, test artifacts, and IDE configs
- files and any secrets
.env
See for a comprehensive template.
assets/dockerignore-example始终在 Dockerfile 旁边生成 。排除:
.dockerignore- 、
.git/、.github/、.vscode/.idea/ - 、
node_modules/、__pycache__/、.venv/(在构建阶段会重新构建时)vendor/ - 、
*.md、LICENSEdocs/ - 构建输出、测试产物和 IDE 配置
- 文件和任何密钥
.env
参见 获取完整的模板。
assets/dockerignore-exampleNon-root user
非 root 用户
Always configure the final image to run as a non-root user.
- Create a dedicated user and group in the runtime stage:
dockerfile
RUN addgroup --system --gid 1001 appgroup && \ adduser --system --uid 1001 --ingroup appgroup appuser - Set ownership on application files:
COPY --from=build --chown=appuser:appgroup /app /app - When combining with
--chown, always use the numeric UID:GID you assigned (e.g.,COPY --linkif you used--chown=1001:1001above), not named users.--uid 1001 --gid 1001creates an independent layer where named users from prior--linkinstructions are not available.RUN - Place the instruction after all file operations and before
USER appuser/ENTRYPOINT.CMD - On distroless images, use the built-in nonroot user: .
USER nonroot:nonroot
始终将最终镜像配置为以非 root 用户运行。
- 在运行时阶段创建专用用户和组:
dockerfile
RUN addgroup --system --gid 1001 appgroup && \ adduser --system --uid 1001 --ingroup appgroup appuser - 设置应用文件的所有权:
COPY --from=build --chown=appuser:appgroup /app /app - 将 与
--chown结合使用时,始终使用你指定的数字 UID:GID(例如,如果你上面使用了COPY --link,则使用--uid 1001 --gid 1001),而不是命名用户。--chown=1001:1001会创建独立层,先前--link指令中的命名用户在该层不可用。RUN - 在所有文件操作之后、/
ENTRYPOINT之前放置CMD指令。USER appuser - 在 distroless 镜像上,使用内置的 nonroot 用户:。
USER nonroot:nonroot
Image size optimization
镜像体积优化
- Prefer (Go static binaries), distroless, or Alpine-based images for the runtime stage.
FROM scratch - Remove package manager caches in the same layer that installs packages:
RUNapt-get install -y ... && rm -rf /var/lib/apt/lists/* - Do not install documentation, man pages, or debug tools in the runtime image.
- Use aggressively to minimize the build context.
.dockerignore
- 运行时阶段优先选择 (Go 静态二进制)、distroless 或 Alpine 基础镜像。
FROM scratch - 在与安装包相同的 层中删除包管理器缓存:
RUNapt-get install -y ... && rm -rf /var/lib/apt/lists/* - 不要在运行时镜像中安装文档、man 手册或调试工具。
- 积极使用 来最小化构建上下文。
.dockerignore
General rules
通用规则
- Always include a directive as the first line to enable BuildKit features.
# syntax=docker/dockerfile:1 - Set before any
WORKDIRorCOPYinstructions — never rely on the defaultRUN./ - Prefer with exec form (
ENTRYPOINT) over shell form.["binary"] - Add to document the listening port.
EXPOSE - Add metadata labels:
LABEL org.opencontainers.image.source=...
- 始终在第一行包含 指令以启用 BuildKit 特性。
# syntax=docker/dockerfile:1 - 在任何 或
COPY指令之前设置RUN——绝不要依赖默认的WORKDIR。/ - 优先使用 exec 形式的 (
ENTRYPOINT)而非 shell 形式。["binary"] - 添加 以记录监听端口。
EXPOSE - 添加元数据标签:
LABEL org.opencontainers.image.source=...
Related skills
相关技能
- For first-time Docker project scaffolding and deciding which files to create, use .
docker-project-foundations - For service dependencies, health checks, overrides, networks, and volume patterns, use .
docker-compose-patterns - For destructive Docker CLI commands (,
docker system prune, image/network/builder pruning) and a cross-product index of destructive-command guardrails, usedocker rm -f.docker-destructive-guardrails
- 首次 Docker 项目脚手架搭建和决定创建哪些文件时,使用 。
docker-project-foundations - 服务依赖、健康检查、覆盖配置、网络和卷模式,使用 。
docker-compose-patterns - 破坏性 Docker CLI 命令(、
docker system prune、镜像/网络/构建器清理)以及跨产品破坏性命令防护索引,使用docker rm -f。docker-destructive-guardrails
References
参考
- — Language-specific multi-stage patterns for Go, Node.js, Python, and Java
references/multi-stage-builds.md - — Deep dive on layer ordering, cache invalidation, and BuildKit cache mounts
references/layer-caching.md
- — Go、Node.js、Python 和 Java 的语言特定多阶段模式
references/multi-stage-builds.md - — 层排序、缓存失效和 BuildKit 缓存挂载的深入探讨
references/layer-caching.md
Assets
资源
- — Multi-stage Go build with distroless runtime and non-root user
assets/Dockerfile.go - — Multi-stage Node.js build with proper layer caching and non-root user
assets/Dockerfile.nodejs - — Python build with virtual env, layer ordering, and non-root user
assets/Dockerfile.python - — Comprehensive
assets/dockerignore-exampletemplate.dockerignore
- — 使用 distroless 运行时和非 root 用户的多阶段 Go 构建
assets/Dockerfile.go - — 具有正确层缓存和非 root 用户的多阶段 Node.js 构建
assets/Dockerfile.nodejs - — 使用虚拟环境、层排序和非 root 用户的 Python 构建
assets/Dockerfile.python - — 全面的
assets/dockerignore-example模板.dockerignore
Scripts
脚本
- — Builds the image, reports size and configured user.
scripts/verify-build.shExit status isbashbash scripts/verify-build.sh [--help] [IMAGE_NAME]when all Docker commands succeed or help is requested, the failing Docker command's non-zero status when verification fails, and0for invalid arguments.2
- — 构建镜像,报告体积和已配置的用户。
scripts/verify-build.sh当所有 Docker 命令成功或请求帮助时退出状态为bashbash scripts/verify-build.sh [--help] [IMAGE_NAME];当验证失败时,退出状态为失败 Docker 命令的非零状态;参数无效时为0。2
Checks
检查
- — Detailed verification runbook for manual review.
checks/verification.md
- — 用于手动审查的详细验证运行手册。
checks/verification.md