6.2 KiB
6.2 KiB
name, overview, todos
| name | overview | todos | |||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| frontend-cicd-deploy | 参考 zt-closet-backend 的 Gitea Actions CI/CD,为前端管理后台编写 deploy 工作流:构建 dist 静态资源并通过 SSH 同步到生产机 nginx 目录 /www/zt-closet-manage.lzcwy.cn。 |
|
产品概述
为前端项目 zt-closet-manage-frontend 建立与后端一致的 CI/CD 流水线(Gitea Actions),实现「打标签自动构建 → 部署到生产机 nginx 静态目录」的全流程自动化。
核心功能
- 推送
v*标签或手动触发(workflow_dispatch)时,自动安装依赖、类型检查并构建出dist静态产物。 - 通过 SSH 将构建产物安全传输到生产机,部署到 nginx root 目录
/www/zt-closet-manage.lzcwy.cn。 - 采用蓝绿目录原子切换部署,线上目录任何时刻都完整,失败秒级回滚,保证发布零中断。
- 复用后端已有的 Gitea runner 与 SSH 部署凭据,无需重复配置密钥。
约束说明
- 前端为纯静态资源,不使用 Docker,构建产物直接放到 nginx 静态目录。
- 前端 API baseURL 为
/api/v1,由生产 nginx 反代到127.0.0.1:8081,构建无需改动 baseURL 与 vite 配置。 - 产物结构(
index.html+/assets/带 hash 资源)与现有 nginxtry_files、/assets/长缓存配置匹配。
技术栈
- CI/CD:Gitea Actions(与后端
zt-closet-backend一致),runner 环境ubuntu-latest。 - 构建:Node.js(匹配
package.jsonengines^22.18.0 || >=24.12.0,取 Node 22)+ npm。 - 部署:SSH + rsync 传输到临时目录 + 蓝绿目录原子切换(mv)上线。
实现方案
参考后端 .gitea/workflows/deploy.yaml 的整体风格(name / on push tags v* + workflow_dispatch / concurrency / env / SSH heredoc 远端执行 / 健康检查与回滚),针对前端「纯静态资源」特点做如下调整:
- 去掉 Docker:前端无需镜像构建,改为
actions/checkout→actions/setup-node(Node 22,启用 npm 缓存)→npm ci→npm run build(内含 type-check + vite build)。 - 产物传输用 rsync:相比 scp,rsync 支持增量传输与
--delete,可清理临时目录中上一版本遗留的旧 hash 资源,传输更快、更干净。 - 蓝绿目录原子切换(核心):新产物先 rsync 到临时目录
/www/.zt-closet-deploy-tmp(绝不动线上目录);校验临时目录index.html存在后,用mv原子切换:将当前线上目录改名为备份目录,再把临时目录改名为线上目录。任何一步失败,线上目录保持原样不受影响;切换后校验失败则把备份目录mv回去,秒级回滚。 - 凭据复用:直接沿用后端的 secret
ZT_CLOSET_PROD_SSH_KEY与 varsZT_CLOSET_PROD_SSH_HOST、ZT_CLOSET_PROD_SSH_USER,生产机同一台,避免重复配置。
关键决策与权衡
- 蓝绿目录原子切换 而非 直接 rsync --delete 覆盖:直接对线上目录
--delete若传输中断,会出现「旧文件已删、新文件未传完」的半残状态导致站点 404;蓝绿方式线上目录始终完整,切换是一次mv,零中断、回滚快。权衡是需 nginx 进程对/www目录有 rename 权限(root 运行 nginx 通常满足),且临时目录与线上目录需在同一分区才能mv。 - rsync 而非 scp:增量 +
--delete(作用于临时目录)解决 Vite 带 hash 资源累积问题,传输量小、目录干净;需生产机预装 rsync(Linux 默认自带)。 - 不改动 vite 配置:默认
base='/'与 nginxroot部署完全契合,/assets/长缓存与 SPAtry_files均已就绪,零改动最安全。 - 健康检查用文件校验:静态站点无
/ping接口,改用「线上目录index.html是否存在」作为成功判据,简单可靠。
实现要点
- 性能:setup-node 开启 npm 缓存(
cache: true),源码未变动时npm ci复用缓存,加快重建;rsync 增量避免全量传输。 - 可靠性:远端脚本
set -e,rsync 到临时目录 → 校验 index.html →mv原子切换 → 切换后校验;失败则把备份目录 mv 还原,保证发布原子性与零中断;concurrency.group: deploy+cancel-in-progress: false防止并发部署互相打断。 - 安全:SSH 私钥仅从 secret 注入,写入
~/.ssh/deploy_key(600 权限),StrictHostKeyChecking=no仅用于自动化;不引入明文密钥;不改动业务代码与请求层。 - 爆炸半径控制:仅新增
.gitea/workflows/deploy.yaml一个文件,不动现有源码、vite 配置与 nginx 配置;标签触发不影响日常 push。
架构设计
沿用后端现有分层部署链路,仅将「Docker 镜像」环节替换为「静态产物 rsync + 蓝绿切换」。
flowchart LR
P[push tag v* / workflow_dispatch] --> CI[Gitea Actions Runner]
CI --> B[setup-node + npm ci + npm run build]
B --> D[dist 静态产物]
D --> R[rsync over SSH 到临时目录]
R --> V{校验 index.html}
V -->|通过| M[mv 原子切换上线]
V -->|失败| X1[保留线上旧版本]
M --> N[生产机 /www/zt-closet-manage.lzcwy.cn]
N --> X[nginx 对外提供 SPA + 反代 /api 到 127.0.0.1:8081]
目录结构
/root/zt-closet-manage-frontend/
└── .gitea/
└── workflows/
└── deploy.yaml # [NEW] 前端构建部署流水线。触发:push tag v* 与 workflow_dispatch。步骤:checkout → setup-node(Node22, 开 npm 缓存) → npm ci → npm run build(type-check + vite build) → SSH 密钥 + rsync 将 dist/ 同步到临时目录 /www/.zt-closet-deploy-tmp → 校验 index.html 存在 → mv 蓝绿原子切换上线(线上目录改名为备份、临时目录改名为线上),切换后校验失败则 mv 备份还原。复用后端 secret ZT_CLOSET_PROD_SSH_KEY 与 vars ZT_CLOSET_PROD_SSH_HOST/ZT_CLOSET_PROD_SSH_USER。