docs(docs): 新增本地启动/多AI协作/CI-CD 使用手册

- local-dev-runbook.md: 8 章本地启动手册(环境依赖/端口分配/开发模式/生产模式/裸机运行/常见问题)

- multi-ai-collaboration.md: 15 章多AI协作文档(角色定义/模块分工/分支策略/PR流程/审核合并/跨模块变更)

- cicd-runbook.md: 10 章 CI/CD 使用手册(架构总览/一次性配置/日常使用/镜像管理/部署验证/回滚)

- README.md: 文档清单新增三个 runbook 链接
This commit is contained in:
SpecialX
2026-07-08 15:14:30 +08:00
parent 3b88e9cca5
commit d19285a977
4 changed files with 1516 additions and 0 deletions

View File

@@ -0,0 +1,445 @@
# CI/CD 使用手册CI/CD Runbook
> 版本1.0
> 日期2026-07-08
> 适用范围Edu 微服务项目Gitea Actions + Gitea Container Registry + Runner 直接部署)
> 关联文档:[project_rules §15](../../.trae/rules/project_rules.md)、[本地启动手册](./local-dev-runbook.md)、[多 AI 协作指南](./multi-ai-collaboration.md)
---
## 1. 架构总览
```
开发 AI 推送 PR 协调 AI 合并到 main
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ ci-*.yml │ │ docker.yml │
│ lint+test+ │ │ build+push │
│ build+scan │ │ 镜像到 Gitea│
└─────────────┘ │ Registry │
└──────┬──────┘
┌─────────────┐
│ deploy.yml │
│ Runner 直接 │
│ docker │
│ compose up │
└─────────────┘
```
### 1.1 组件清单
| 组件 | 说明 |
| ---------------------------- | --------------------------------------------------------------- |
| **Gitea** | `git.eazygame.cn`,代码托管 + Actions + Container Registry |
| **Gitea Actions** | CI 运行器,兼容 GitHub Actions 语法 |
| **Gitea Container Registry** | 镜像仓库,地址 `git.eazygame.cn/xiner/edu/<service>:<tag>` |
| **Deploy Runner** | 跑在服务器上的 self-hosted runner标签 `[self-hosted, deploy]` |
| **服务器 MySQL** | 已有容器,端口 3306容器名 `edu-mysql`(假设) |
| **服务器 Redis** | 已有容器,端口 6379容器名 `edu-redis`(假设) |
### 1.2 流水线文件
| 文件 | 触发 | 作用 |
| -------------------------------- | ------------------------ | ---------------------------------------------------------- |
| `.github/workflows/ci-ts.yml` | TS 路径变更 | lint + typecheck + test + build + arch:scan + docker-build |
| `.github/workflows/ci-go.yml` | Go 路径变更 | vet + build + test + docker-build |
| `.github/workflows/ci-py.yml` | Python 路径变更 | ruff + pytestP4 阶段) |
| `.github/workflows/ci-proto.yml` | proto 变更 | buf lint + buf breaking |
| `.github/workflows/docker.yml` | push main / tag `v*` | 构建并推送镜像到 Gitea Registry |
| `.github/workflows/deploy.yml` | docker.yml 完成后 / 手动 | Runner 执行 docker compose up |
---
## 2. 一次性配置SRE AI 或人类执行)
### 2.1 启用 Gitea Actions
在 Gitea 仓库 `xiner/Edu` 设置:
1. **仓库设置 → Actions → 启用**
2. 安装 actrunner若未安装
```bash
# 在服务器上
wget https://gitea.com/gitea/act_runner/raw/branch/main/act_runner
chmod +x act_runner
./act_runner register --instance https://git.eazygame.cn --token <TOKEN>
```
3. 配置 runner 标签为 `self-hosted,deploy`(部署用)和 `self-hosted,linux`CI 用)
### 2.2 启用 Gitea Container Registry
Gitea 1.20+ 自带 Container Registry无需额外启用。确认
```bash
# 测试登录
docker login git.eazygame.cn -u <你的用户名>
# 输入密码或 token
```
### 2.3 准备服务器网络
确保 MySQL/Redis 容器与应用容器在同一 Docker 网络:
```bash
# 创建共享网络(若不存在)
docker network create edu-shared
# 将已有的 MySQL/Redis 加入网络(容器名按实际替换)
docker network connect edu-shared edu-mysql # 或实际容器名
docker network connect edu-shared edu-redis # 或实际容器名
```
> 查看实际容器名:`docker ps --format "{{.Names}}" | grep -E "mysql|redis"`
### 2.4 初始化部署目录
```bash
# 1. 创建部署目录
sudo mkdir -p /opt/edu
sudo chown -R $USER:$USER /opt/edu
# 2. 拷贝 compose 文件
cd /path/to/Edu
cp infra/docker-compose.deploy.yml /opt/edu/docker-compose.yml
# 3. 创建生产 .env从模板
cp infra/deploy.env.example /opt/edu/.env
vim /opt/edu/.env
# 必须修改:
# JWT_SECRET=<openssl rand -hex 32 生成的随机值>
# DATABASE_URL=mysql://<user>:<pass>@<mysql容器名>:3306/<db>
# REDIS_URL=redis://<redis容器名>:6379
# 4. 登录 Gitea Container RegistryRunner 用户)
docker login git.eazygame.cn -u <user> -p <token>
# token 在 Gitea → 设置 → 应用 → 生成新 token
```
### 2.5 配置 Gitea Secrets
在 Gitea 仓库 → 设置 → Actions → Secrets添加
| Secret 名 | 用途 | 必填 |
| ---------------------- | -------------------------------- | ---- |
| `GITHUB_TOKEN` | Gitea 自动注入,推送镜像用 | 自动 |
| `GITEA_REGISTRY_USER` | deploy.yml 登录 registry可选 | 否 |
| `GITEA_REGISTRY_TOKEN` | deploy.yml 登录 registry可选 | 否 |
> `GITHUB_TOKEN` 由 Gitea Actions 自动注入,无需手动配置。`docker.yml` 用它推送镜像。
> `deploy.yml` 中 Runner 已在服务器上,若已 `docker login` 过则无需 secrets。
---
## 3. 日常使用
### 3.1 开发 AI 提 PR
开发 AI 推送特性分支后创建 PR自动触发 CI
```
PR 创建 → ci-ts.yml / ci-go.yml 运行
├─ qualitylint + typecheck + test + build
├─ arch-scan架构扫描
└─ docker-build构建不推送
CI 全绿 → 协调 AI 审核合并
```
### 3.2 协调 AI 合并 PR
PR 合并到 main 后,自动触发:
```
push main →
├─ ci-*.yml确保 main 稳定)
└─ docker.yml → 构建并推送镜像到 git.eazygame.cn/xiner/edu/<service>:latest
deploy.yml → Runner 执行 docker compose pull && up -d
健康检查(轮询 /healthz
```
### 3.3 手动部署
在 Gitea → Actions → Deploy → Run workflow
| 参数 | 说明 |
| ----------- | --------------------------------------- |
| `image_tag` | 部署指定 tag默认 `latest` |
| `rollback` | 勾选则跳过 pull用本地已有镜像重新启动 |
### 3.4 发布正式版本tag
```bash
git tag -a v1.0.0 -m "P1 阶段首次发布"
git push origin v1.0.0
```
触发 `docker.yml` 推送 `v1.0.0` tag 镜像,再手动触发 deploy.yml 部署 `v1.0.0`。
---
## 4. 镜像管理
### 4.1 镜像地址
```
git.eazygame.cn/xiner/edu/<service>:<tag>
```
| service | 说明 |
| ---------------- | --------------- |
| `api-gateway` | Go 网关 |
| `classes` | NestJS 班级服务 |
| `teacher-portal` | Next.js 前端 |
### 4.2 Tag 策略
| tag | 来源 | 用途 |
| ------------------ | ----------------- | ---------- |
| `latest` | main 分支最新构建 | 默认部署 |
| `main-<sha>` | main 分支每次构建 | 可追溯 |
| `v<version>` | 打 `v*` tag 触发 | 正式版本 |
| `v<major>.<minor>` | 打 `v*` tag 触发 | 大版本追踪 |
### 4.3 查看与清理镜像
在 Gitea → 用户设置 → Packages可查看与管理所有镜像。
清理旧 tag手动
```bash
# 列出所有 tag
docker images git.eazygame.cn/xiner/edu/classes --format "{{.Tag}}"
# 删除本地旧镜像
docker rmi git.eazygame.cn/xiner/edu/classes:main-abc1234
```
---
## 5. 部署验证
### 5.1 CI 自动验证
`deploy.yml` 部署后会自动轮询健康检查(最多 10 次,每次间隔 6 秒):
- `http://localhost:8080/healthz` — api-gateway
- `http://localhost:3001/healthz` — classes
- `http://localhost:3000/` — teacher-portal
失败时输出容器日志,方便排查。
### 5.2 手动验证
```bash
# SSH 到服务器后
cd /opt/edu
# 容器状态
docker compose ps
# 健康检查
curl http://localhost:8080/healthz # api-gateway
curl http://localhost:3001/healthz # classes
curl http://localhost:3000/ # teacher-portal
# 鉴权验证(生产模式 dev-token 应被拒绝)
curl -H "Authorization: Bearer dev-token" http://localhost:8080/api/v1/classes
# 预期401 INVALID_TOKEN
# 查看日志
docker compose logs -f api-gateway
docker compose logs -f classes
docker compose logs -f teacher-portal
```
### 5.3 外部访问
若服务器有公网 IP如 `1.2.3.4`
- 前端:`http://1.2.3.4:3000`
- API 网关:`http://1.2.3.4:8080`
- 健康检查:`http://1.2.3.4:8080/healthz`
---
## 6. 回滚
### 6.1 CI 回滚(推荐)
在 Gitea → Actions → Deploy → Run workflow
- `image_tag`:填入上一个稳定版本的 tag如 `main-abc1234`
- `rollback`:勾选(跳过 pull用本地已有镜像
### 6.2 手动回滚
```bash
cd /opt/edu
# 查看本地镜像
docker images git.eazygame.cn/xiner/edu/classes --format "{{.Tag}}"
# 回滚到指定版本
IMAGE_TAG=main-abc1234 docker compose up -d
```
### 6.3 紧急回滚Git revert
若代码有问题:
```bash
git revert <bad-commit>
git push origin main
# CI 自动重新构建部署
```
---
## 7. 常见问题
### 7.1 CI: pnpm install 失败
**症状**`pnpm install --frozen-lockfile` 报错。
**排查**
1. `pnpm-lock.yaml` 未提交:`git add pnpm-lock.yaml && git commit -m "chore(deps): 更新 lockfile"`
2. Node 版本不匹配:确认 CI 用 Node 20本地一致
### 7.2 CI: docker-build 失败
**症状**`docker/build-push-action` 报错。
**排查**
1. Dockerfile 语法错误:本地 `docker build` 验证
2. 路径错误:确认 `context` 与 `file` 参数
### 7.3 CD: 镜像拉取失败
**症状**`docker compose pull` 报 `unauthorized`。
**修复**
```bash
# 服务器上重新登录
docker login git.eazygame.cn -u <user> -p <token>
# 或配置 Gitea secrets GITEA_REGISTRY_USER / GITEA_REGISTRY_TOKEN
```
### 7.4 CD: 健康检查失败
**症状**`deploy.yml` 健康检查 10 次后失败。
**排查**
1. 查看日志:`cd /opt/edu && docker compose logs api-gateway`
2. 常见原因:
- `DATABASE_URL` 连不上 MySQL检查容器名与网络
- `JWT_SECRET` 未配置
- 端口被占用:`docker ps` 检查冲突
### 7.5 CD: 连不上 MySQL/Redis
**症状**classes 容器报 `ECONNREFUSED edu-mysql:3306`。
**修复**
```bash
# 1. 确认 MySQL 容器名
docker ps --format "{{.Names}}" | grep mysql
# 2. 确认 MySQL 在 edu-shared 网络
docker network inspect edu-shared | grep -A5 Containers
# 3. 若不在,加入网络
docker network connect edu-shared <实际mysql容器名>
# 4. 修改 /opt/edu/.env 的 DATABASE_URL
# DATABASE_URL=mysql://edu:changeme@<实际容器名>:3306/next_edu_cloud
```
### 7.6 Gitea Actions 未触发
**症状**push 后 Actions 不运行。
**排查**
1. 仓库设置 → Actions → 确认已启用
2. Runner 在线Gitea → 设置 → Actions → Runners
3. workflow 文件在 `.github/workflows/` 目录(非 `.gitea/workflows/`
4. `on:` 触发条件匹配paths 过滤)
### 7.7 workflow_run 不触发
**症状**`docker.yml` 完成后 `deploy.yml` 不自动运行。
**原因**Gitea Actions 对 `workflow_run` 触发支持可能不完整。
**解决**
- 改用手动触发Actions → Deploy → Run workflow
- 或在 `docker.yml` 末尾加 job 调用 deploy需要 `workflow_call`
---
## 8. 排查命令速查
```bash
# === 在服务器上 ===
# 查看所有 edu 容器
docker compose -f /opt/edu/docker-compose.yml ps
# 查看实时日志
docker compose -f /opt/edu/docker-compose.yml logs -f
# 重启单个服务
docker compose -f /opt/edu/docker-compose.yml restart api-gateway
# 进入容器
docker exec -it edu-api-gateway sh
docker exec -it edu-classes sh
# 查看网络
docker network inspect edu-shared
# 查看镜像列表
docker images git.eazygame.cn/xiner/edu
# === 在 Gitea Web UI ===
# 仓库 → Actions → 查看流水线运行记录
# 用户设置 → Packages → 管理镜像
# 仓库 → 设置 → Secrets → 管理 CI 密钥
# 仓库 → 设置 → Actions → Runners → 查看 Runner 状态
```
---
## 9. 安全注意事项
1. **`.env` 文件不入库**`.gitignore` 已忽略,仅存在于服务器 `/opt/edu/.env`
2. **JWT_SECRET 强随机**:生产必须用 `openssl rand -hex 32` 生成
3. **DEV_MODE=false**docker-compose.deploy.yml 强制设为 `false`
4. **Gitea Token 权限最小化**:仅给 `package:write` 和 `contents:read`
5. **Runner 隔离**deploy runner 仅跑在目标服务器,不暴露公网 SSH
6. **镜像扫描**P6`docker.yml` 后续加 Trivy 扫描步骤
---
## 10. 相关文档
- [project_rules §15 CI/CD 规范](../../.trae/rules/project_rules.md)
- [project_rules §14 多 AI 协作规范](../../.trae/rules/project_rules.md)
- [本地启动手册](./local-dev-runbook.md)
- [多 AI 协作指南](./multi-ai-collaboration.md)
- [Git 工作流](./git-workflow.md)
- [known-issues](../troubleshooting/known-issues.md)