当前位置: 首页 > news >正文

第三部分-Dockerfile与镜像构建——13. Dockerfile 最佳实践

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:latest

3. 镜像体积优化

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 --only=production # 最后复制源代码(变化频繁) 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_TOKEN=xxx .

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_ENABLED=0 GOOS=linux go build -o main . # 阶段2:运行阶段 FROM alpine:latest RUN apk --no-cache add ca-certificates COPY --from=builder /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 --chown=nodejs: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/null

6.3 安全扫描

# 使用 Docker Scan 扫描镜像漏洞dockerscan myapp:latest# 使用 Trivytrivy image myapp:latest# 使用 Clairclair-scanner myapp:latest

7. 可维护性

7.1 使用 LABEL

# ✅ 好:添加元数据标签 LABEL maintainer="team@example.com" \ version="1.0.0" \ description="My application" \ build-date="${BUILD_DATE}" \ vcs-url="https://github.com/example/myapp"

7.2 使用 ARG 和 ENV

# ✅ 好:集中管理配置 ARG NODE_VERSION=14.17.0 ARG APP_HOME=/app FROM node:${NODE_VERSION}-alpine ENV NODE_ENV=production \ APP_PORT=8080 \ APP_HOME=/app WORKDIR ${APP_HOME}

7.3 添加健康检查

# ✅ 好:配置健康检查 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost:8080/health || exit 1 # 或使用 wget HEALTHCHECK --interval=30s \ CMD wget --quiet --tries=1 --spider http://localhost:8080/health || exit 1

8. 开发环境 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 --only=production COPY . . RUN npm run build # 运行阶段 FROM node:14-alpine RUN addgroup -g 1000 -S nodejs && \ adduser -S nodejs -u 1000 WORKDIR /app COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules COPY package.json ./ USER nodejs EXPOSE 3000 HEALTHCHECK --interval=30s CMD node healthcheck.js CMD ["node", "dist/server.js"]

9. 性能优化技巧

9.1 并行构建

# 使用 BuildKit 并行构建DOCKER_BUILDKIT=1dockerbuild.# 启用并行下载和构建dockerbuild--progress=plain --build-argBUILDKIT_INLINE_CACHE=1.

9.2 缓存挂载

# 使用 --mount=type=cache(BuildKit 特性) # syntax = docker/dockerfile:1.2 FROM node:14-alpine WORKDIR /app # 缓存 node_modules RUN --mount=type=cache,target=/app/node_modules \ --mount=type=cache,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 或构建参数

http://www.jsqmd.com/news/788787/

相关文章:

  • 百度网盘直链解析神器:3分钟突破限速实现满速下载 [特殊字符]
  • 从示波器波形看懂软启动:如何让电容电压匀速上升,电流保持2A限流11毫秒
  • 从空密码到安全加固:详解MySQL root@localhost初始安全风险与实战修复
  • 跨越EDA鸿沟:Allegro PCB高效迁移至PADS实战指南
  • DBeaver驱动管理进阶:手把手教你用PowerShell脚本批量管理本地驱动库,实现一键更新与备份
  • 27_AI短片工作流:从三视图到动态分镜,三步锁定电影级画面
  • FunClip终极指南:如何用AI智能剪辑视频,从新手到专家的完整教程
  • MediaCreationTool.bat终极指南:5分钟制作Windows安装介质的完整教程
  • 2026年屈新生红旗饭店八大碗口碑怎么样 - mypinpai
  • 【新手操作】零基础用 OpenClaw 快速开发 HTML5 企业静态网站方法(含安装包)
  • 【VSCode】告别Qt Creator:手把手配置VSCode调试QT项目全流程
  • 深入Linux USB驱动框架:从虚拟控制器dummy_hcd到USB/IP的vhci-hcd(附代码导读)
  • 超图像方法:用2D网络高效处理3D医学影像分割
  • Sentinel-2 L2A数据实战:从云端下载到Python处理全链路解析
  • JsBarcode:JavaScript条形码生成的完整解决方案
  • 2026年多少钱的聚氨酯涂料生产商排名 - mypinpai
  • 欧盟AI法案解读:高风险系统界定、生物识别监管与合规路径
  • ncmdumpGUI:简单三步将网易云音乐NCM文件转换为通用格式
  • 2026年摩尔线程数字IC面试试卷带答案
  • 全面掌握Windows Cleaner:高效解决C盘空间危机的深度应用指南
  • AD19中3D封装高度偏移设置,精准解决PCB叠层元件DRC干涉警告
  • Agency Orchestrator:基于DAG与多智能体编排的AI团队协作引擎
  • MAA助手终极指南:5分钟实现明日方舟智能自动化管理
  • 别再只读卡号了!用STM32+RC522,我实现了M1卡扇区数据读写与简单门禁模拟
  • 3分钟打造专属Windows桌面:TranslucentTB任务栏透明化终极指南
  • 如何一键完整备份你的QQ空间十年青春回忆?GetQzonehistory终极解决方案
  • Sunshine技术架构深度解析:构建高性能自托管游戏串流服务器
  • 别再跳过启动文件了!STM32F407移植FreeRTOS/RT-Thread前必须搞懂的3个关键点
  • AMD锐龙SDT调试工具终极指南:高效调节CPU参数与故障排查
  • 首次使用Taotoken Token Plan套餐在月度账单上体现的成本节省