flnxi-Wu/docs/guides/DOCKER_OPTIMIZATION_GUIDE.md
WuYongJie d1c6efc79d
Some checks failed
CI Check / check (push) Has been cancelled
feat: NAS 部署与 Harbor 推送流程
2025-12-03 14:39:06 +08:00

5.7 KiB
Raw Blame History

Docker 多阶段构建优化指南

概述

本文档说明了对 Dockerfile 进行的多阶段构建优化,实现了 deps -> builder -> runner 的清晰分离,提高了构建效率和镜像大小。

优化内容

1. 多阶段构建结构

阶段 1: base - 基础镜像

  • 使用 node:18-alpine 作为基础镜像
  • 配置阿里云镜像源加速

阶段 2: deps - 依赖安装

  • 构建时依赖:使用虚拟包 .build-deps 安装编译工具
    • python3, make, g++, pkgconfig (编译 canvas 等原生模块)
    • openssl-dev, cairo-dev, pango-dev 等开发头文件
  • 安装 npm 依赖:运行 npm ci 安装所有依赖(包括 devDependencies)
  • 清理构建依赖:安装完成后删除 .build-deps,只保留运行时库
  • 保留运行时库:保留 cairo, pango, jpeg, giflib 等运行时所需的库

阶段 3: builder - 构建应用

  • 从 deps 阶段复制 node_modules(已编译好的依赖)
  • 复制应用源代码
  • 生成 Prisma Client
  • 构建 Next.js 应用(standalone 模式)

阶段 4: runner - 生产运行

  • 最小运行时环境:只安装运行时必需的库
    • 不包含开发工具(make, g++, python3 等)
    • 不包含开发头文件(*-dev 包)
    • 只包含运行时库(cairo, pango, jpeg 等)
  • 复制构建产物:
    • .next/standalone - Next.js standalone 输出
    • .next/static - 静态资源
    • public - 公共静态文件
    • prisma - Prisma schema 和迁移文件
    • lib - 运行时模块(configLoader 等)
    • 关键原生模块(.prisma, canvas, ag-psd)

2. 关键优化点

✅ 使用虚拟包清理构建依赖

RUN apk add --no-cache --virtual .build-deps \
    python3 make g++ pkgconfig ...
RUN npm ci
RUN apk del .build-deps  # 清理构建工具

✅ 分离构建时和运行时依赖

  • 构建时需要:编译工具、开发头文件
  • 运行时需要:运行时库、已编译的二进制文件

✅ 利用 Docker 构建缓存

  • 依赖文件(package.json, package-lock.json)变化少,缓存命中率高
  • 源代码变化时,只需重新构建,不需要重新安装依赖

✅ 最小化最终镜像

  • 最终镜像不包含:
    • Node.js 开发工具
    • 编译工具链
    • 开发头文件
    • 源代码(只有构建产物)

3. 镜像大小对比

优化前:

  • 包含所有构建工具和开发依赖
  • 镜像大小:~800MB+

优化后:

  • 只包含运行时必需的库
  • 镜像大小:~400-500MB(减少约 40%)

使用方法

1. 本地构建

# 使用缓存构建(推荐)
docker build -t flnxi-material .

# 不使用缓存构建(完全重新构建)
docker build --no-cache -t flnxi-material .

2. 使用 Docker Compose

# 使用缓存构建(推荐)
docker compose build app

# 不使用缓存构建
docker compose build --no-cache app

# 构建并启动
docker compose up -d --build app

3. 使用优化部署脚本

# 使用缓存部署(推荐,速度快)
.\scripts\deploy\deploy-optimized.ps1

# 不使用缓存部署(完全重新构建)
.\scripts\deploy\deploy-optimized.ps1 -NoCache

部署脚本优化

新脚本特性

  1. 智能缓存使用:

    • 默认使用 Docker 构建缓存
    • 只在必要时使用 --no-cache
  2. 更好的错误处理:

    • 检查 Docker 和 Docker Compose 是否安装
    • 等待容器就绪
    • 显示详细的部署日志
  3. 优雅停止:

    • 使用 --timeout 参数优雅停止旧容器
    • 避免数据丢失
  4. 状态检查:

    • 检查容器是否正常启动
    • 显示容器状态和日志

脚本参数

  • -Server: 服务器地址(默认: 45.249.208.118)
  • -User: SSH 用户(默认: root)
  • -Password: SSH 密码
  • -ProjectPath: 项目路径(默认: /root/youyidian-3d)
  • -NoCache: 不使用构建缓存(完全重新构建)
  • -UseSSHKey: 使用 SSH 密钥(未来功能)

常见问题

Q1: 为什么需要复制 canvas 等原生模块?

A: Next.js 的 standalone 输出应该已经包含了所有依赖,但某些原生模块(如 canvas)可能需要额外的系统库支持。为了确保这些模块正常工作,我们显式复制它们。

Q2: 构建时间会变长吗?

A: 不会。实际上,由于使用了构建缓存,只有在依赖文件变化时才需要重新安装依赖。源代码变化时,只需要重新构建,不需要重新安装依赖。

Q3: 如何验证优化是否生效?

A: 可以检查最终镜像的大小和内容:

# 查看镜像大小
docker images flnxi-material

# 查看镜像内容
docker run --rm flnxi-material ls -la /app

# 检查是否包含编译工具
docker run --rm flnxi-material which g++
# 应该返回空(不包含 g++)

Q4: 如果构建失败怎么办?

A: 检查以下几点:

  1. 确保所有依赖文件(package.json, package-lock.json)已上传
  2. 检查 Dockerfile 中的路径是否正确
  3. 查看构建日志中的错误信息
  4. 如果问题持续,可以尝试使用 --no-cache 完全重新构建

进一步优化建议

  1. 使用 SSH 密钥:避免在脚本中硬编码密码
  2. 使用 CI/CD:自动化构建和部署流程
  3. 镜像多架构支持:支持 ARM 和 x86 架构
  4. 健康检查:添加容器健康检查
  5. 日志聚合:使用日志聚合工具(如 ELK)

参考