优化checkout

This commit is contained in:
2026-09-13 23:44:36 +08:00
parent a4cb34a2e6
commit be84b34ed8
2 changed files with 126 additions and 1 deletions
@@ -0,0 +1,125 @@
---
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 清单、生产机准备、触发方式)
```
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: 拉取代码 - name: 拉取代码
uses: actions/checkout@v4 uses: https://gitee.com/liu_zhengchi/checkout@v4
- name: 确认 docker 可用 - name: 确认 docker 可用
run: | run: |