13. Dockerfile 最佳实践1. 最佳实践概述遵循 Dockerfile 最佳实践可以构建出更小、更安全、更高效的镜像提升构建速度减少部署时间和安全风险。┌─────────────────────────────────────────────────────────────┐ │ Dockerfile 最佳实践金字塔 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 顶部 │ │ ┌─────────────┐ │ │ │ 安全 │ ← 安全加固 │ │ ┌──┴─────────────┴──┐ │ │ │ 可维护 │ ← 可读性、可维护 │ │ ┌──┴───────────────────┴──┐ │ │ │ 性能优化 │ ← 层缓存、并行构建 │ │ ┌──┴─────────────────────────┴──┐ │ │ │ 镜像体积优化 │ ← 多阶段构建、清理│ │ ┌──┴───────────────────────────────┴──┐ │ │ │ 基础原则 │ ← 单个进程、稳定│ │ └─────────────────────────────────────┘ │ │ 底部 │ └─────────────────────────────────────────────────────────────┘2. 基础原则2.1 容器应该是短暂的# ✅ 好容器可以随时停止和销毁 # 应用状态应该存储在外部数据库、存储卷 # ❌ 不好容器内存储状态 # 不要将数据存储在容器可写层2.2 一个容器只运行一个进程# ✅ 好单一进程 FROM node:14-alpine CMD [node, app.js] # ❌ 不好多个进程 FROM ubuntu CMD [sh, -c, nginx node app.js] # 应使用 docker-compose 管理多个进程2.3 使用具体标签避免 latest# ✅ 好指定具体版本 FROM node:14.17.0-alpine FROM python:3.9.7-slim # ❌ 不好使用 latest FROM node:latest FROM python:latest3. 镜像体积优化3.1 选择合适的基础镜像# 镜像大小对比约 # ubuntu:20.04 → 72MB # debian:11-slim → 40MB # alpine:3.14 → 5.6MB # scratch → 0MB # ✅ 推荐Alpine Linux FROM alpine:3.14 # 安装软件包 RUN apk add --no-cache nginx # ✅ 使用 slim 版本 FROM python:3.9-slim FROM node:14-slim # ✅ 对于静态编译的应用使用 scratch FROM scratch COPY myapp /myapp CMD [/myapp]3.2 合并 RUN 命令# ❌ 不好多层 RUN apt-get update RUN apt-get install -y curl RUN apt-get install -y nginx RUN apt-get clean # ✅ 好合并为单层 RUN apt-get update \ apt-get install -y curl nginx \ apt-get clean \ rm -rf /var/lib/apt/lists/*3.3 清理缓存和临时文件# ✅ 好清理缓存 RUN apk add --no-cache nginx # ✅ 好删除临时文件 RUN apt-get update \ apt-get install -y build-essential \ make \ make install \ apt-get remove -y build-essential \ apt-get autoremove -y \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*4. 构建缓存优化4.1 层缓存原则# ✅ 好变化最少的指令放在前面 FROM node:14-alpine # 先复制依赖文件变化少 WORKDIR /app COPY package*.json ./ # 安装依赖只有 package.json 变化才重新安装 RUN npm ci --onlyproduction # 最后复制源代码变化频繁 COPY . . CMD [node, app.js]4.2 利用构建参数缓存# ✅ 好使用 ARG 控制缓存失效 FROM node:14-alpine ARG NPM_TOKEN ARG BUILD_DATE # npm token 变化不会影响前面层 COPY package.json ./ # RUN 变化 RUN if [ $NPM_TOKEN ! ]; then \ echo //registry.npmjs.org/:_authToken$NPM_TOKEN .npmrc; \ fi \ npm install \ rm -f .npmrc COPY . . # 构建时传入 # docker build --build-arg NPM_TOKENxxx .4.3 指定构建上下文# .dockerignore # 排除无关文件 node_modules .git *.log .DS_Store coverage dist .env # 减少上下文大小加速构建5. 多阶段构建# ✅ 好多阶段构建分离编译和运行环境 # 阶段1编译阶段 FROM golang:1.17-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED0 GOOSlinux go build -o main . # 阶段2运行阶段 FROM alpine:latest RUN apk --no-cache add ca-certificates COPY --frombuilder /app/main /app/main ENTRYPOINT [/app/main]6. 安全最佳实践6.1 使用非 root 用户# ✅ 好创建并切换到非 root 用户 FROM node:14-alpine # 创建应用用户 RUN addgroup -g 1000 -S nodejs \ adduser -S nodejs -u 1000 # 设置目录权限 COPY --chownnodejs:nodejs . /app WORKDIR /app # 切换到非 root 用户 USER nodejs CMD [node, app.js]6.2 安全配置# ❌ 不好使用 root 用户 USER root # ✅ 好指定安全的用户 USER nodejs # ✅ 好只读文件系统配合 RUN chmod -R 755 /app \ chown -R nodejs:nodejs /app # ✅ 好删除不必要的 SUID/SGID RUN find / -type f \( -perm /6000 -o -perm /2000 \) -exec chmod 000 {} \; 2/dev/null6.3 安全扫描# 使用 Docker Scan 扫描镜像漏洞dockerscan myapp:latest# 使用 Trivytrivy image myapp:latest# 使用 Clairclair-scanner myapp:latest7. 可维护性7.1 使用 LABEL# ✅ 好添加元数据标签 LABEL maintainerteamexample.com \ version1.0.0 \ descriptionMy application \ build-date${BUILD_DATE} \ vcs-urlhttps://github.com/example/myapp7.2 使用 ARG 和 ENV# ✅ 好集中管理配置 ARG NODE_VERSION14.17.0 ARG APP_HOME/app FROM node:${NODE_VERSION}-alpine ENV NODE_ENVproduction \ APP_PORT8080 \ APP_HOME/app WORKDIR ${APP_HOME}7.3 添加健康检查# ✅ 好配置健康检查 HEALTHCHECK --interval30s --timeout3s --start-period5s --retries3 \ CMD curl -f http://localhost:8080/health || exit 1 # 或使用 wget HEALTHCHECK --interval30s \ CMD wget --quiet --tries1 --spider http://localhost:8080/health || exit 18. 开发环境 vs 生产环境8.1 开发环境 Dockerfile# Dockerfile.dev FROM node:14-alpine WORKDIR /app # 安装所有依赖 COPY package*.json ./ RUN npm install # 热重载支持 COPY . . EXPOSE 3000 # 开发命令 CMD [npm, run, dev]8.2 生产环境 Dockerfile# Dockerfile.prod # 构建阶段 FROM node:14-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci --onlyproduction COPY . . RUN npm run build # 运行阶段 FROM node:14-alpine RUN addgroup -g 1000 -S nodejs \ adduser -S nodejs -u 1000 WORKDIR /app COPY --frombuilder --chownnodejs:nodejs /app/dist ./dist COPY --frombuilder --chownnodejs:nodejs /app/node_modules ./node_modules COPY package.json ./ USER nodejs EXPOSE 3000 HEALTHCHECK --interval30s CMD node healthcheck.js CMD [node, dist/server.js]9. 性能优化技巧9.1 并行构建# 使用 BuildKit 并行构建DOCKER_BUILDKIT1dockerbuild.# 启用并行下载和构建dockerbuild--progressplain --build-argBUILDKIT_INLINE_CACHE1.9.2 缓存挂载# 使用 --mounttypecacheBuildKit 特性 # syntax docker/dockerfile:1.2 FROM node:14-alpine WORKDIR /app # 缓存 node_modules RUN --mounttypecache,target/app/node_modules \ --mounttypecache,target/root/.npm \ npm install COPY . . CMD [node, app.js]10. 检查清单## Dockerfile 检查清单 - [ ] 使用具体版本标签避免 latest - [ ] 选择合适的轻量级基础镜像alpine/slim - [ ] 合并 RUN 命令减少层数 - [ ] 清理 apt/apk 缓存 - [ ] 删除临时文件 - [ ] 配置 .dockerignore - [ ] 使用多阶段构建 - [ ] 使用非 root 用户运行 - [ ] 添加健康检查 - [ ] 添加 LABEL 元数据 - [ ] 利用构建缓存顺序优化 - [ ] 固定依赖版本 - [ ] 扫描镜像漏洞 - [ ] 测试镜像 - [ ] 文档化构建参数11. 常见反模式反模式问题解决方案使用:latest标签不可复现的构建使用具体版本在容器中存储数据数据丢失风险使用 Volume在一层中安装所有包缓存失效分离依赖和代码使用 root 用户运行安全风险创建应用用户忽略缓存构建缓慢优化层顺序12. 小结短暂容器应用无状态单进程一个容器一个进程具体标签避免 latest镜像体积使用 alpine/slim多阶段构建构建缓存稳定指令在前经常变动的指令在后安全加固非 root 用户健康检查可维护性LABEL、ARG、ENV、注释开发/生产分离不同 Dockerfile 或构建参数