7.3 KiB
7.3 KiB
部署流程优化方案
当前流程分析
当前部署步骤(总耗时约 5-10 分钟)
- npm run check (可选,~30秒) - 类型检查和 lint
- docker build (~3-5分钟) - 构建镜像
- docker save (~30秒-1分钟) - 打包镜像为 tar
- scp/rsync 上传 (~1-2分钟) - 上传 tar 文件(~120MB)
- 服务器 docker load (~30秒-1分钟) - 加载镜像
- docker compose up (~30秒) - 启动容器
- 数据库备份和迁移 (~10-30秒)
- 健康检查 (~10-20秒)
瓶颈分析
- 最大瓶颈:Docker 构建(3-5分钟)
- 次要瓶颈:文件上传(1-2分钟,取决于网络)
- 可优化点:某些步骤可以并行或跳过
优化方案
1. 启用 BuildKit 缓存(推荐 ⭐⭐⭐)
优化效果:构建时间从 3-5 分钟减少到 1-3 分钟(如果依赖未变化)
实施方法:
在部署脚本开头添加:
# 启用 BuildKit
$env:DOCKER_BUILDKIT = "1"
$env:COMPOSE_DOCKER_CLI_BUILD = "1"
# 构建时使用缓存挂载
docker build --progress=plain \
--build-arg BUILDKIT_INLINE_CACHE=1 \
-t $fullImage \
-f $Dockerfile \
$buildArgs \
$Context
修改部署脚本:
# 在 local-build-and-upload.ps1 的构建部分添加
if (-not $env:DOCKER_BUILDKIT) {
$env:DOCKER_BUILDKIT = "1"
Write-Host "已启用 BuildKit 缓存" -ForegroundColor Green
}
2. 使用 Docker 层缓存(已部分实现,可优化)
当前状态:Dockerfile 已经优化了层顺序,但可以进一步优化
优化建议:
- ✅ 已实现:package.json 在前,源代码在后
- ✅ 已实现:使用多阶段构建
- ⚠️ 可优化:添加
--cache-from参数使用之前的镜像作为缓存源
实施方法:
# 尝试从之前的镜像加载缓存
$previousImage = "${ImageName}:previous"
docker image inspect $previousImage 2>&1 | Out-Null
if ($LASTEXITCODE -eq 0) {
$cacheFrom = "--cache-from=$previousImage"
} else {
$cacheFrom = ""
}
docker build --progress=plain $cacheFrom -t $fullImage ...
3. 压缩 tar 文件(可选)
优化效果:上传时间从 1-2 分钟减少到 30秒-1分钟(取决于压缩率)
权衡:
- ✅ 优点:上传文件更小,上传更快
- ❌ 缺点:压缩需要额外时间(~30秒),服务器解压也需要时间
实施方法:
# 使用 gzip 压缩
Write-Host "正在压缩镜像..." -ForegroundColor Yellow
$compressedPath = "${archivePath}.gz"
docker save $fullImage | gzip > $compressedPath
# 上传压缩文件
Invoke-SCPUpload -LocalPath $compressedPath ...
# 服务器端解压并加载
Invoke-SSHCommand -Command "gunzip -c ${remoteTarPath}.gz | docker load"
建议:如果网络速度较慢(<10MB/s),启用压缩;如果网络速度较快(>20MB/s),不压缩更快。
4. 并行执行某些步骤
优化效果:总耗时减少 30-60 秒
可并行的步骤:
- 构建镜像的同时,可以检查服务器连接
- 打包镜像的同时,可以准备上传脚本
- 上传文件的同时,可以准备部署命令
实施方法:
# 使用 PowerShell 后台任务
$buildJob = Start-Job -ScriptBlock { docker build ... }
$checkJob = Start-Job -ScriptBlock { Test-SSHConnection ... }
# 等待构建完成
Wait-Job $buildJob
Receive-Job $buildJob
5. 智能跳过不必要的步骤
优化效果:节省 30-60 秒
可跳过的步骤:
- 如果只是代码变更(没有依赖变化),可以跳过
npm run check - 如果镜像已存在且未变化,可以跳过构建
- 如果数据库 schema 未变化,可以跳过迁移
实施方法:
# 检查是否有依赖变化
$packageHash = (Get-FileHash package.json).Hash
$lastHash = Get-Content .last-package-hash -ErrorAction SilentlyContinue
if ($packageHash -eq $lastHash) {
Write-Host "依赖未变化,跳过检查" -ForegroundColor Yellow
$SkipCheck = $true
} else {
$packageHash | Out-File .last-package-hash
}
6. 使用 Docker Registry(长期优化)
优化效果:完全避免上传 tar 文件,部署时间减少 1-2 分钟
方案:
- 在服务器上搭建私有 Docker Registry(如 Harbor)
- 或者使用 Docker Hub / 阿里云容器镜像服务
- 构建后直接 push 到 registry
- 服务器端直接 pull
实施方法:
# 构建后直接 push
docker build -t registry.example.com/flnxi-material:latest .
docker push registry.example.com/flnxi-material:latest
# 服务器端直接 pull
docker pull registry.example.com/flnxi-material:latest
docker compose up -d
权衡:
- ✅ 优点:不需要上传大文件,部署更快
- ❌ 缺点:需要搭建和维护 registry,增加复杂度
7. 增量部署(仅代码变更时)
优化效果:如果只是代码变更,可以只上传变更文件,在服务器上重新构建
方案:
- 使用 rsync 同步源代码到服务器
- 在服务器上执行构建(利用服务器更强的性能)
实施方法:
# 只同步源代码
rsync -avz --exclude 'node_modules' --exclude '.next' \
./ ${Username}@${Server}:${RemotePath}/source/
# 在服务器上构建
Invoke-SSHCommand -Command "cd ${RemotePath}/source && docker build ..."
权衡:
- ✅ 优点:上传文件小,速度快
- ❌ 缺点:需要在服务器上安装构建环境,占用服务器资源
推荐优化方案(按优先级)
优先级 1:立即实施(效果明显,实施简单)
- ✅ 启用 BuildKit 缓存 - 构建时间减少 50-70%
- ✅ 使用
--cache-from- 进一步利用缓存 - ✅ 智能跳过检查 - 节省 30-60 秒
优先级 2:中期实施(效果中等,需要测试)
- ⚠️ 压缩 tar 文件 - 如果网络较慢,效果明显
- ⚠️ 并行执行步骤 - 节省 30-60 秒
优先级 3:长期考虑(需要架构调整)
- 🚀 使用 Docker Registry - 最佳长期方案
- 🚀 增量部署 - 适合频繁小更新
实施建议
快速优化(5分钟实施)
修改 local-build-and-upload.ps1:
- 在脚本开头添加
$env:DOCKER_BUILDKIT = "1" - 添加
--cache-from参数 - 添加智能跳过检查逻辑
中期优化(30分钟实施)
- 添加压缩选项(可选参数)
- 实现并行执行
- 优化错误处理和日志
长期优化(需要规划)
- 评估 Docker Registry 方案
- 考虑 CI/CD 集成
- 优化服务器资源使用
预期效果
优化前
- 总耗时:5-10 分钟
- 构建:3-5 分钟
- 上传:1-2 分钟
- 部署:1-2 分钟
优化后(实施优先级 1)
- 总耗时:2-4 分钟(减少 50-60%)
- 构建:1-2 分钟(使用缓存)
- 上传:1-2 分钟(不变)
- 部署:30秒-1分钟(优化后)
优化后(实施所有优先级 1+2)
- 总耗时:1.5-3 分钟(减少 70-80%)
- 构建:1-2 分钟(使用缓存)
- 上传:30秒-1分钟(压缩后)
- 部署:30秒(优化后)
注意事项
- BuildKit 要求:需要 Docker 19.03+ 和启用 BuildKit
- 缓存失效:如果 package.json 变化,缓存会失效
- 网络依赖:上传速度取决于网络,压缩可能不总是更快
- 服务器资源:确保服务器有足够资源处理构建和部署