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

190 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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. 关键优化点
#### ✅ 使用虚拟包清理构建依赖
```dockerfile
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. 本地构建
```bash
# 使用缓存构建(推荐)
docker build -t flnxi-material .
# 不使用缓存构建(完全重新构建)
docker build --no-cache -t flnxi-material .
```
### 2. 使用 Docker Compose
```bash
# 使用缓存构建(推荐)
docker compose build app
# 不使用缓存构建
docker compose build --no-cache app
# 构建并启动
docker compose up -d --build app
```
### 3. 使用优化部署脚本
```powershell
# 使用缓存部署(推荐,速度快)
.\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: 可以检查最终镜像的大小和内容:
```bash
# 查看镜像大小
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)
## 参考
- [Docker 多阶段构建文档](https://docs.docker.com/build/building/multi-stage/)
- [Next.js Docker 部署指南](https://nextjs.org/docs/deployment#docker-image)
- [Alpine Linux 包管理](https://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management)