docker-best-practiceslisted
Install: claude install-skill Wade-DevCode/awesome-coding-skills-cn
# Docker 最佳实践
## 何时用
- 新写或修改任何 Dockerfile。
- 把现有应用容器化时做方案设计。
- 发现镜像体积异常大、构建反复拉依赖、容器以 root 身份运行时。
- 做镜像安全扫描前的自查。
## 核心规则
### 1. 多阶段构建 + 锁定基础镜像版本
**规则:** 用多阶段构建(multi-stage build)将编译工具与运行时分离;最终阶段只保留运行所需;基础镜像使用 `slim` 或 `alpine` 变体并固定具体版本标签,不用 `latest`。
**为什么:** AI 生成 Dockerfile 时惯用 `FROM node:latest` 并把构建工具一并打进最终镜像,导致:镜像体积从几十 MB 膨胀到数百 MB,`latest` 标签在不同时间拉取内容不同使构建不可重复,安全扫描面随之大幅增加。曾见过把 `gcc`、`make`、完整 Python 开发头文件留在生产镜像里的真实事故。
**怎么做:**
- `FROM node:20-alpine AS builder` 做编译,`FROM node:20-alpine AS runtime` 只拷产物。
- 用 `COPY --from=builder /app/dist ./dist` 跨阶段拷贝,其余一概不带。
- 在 CI 中定期用 `docker scout` 或 `trivy` 扫镜像,升版本时同步更新标签。
---
### 2. 善用层缓存:先装依赖再拷源码
**规则:** 把"依赖清单文件"(`package.json`、`requirements.txt`、`go.mod` 等)单独先 `COPY` 进去并执行安装,再 `COPY` 源码;源码修改不会使依赖层失效。
**为什么:** AI 最常见的写法是 `COPY . .` 然后 `RUN npm install`——每次改一行业务代码,整个依赖安装层失效,CI 上几分钟的 `npm install` 变成每次必跑。在依赖上百包的项目里这是显而易见的浪费,但 AI 很少主动意识到。
**怎么做:**
```dockerfile
# 正确顺序:依赖清单 → 安装 → 源码
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY src/ ./src/
```
- 每次只有 `package.json` 变化才重新跑 `npm ci`,改源码直接命中缓存。
- monorepo 场景先 `COPY` 根 `package.json` 与各 workspace 的 `package.json`,再统一安装。
---
### 3. 不以 root 运行;密钥不进镜像
**规则:** 用 `USER` 指令切换到无特权用户;通过 BuildKit secret 或运行时环境变量传入凭据,不用 `ENV`/`ARG` 把密钥固化进镜像层。
**为什么:** AI 生成的 Dockerfile 几乎从不加 `USER` 指令,容器进程默认以 root 运行,一旦容器被攻破即获宿主机高权限。同样,AI 会把 `ARG NPM_TOKEN=xxx` 写进 Dockerfile 并 `RUN npm install`,虽然 `ARG` 不出现在 `docker inspect` 环境变量里,但该层的文件系统快照仍可被 `docker history` 提取,密钥实质上已泄露。
**