ci(deploy): enable containerized production release

This commit is contained in:
2026-07-06 12:58:01 +08:00
parent 0462f60bc5
commit fca397a87d
6 changed files with 67 additions and 57 deletions
+50 -16
View File
@@ -66,18 +66,16 @@ production root@43.106.13.130:/root/cozsweet-repos/main
服务器收到 push 后,`post-receive` hook 会自动执行以下步骤:
1. 初始化 Node / pnpm 环境
2. 解析当前仓库目录,进入服务端工作树
3. 初始化日志文件:`logs/post-receive.log`
4. 覆盖写入本次执行元信息,包括时间、分支、commit、cwd
5. 执行 `git reset --hard HEAD`,让服务端工作树同步到刚推送的最新 commit
6. 根据当前分支复制环境变量文件
7. 根据当前分支选择 Next.js 启动端口。
8. 根据分支导出 Docker Compose 所需变量,包括镜像名、容器名、env 文件和端口
9. 执行 `docker compose build web` 构建环境专属镜像
10. 如果镜像构建失败,写入失败日志并中止,旧容器继续运行
11. 如果镜像构建成功,执行 `docker compose up -d --remove-orphans web` 重建并启动容器。
12. 第一次从裸机 `next start` 迁移到容器时,如果目标端口上没有同名容器但存在旧进程,会清理旧进程后再启动容器。
1. 解析当前仓库目录,进入服务端工作树
2. 初始化日志文件:`logs/post-receive.log`
3. 覆盖写入本次执行元信息,包括时间、分支、commit、cwd
4. 执行 `git reset --hard HEAD`,让服务端工作树同步到刚推送的最新 commit。
5. 根据当前分支复制环境变量文件
6. 根据当前分支选择 Next.js 启动端口
7. 根据分支导出 Docker Compose 所需变量,包括镜像名、容器名、env 文件和端口。
8. 执行 `docker compose build web` 构建环境专属镜像
9. 如果镜像构建失败,写入失败日志并中止,旧容器继续运行
10. 如果镜像构建成功,执行 `docker compose up -d --remove-orphans web` 重建并启动容器
## 分支、环境变量、端口映射
@@ -94,6 +92,41 @@ production root@43.106.13.130:/root/cozsweet-repos/main
本地部署脚本清除 Cloudflare CDN 缓存时,也会按当前分支读取 env:`main` 优先读取 `.env.production`,其他分支优先读取 `.env.local`。如果优先文件不存在或缺少 `CF_ZONE_ID` / `CF_API_TOKEN`,会尝试读取另一个文件作为兜底。
## 生产容器化启用与验证
生产环境容器化通过 `main` 分支触发。发布入口为:
```bash
./scripts/release/release_web.sh
```
发布完成后,可在生产服务器工作树中验证:
```bash
cd /root/cozsweet-repos/main
# 确认生产工作树已更新到 main 最新 commit
git branch --show-current
git rev-parse --short HEAD
# 查看生产容器
docker ps --filter 'name=cozsweet-web-prod'
docker inspect cozsweet-web-prod --format '{{.State.Health.Status}}'
# 验证生产宿主机端口和 PWA service worker
curl -I http://127.0.0.1:9185/
curl -I http://127.0.0.1:9185/serwist/sw.js
```
如果本次发布同时更新了 `.githooks/post-receive` 本身,而服务器这次 push 仍由旧 hook 执行,可在生产工作树中手动触发一次新 hook:
```bash
cd /root/cozsweet-repos/main
./.githooks/post-receive
```
后续生产发布会自动使用新的容器化 hook。
## 容器构建机制
Docker 构建使用 Next.js standalone 输出:
@@ -102,8 +135,9 @@ Docker 构建使用 Next.js standalone 输出:
2. `Dockerfile` 使用 multi-stage build。
3. build 阶段通过 Docker BuildKit secret 挂载 `.env.local``.env.production`
4. build 完成后删除临时 env 文件,避免 env 文件被复制到最终镜像。
5. runtime 阶段复制 `.next/standalone``.next/static``public`
6. 容器通过 `node server.js` 启动,不再依赖完整 `node_modules``next start`
5. runtime 阶段复制 `.next/standalone``.next/static``public` 和生产依赖 `node_modules`
6. 生产依赖用于支持 Serwist 在运行时生成 `/serwist/sw.js`,避免手动修复 pnpm symlink
7. 容器通过 `node server.js` 启动,不再使用 `next start`
注意:`NEXT_PUBLIC_*` 变量会在 `next build` 时固化到前端 bundle,因此测试环境和生产环境必须分别构建镜像,不能共用同一个镜像。
@@ -122,8 +156,7 @@ docker compose up -d --remove-orphans web
4. Compose 会使用新镜像重建服务容器。
5. 容器配置了 `restart: unless-stopped`,容器异常退出后由 Docker 自动拉起。
6. 容器内固定监听 `3000`,宿主机端口按分支映射为 `9135``9185`
首次迁移时,如果宿主机端口仍被旧的裸机 `next start` 进程占用,hook 会在构建成功后、启动容器前清理旧进程。后续如果同名容器已经存在,则不再手动清理端口,由 Docker Compose 管理容器替换。
7. hook 不再主动清理宿主机端口进程,端口和容器生命周期交给 Docker Compose 管理。
## 日志与排查
@@ -184,6 +217,7 @@ ABORTED ... (docker compose up failed)
5. 构建失败时不会重启容器,旧容器继续运行。
6. 服务启动由 Docker Compose 管理,不再使用 `nohup pnpm run start`
7. 服务器需要安装 Docker,并支持 `docker compose` 或旧版 `docker-compose` 命令。
8. 测试环境和生产环境都通过同一套 `post-receive` 容器化流程部署,差异仅由分支、环境变量文件和端口决定。
## 后续优化建议