关于 docker-dockerfile
面向需要构建应用容器镜像的开发者,提供编写和优化 Dockerfile 的参考。内容涵盖指令用法、按语言区分的多阶段构建模式、层缓存和生产环境加固;不负责执行镜像构建或编排。
主要功能
- 01常见 Dockerfile 指令及用法参考
- 02适用于 Go、Java、Node.js 和 Python 的多阶段构建模式
- 03层缓存与依赖优先复制的指导
- 04镜像精简、安全和生产加固实践
- 05常见 Dockerfile 问题的排查建议
适用场景
- 01为应用运行环境编写 Dockerfile
- 02优化依赖层和构建缓存
- 03检查 Dockerfile 的安全性与生产就绪情况
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ full-stack-skills/ docker-skills --skill docker-dockerfile安装后在 Claude Code 中输入/docker-dockerfile确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
evaluation-report.htmlagents/openai.yamlexamples/01-multi-stage-go.md02-multi-stage-java.md03-spring-boot-layers.md04-multi-stage-node.md05-multi-stage-python.mdreferences/01-dockerfile-instructions.md02-layer-caching.md03-dockerignore.md04-image-size-optimization.md05-multi-stage-patterns.md详细介绍
Dockerfile——完整编写指南
用于编写生产级 Dockerfile 的专家参考。涵盖每条指令、每种模式和每项优化。
适用场景
用户提及以下内容时,始终使用此技能:
- “Dockerfile”“怎么写 Dockerfile”“Dockerfile 指令”
- “多阶段构建”“multi-stage build”
- “Dockerfile 层优化”“layer caching”
- “Dockerfile 模板”,语言专属模板:“Go Dockerfile”“Java Dockerfile”“Python Dockerfile”
- 需要创建或优化 Dockerfile
- “Dockerfile 最佳实践”
指令参考
FROM——基础镜像
FROM <image>[:<tag>] [AS <stage-name>]
FROM alpine:3.20 # Tag
FROM alpine:3.20@sha256:abc123...def456 # Digest (production!)
FROM golang:1.22-alpine AS builder # Named stage
FROM scratch # Empty image (for static binaries)
| 最佳实践 | 原因 |
|---|---|
| 生产环境固定摘要 | 标签可变;摘要不可变 |
| 使用 Alpine/slim 变体 | 减小攻击面和镜像体积 |
Go/Rust 使用 FROM scratch | 静态二进制文件不需要其他内容 |
RUN——执行命令
# ✅ Chain commands, clean in same layer
RUN apk add --no-cache curl && \
curl -fsSL https://example.com/script.sh -o /usr/local/bin/script && \
chmod +x /usr/local/bin/script
# ❌ Each RUN = new layer (bloat)
RUN apk add curl
RUN curl ... -o /usr/local/bin/script
RUN chmod +x /usr/local/bin/script
# Multi-line readability
RUN set -eux; \
apk add --no-cache \
curl \
ca-certificates \
tzdata; \
curl -fsSL ... | tar xz -C /usr/local
COPY——复制文件
COPY [--chown=<user>:<group>] <src>... <dest>
COPY . /app
COPY --chown=app:app ./binary /usr/local/bin/
COPY --from=builder /app/build /app # From another stage (multi-stage)
# ✅ Layer-friendly: copy deps first, then source
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# ❌ Source change invalidates dependency cache
COPY . .
RUN go mod download
ADD——复制并自动解压
# ADD auto-extracts tar archives
ADD archive.tar.gz /app/
# Prefer COPY unless you need tar extraction
COPY archive.tar.gz /app/
RUN tar xzf /app/archive.tar.gz -C /app
WORKDIR——设置工作目录
WORKDIR /app
# All subsequent RUN/COPY/CMD use /app as base
# Prefer over:
RUN cd /app && npm install # ❌ cd doesn't persist
ENV 和 ARG
# ARG: build-time only (not in final image)
ARG VERSION=1.0.0
FROM myapp:${VERSION}
# ENV: runtime (persists in image)
ENV NODE_ENV=production \
PORT=8080
# Combine: pass ARG to ENV
ARG APP_VERSION
ENV APP_VERSION=${APP_VERSION}
EXPOSE——声明端口
EXPOSE 8080
EXPOSE 8080/tcp # Protocol-specific
EXPOSE 8080/udp
# Note: EXPOSE does NOT publish ports. Use -p at runtime:
# docker run -p 8080:8080 myapp
CMD 与 ENTRYPOINT
# CMD: default command (overridable)
CMD ["nginx", "-g", "daemon off;"]
# docker run myimage echo hello → overrides CMD
# ENTRYPOINT: fixed entry (not overridable)
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]
# docker run myimage → runs: docker-entrypoint.sh nginx -g 'daemon off;'
# docker run myimage echo hello → runs: docker-entrypoint.sh echo hello
# Common pattern: script + default args
ENTRYPOINT ["/entrypoint.sh"]
CMD ["start"]
USER——切换到非 root 用户
# Create user and group
RUN addgroup --system app && adduser --system --ingroup app app
USER app
HEALTHCHECK
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget -qO- http://localhost:8080/health || exit 1
# Dockerfile without shell (scratch):
HEALTHCHECK --interval=30s CMD /app/healthcheck || exit 1
SHELL——更改默认 Shell
SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]
RUN echo "Now using bash with strict mode"
多阶段构建模式
模式 1:构建二进制文件 + scratch(Go/Rust)
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o server .
FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /app/server /server
USER 1000:1000
CMD ["/server"]
模式 2:构建 + 最小化运行时(Java)
FROM maven:3.9-eclipse-temurin-21 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests
FROM eclipse-temurin:21-jre-alpine
RUN addgroup --system app && adduser -S -G app app
COPY --from=builder /app/target/*.jar /app.jar
USER app
CMD ["java", "-jar", "/app.jar"]
模式 3:优化层结构(Spring Boot)
FROM eclipse-temurin:21-jre-alpine AS builder
WORKDIR /app
COPY build/libs/*.jar app.jar
RUN java -Djarmode=layertools -jar app.jar extract
FROM eclipse-temurin:21-jre-alpine
RUN addgroup --system app && adduser -S -G app app
# Layers in dependency order (max cache)
COPY --from=builder /app/dependencies/ ./
COPY --from=builder /app/spring-boot-loader/ ./
COPY --from=builder /app/snapshot-dependencies/ ./
COPY --from=builder /app/application/ ./
USER app
ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
模式 4:构建 + Alpine(Node.js)
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-alpine
RUN addgroup --system app && adduser -S -G app app
COPY --from=builder /app/dist /app
COPY --from=builder /app/node_modules /app/node_modules
USER app
CMD ["node", "/app/index.js"]
模式 5:Python 依赖 + Slim 运行时
FROM python:3.12 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
FROM python:3.12-slim
RUN groupadd --system app && useradd --system -g app app
COPY --from=builder /root/.local /home/app/.local
COPY . /app
ENV PATH=/home/app/.local/bin:$PATH
USER app
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0"]
层缓存策略
Docker builds layers from top to bottom.
A changed layer invalidates ALL layers below it.
✅ CORRECT order:
FROM base ← rarely changes
RUN install-system-deps ← changes with system updates
COPY go.mod go.sum ./ ← changes with dependency changes
RUN go mod download ← changes with dependency changes
COPY . . ← changes every commit ← MUST BE LAST
❌ WRONG order (slow builds):
COPY . . ← changes every commit
RUN go mod download ← reruns every time!
.dockerignore
# .dockerignore
.git
.gitignore
*.md
.env
.env.*
Dockerfile
docker-compose*.yml
node_modules
__pycache__
*.pyc
.git
.idea
.vscode
*.log
tmp/
工作流——推荐编写流程
步骤 1:确定语言和运行时:Go/Java/Node.js/Python → 选择基础镜像
步骤 2:选择构建模式:单阶段/多阶段/Spring Boot 分层 → 从 templates 选择模板
步骤 3:编写 Dockerfile:先 COPY 依赖 → RUN install → COPY 源码 → CMD
步骤 4:验证:docker build -t app . + docker run + 使用 dive 分析镜像大小
步骤 5:生产环境加固:使用非 root 用户 USER、HEALTHCHECK、固定摘要,并进行安全检查
注意事项——常见陷阱
- 在
RUN install前执行COPY . .:每次代码变更都会使依赖层缓存失效,导致从头开始重新构建。→ 解决方法:始终先复制依赖:COPY package.json . → RUN install → COPY src/ .。 - 默认使用 root 用户:始终在 Dockerfile 末尾使用
USER <non-root>。以 root 身份逃逸容器等同于获得主机 root 权限。→ 解决方法:添加RUN addgroup -S app && adduser -S app -G app+USER app;使用docker exec myapp whoami验证。 - 在 Dockerfile 中使用
ENV SECRET=value:该值会永久写入镜像层。→ 解决方法:使用 BuildKit--mount=type=secret,或在运行时注入docker run -e SECRET=$VAL。 - 没有
.dockerignore:整个项目都会发送到构建上下文中,导致构建缓慢并泄露敏感文件。→ 解决方法:创建.dockerignore,至少包含.git node_modules .env;使用docker build --no-cache . 2>&1 | head -1验证。 - 执行
RUN apt update && apt install后不清理:软件包列表会留在镜像层中。→ 解决方法:在命令末尾添加&& rm -rf /var/lib/apt/lists/*;对于 apk,使用--no-cache标志。 - 基础镜像过大:
ubuntu:22.04(77 MB)与alpine:3.20(7 MB)相比体积更大。→ 解决方法:优先使用 Alpine;如果需要 glibc,则使用debian:bookworm-slim;使用docker images检查体积。
边界——适用与不适用场景
| 分类 | 场景 | 说明 |
|---|---|---|
| ✅ 能做 | 编写生产级 Dockerfile | 14 条指令的完整参考 + 最佳实践 |
| ✅ 能做 | 多阶段构建(Go/Java/Node/Python) | 5 种语言专属模板 |
| ✅ 能做 | 层缓存优化 | 优先 COPY 依赖 + 合并 RUN + BuildKit cache mount |
| ✅ 能做 | 镜像瘦身 | 5 步路线图:多阶段→Alpine→distroless→清理→dive |
| ⚠️ 需条件 | 安装私有依赖 | 需配合 BuildKit --secret 或 SSH forwarding |
| ⚠️ 需条件 | 选择 CMD 与 ENTRYPOINT | 参见指令参考中的决策树(工具用 ENTRYPOINT,服务用 CMD) |
| ❌ 超范围 | 执行 docker build 命令 | 使用 docker-build |
| ❌ 超范围 | 多平台构建(arm64/amd64) | 使用 docker-buildx |
| ❌ 超范围 | 容器编排(多容器) | 使用 docker-compose |
不应使用此技能的场景
| ❌ 跳过 | ✅ 改用 |
|---|---|
构建镜像(docker build ...) | docker-build |
| 多平台构建 | docker-buildx |
| 编写 Compose 文件 | docker-compose |
| Docker 基础知识 | docker-basics |
| 运行容器 | docker-run |
安全性与稳定性
- 所有 Dockerfile 模板仅供学习参考。用于生产环境前,请先审查并加固。
- 切勿在 Dockerfile 中嵌入机密信息。请使用 BuildKit
--mount=type=secret或在运行时注入。 - 生产环境中始终使用
USER <non-root>。为该用户复制文件时,请使用COPY --chown。 - 为确保生产环境的可复现性,请固定基础镜像摘要。
📚 官方文档参考
🧭 Docker 技能之旅
📍 你当前所在位置:
docker-dockerfile— Dockerfile 编写
basics → dockerfile → build → buildx → run → compose → ...
→ 下一步:docker-build — 使用 docker build 构建镜像
评论
支持 Markdown