Files
zt-closet-manage-backend/.codebuddy/plans/管理后台_CI_CD_流水线_1e4d6d0a.md
T
2026-09-13 23:44:36 +08:00

125 lines
8.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.
---
name: 管理后台 CI/CD 流水线
overview: 参照业务服务 /root/zt-closet-backend 的 Gitea Actions CI/CD(.gitea/workflows/deploy.yaml + 多阶段 Dockerfile + .dockerignore),为本服务 /root/zt-closet-manage-backend 建立等价的构建部署流水线:tag 推送或手动触发 → 构建镜像推送到 Gitea 仓库 → SSH 部署生产机 → 健康检查失败自动回滚。
todos:
- id: create-deploy-workflow
content: 新增 .gitea/workflows/deploy.yaml 构建部署流水线(tag v* 与手动触发、镜像推送、SSH 部署、健康检查失败回滚)
status: completed
- id: create-dockerfile
content: 新增 scripts/dockerfile/Dockerfile 多阶段构建(golang:1.26-alpine 静态编译、alpine:3.22 非 root 运行、TZ 与 /ping 健康检查)
status: completed
- id: create-dockerignore
content: 新增 .dockerignore(排除 configs/storage/文档/scripts 等,防密钥进入镜像层)
status: completed
- id: update-readme
content: 更新 README 新增「CI/CD 与部署」章节(流水线说明、Gitea Secrets/Vars 清单、生产机目录与配置准备)
status: completed
dependencies:
- create-deploy-workflow
- id: verify-cicd
content: 验证:pyyaml 校验 workflow 语法,docker build 本地构建确认 Dockerfile 可产出镜像
status: completed
dependencies:
- create-deploy-workflow
- create-dockerfile
- create-dockerignore
---
## 产品概述
为管理后台服务(zt-closet-manage-backend)建立与业务服务一致的 CI/CD 体系。参照业务服务已有的 Gitea Actions 流水线与 Docker 构建方案,实现「打 tag 自动触发 + 手动触发」的镜像构建、推送与生产机部署,并带健康检查与失败自动回滚能力。
## 核心功能
- 构建部署流水线(Gitea Actions):推送 `v*` 标签或手动触发后,构建 Docker 镜像推送到 Gitea 镜像仓库(git.lzcwy.cn),再通过 SSH 部署到生产机。
- 多阶段 Dockerfile:Go 静态编译(golang:1.26-alpine)→ 精简运行镜像(alpine:3.22),非 root 用户运行,内置 `/ping` 健康检查,配置与日志目录以卷挂载方式接入(密钥不进镜像层)。
- 部署安全机制:部署前记录旧镜像 ID,新容器启动 5 秒后健康检查,失败自动输出日志并回滚到旧镜像。
- .dockerignore:剔除配置密钥、日志、文档等非构建资产,防止密钥进入镜像层。
- 文档:README 增加 CI/CD 章节,说明流水线触发方式、Gitea Secrets/Vars 配置清单、生产机目录准备要求。
- 不包含数据库迁移流水线:管理后台无独立迁移命令(admin_users 表由服务启动时 GORM AutoMigrate 幂等创建),故无需业务服务的 mysqlup/mysqldown 工作流。
## 与业务服务的差异适配
业务服务(zt-closet-backend)CI/CD 的调研结论:Gitea Actions 三套工作流(deploy.yaml、mysqlup.yaml、mysqldown.yaml)+ scripts/dockerfile 下两个 Dockerfile + .dockerignore。管理后台按自身特性适配:Go 版本 1.26(业务 1.27)、无上传功能(挂载仅 configs + storage/logs)、独立部署目录与 Secrets 命名(ZT_CLOSET_MANAGE_*)。
## 技术栈
- CI/CD 平台:Gitea Actions(与业务服务同一 Gitea 实例 git.lzcwy.cn,runner 支持 docker)
- 容器:Docker(多阶段构建,golang:1.26-alpine → alpine:3.22)
- 部署:SSH 免密部署到生产机 + docker run(--network host)+ curl/wget 健康检查 + 旧镜像回滚
- 验证:pyyaml 语法校验 + 本机 docker build 构建验证(本机 docker 26.1.3 可用)
## 实现方案
### 1. 流水线文件 `.gitea/workflows/deploy.yaml`
结构复刻业务 deploy.yaml,参数按管理后台调整:
```
name: 构建并部署
on:
push:
tags: ['v*']
workflow_dispatch:
concurrency:
group: deploy
cancel-in-progress: false
env:
REGISTRY: git.lzcwy.cn
IMAGE: git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend
```
Job 步骤(runs-on: ubuntu-latest):
1. `actions/checkout@v4` 拉取代码。
2. 确认 docker 可用(`docker version`)。
3. 计算镜像标签:`refs/tags/*` 取 tag 名,否则 `sha-<7位SHA>`。
4. `docker login` 登录 Gitea 镜像仓库(secrets:`ZT_CLOSET_MANAGE_REGISTRY_USER` / `ZT_CLOSET_MANAGE_REGISTRY_TOKEN`)。
5. `docker build --build-arg GOPROXY=https://goproxy.cn,direct -f scripts/dockerfile/Dockerfile -t <IMAGE>:<tag> -t <IMAGE>:latest .` 并推送 tag + latest。
6. SSH 部署生产机(secrets:`ZT_CLOSET_MANAGE_PROD_SSH_KEY`;vars:`ZT_CLOSET_MANAGE_PROD_SSH_HOST` / `ZT_CLOSET_MANAGE_PROD_SSH_USER`),远端脚本:
- `DIR=/opt/zt-closet-manage`、`APP=zt-closet-manage-backend`;
- `mkdir -p $DIR/configs $DIR/storage/logs` 并 `chown -R 10001:10001 $DIR/storage`(容器内非 root 用户 uid 10001 需日志写权限);
- 记录旧镜像 ID → `docker pull` → `docker rm -f` → `docker run -d --name $APP --network host --restart unless-stopped -v $DIR/configs:/app/configs:ro -v $DIR/storage/logs:/app/storage/logs -e TZ=Asia/Shanghai --log-opt max-size=50m --log-opt max-file=5 $IMAGE:latest`;
- `sleep 5` 后 `curl/wget http://127.0.0.1:8080/ping` 健康检查(端口须与生产 config.yaml 的 `Server.HttpPort` 一致,注释说明);
- 失败:`docker logs --tail 50` → 移除新容器 → 若有旧镜像则以相同参数启动旧镜像回滚 → `exit 1`;
- 成功:`docker image prune -f` 清理旧镜像。
7. 部署结果步骤(`if: always()`)输出镜像标签。
### 2. 多阶段 Dockerfile `scripts/dockerfile/Dockerfile`
复刻业务 Dockerfile,差异:`ARG GO_VERSION=1.26`(管理后台 go.mod 为 go 1.26.1)、二进制名 `zt-closet-manage-backend`、runtime 仅建 `configs` + `storage/logs` 两个挂载点(无 uploads)。
- 构建阶段:`FROM golang:${GO_VERSION}-alpine AS builder`;`ARG TARGETOS/TARGETARCH`(默认 linux/amd64,兼容未启用 buildx 场景);`ARG GOPROXY` 默认 `https://proxy.golang.org,direct`(流水线内以 build-arg 覆盖为 goproxy.cn);先 `COPY go.mod go.sum` + `go mod download` 复用缓存层,再 `COPY . .`;`ENV CGO_ENABLED=0`,`GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -trimpath -ldflags="-s -w" -o /out/zt-closet-manage-backend .` 静态编译。
- 运行阶段:`FROM alpine:${ALPINE_VERSION}`(3.22);`apk add --no-cache ca-certificates tzdata`(HTTPS 依赖根证书、本地时区计算每日额度展示);`addgroup -g 10001 -S app && adduser -u 10001 -S -G app app` 非 root;`WORKDIR /app`;COPY 二进制;`mkdir -p /app/configs /app/storage/logs && chown -R app:app /app`;`ENV TZ=Asia/Shanghai`、`ENV APP_PORT=8080`;`USER app`;`EXPOSE ${APP_PORT}`;`HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 CMD wget -q -O - "http://127.0.0.1:${APP_PORT}/ping" || exit 1`;`CMD ["/app/zt-closet-manage-backend"]`。
### 3. `.dockerignore`
复刻业务按实际目录裁剪:`.git`、`.gitignore`、`*.md`、`docs/`、`design/`、`storage/`、`configs/`(密钥不进构建上下文)、`scripts/`、`Dockerfile`、`.dockerignore`。`.gitea/` 与业务一致不排除。
### 4. README 新增「CI/CD 与部署」章节
- 流水线说明:打 `v*` 标签或 Gitea 页面手动触发;触发后构建推送镜像并部署到生产机,健康检查失败自动回滚。
- Gitea 仓库需创建的 Secrets:`ZT_CLOSET_MANAGE_REGISTRY_USER`、`ZT_CLOSET_MANAGE_REGISTRY_TOKEN`、`ZT_CLOSET_MANAGE_PROD_SSH_KEY`;Variables:`ZT_CLOSET_MANAGE_PROD_SSH_HOST`、`ZT_CLOSET_MANAGE_PROD_SSH_USER`。
- 生产机准备:目录 `/opt/zt-closet-manage`(configs/config.yaml 必填、storage/logs 自动创建并授权 uid 10001);`config.yaml` 的 `Server.HttpPort` 须为 8080(与健康检查一致)。
- 说明无迁移流水线:`admin_users` 表由服务启动时 AutoMigrate 自动创建。
### 5. 验证
- `python3 -c "import yaml; yaml.safe_load(...)"` 校验 deploy.yaml 语法。
- 本机 `docker build -f scripts/dockerfile/Dockerfile --build-arg GOPROXY=https://goproxy.cn,direct -t zt-closet-manage-backend:test .` 验证 Dockerfile 可正常构建出镜像(不推送、不部署)。
## 目录结构
```
/root/zt-closet-manage-backend/
├── .gitea/
│ └── workflows/
│ └── deploy.yaml # [NEW] 构建部署流水线(tag v* / 手动触发,SSH 部署 + 健康检查回滚)
├── scripts/
│ └── dockerfile/
│ └── Dockerfile # [NEW] 多阶段构建(golang:1.26-alpine → alpine:3.22,非 root,HEALTHCHECK /ping)
├── .dockerignore # [NEW] 排除配置密钥/日志/文档等非构建资产
└── README.md # [MODIFY] 新增「CI/CD 与部署」章节(Secrets/Vars 清单、生产机准备、触发方式)
```