- 删除 6 个分散 workflow(ci-ts/ci-go/ci-proto/ci-py/docker/deploy) - 合并为单个 ci.yml:3 个 quality job 并行 + deploy job 串行 - 全部使用官方镜像(node:22-alpine/golang:1.22-alpine/bufbuild/buf/docker:25-git) - deploy job 用 DooD 模式挂载 /var/run/docker.sock - docker-compose.deploy.yml 改用 build: 替代 image:(no-push) - 新增 docker-compose.tools.yml 一次性预拉所有 CI 镜像 - 支持 workflow_dispatch 指定 commit_sha 回滚 - 更新 project_rules §15 与 cicd-runbook.md 为 no-push 模式 - 新增设计文档 docs/superpowers/specs/2026-07-08-cicd-no-push-local-build-design.md
138 lines
5.7 KiB
Markdown
138 lines
5.7 KiB
Markdown
# CI/CD 设计:本地构建部署(no-push)
|
||
|
||
> 日期:2026-07-08
|
||
> 状态:已批准,待实施
|
||
> 替代方案:[2026-07-08 之前的 docker.yml + deploy.yml push 方案](../../.github/workflows/)
|
||
|
||
## 1. 背景
|
||
|
||
### 1.1 现状问题
|
||
|
||
- `node-with-docker:22` 自定义镜像已丢失,原方案依赖它无法运行
|
||
- 推送到 Gitea Registry 的拉取速度极慢,影响部署效率
|
||
- 用户习惯本地构建测试后再推送,无需保留历史构建产物
|
||
- 微服务架构下,拆分多个 workflow 文件(ci-ts/ci-go/docker/deploy)使流程碎片化
|
||
|
||
### 1.2 目标
|
||
|
||
- 不依赖任何自建镜像,全部使用官方镜像
|
||
- 不推送镜像到 registry,构建即部署
|
||
- 单文件管理整个 CI/CD 流程
|
||
- 支持回滚(不依赖 registry tag)
|
||
- 提供一次性预拉所有镜像的 compose 文件
|
||
|
||
## 2. 设计
|
||
|
||
### 2.1 架构总览
|
||
|
||
```
|
||
PR/push 触发
|
||
│
|
||
├─ quality-ts job (container: node:22-alpine) 并行
|
||
├─ quality-go job (container: golang:1.22-alpine) 并行
|
||
├─ quality-proto job (container: bufbuild/buf:latest) 并行
|
||
│
|
||
└─ deploy job (container: docker:25-git) 仅 push main, needs: [quality-*]
|
||
挂载 /var/run/docker.sock(DooD)
|
||
├─ docker compose up --build(本地构建 3 个服务)
|
||
└─ 健康检查轮询
|
||
```
|
||
|
||
### 2.2 文件结构
|
||
|
||
```
|
||
.github/workflows/
|
||
└─ ci.yml # 唯一的 CI/CD 文件
|
||
|
||
infra/
|
||
├─ docker-compose.deploy.yml # 改造:build: 替代 image:
|
||
├─ docker-compose.tools.yml # 新建:预拉所有 CI 需要的镜像
|
||
└─ deploy.env.example # 保留
|
||
```
|
||
|
||
### 2.3 ci.yml 设计
|
||
|
||
**单文件多 job**:
|
||
|
||
- `quality-ts`:PR+push 都跑,container: node:22-alpine,pnpm install → lint → typecheck → test → build
|
||
- `quality-go`:PR+push 都跑,container: golang:1.22-alpine,go mod download → vet → build → test
|
||
- `quality-proto`:PR+push 都跑,container: bufbuild/buf:latest,buf lint + buf breaking(仅 PR)
|
||
- `deploy`:仅 push main 或 workflow_dispatch 触发,needs: [quality-ts, quality-go, quality-proto]
|
||
|
||
**deploy job 关键配置**:
|
||
|
||
- `container: docker:25-git`(官方镜像,自带 docker CLI + compose v2 + git)
|
||
- `options: --volume /var/run/docker.sock:/var/run/docker.sock`(DooD 模式)
|
||
- 流程:checkout → cp compose 文件到 /opt/edu/ → docker compose up --build → 健康检查
|
||
|
||
**回滚**:
|
||
|
||
- `workflow_dispatch` 支持 `commit_sha` 输入
|
||
- checkout 时使用指定 commit SHA
|
||
- 重新 build + deploy
|
||
|
||
### 2.4 docker-compose.deploy.yml 改造
|
||
|
||
所有服务从 `image:` 改为 `build:`:
|
||
|
||
- `api-gateway`:`build: ./services/api-gateway`
|
||
- `classes`:`build: { context: ., dockerfile: services/classes/Dockerfile }`(monorepo 上下文)
|
||
- `teacher-portal`:`build: { context: ., dockerfile: apps/teacher-portal/Dockerfile }`(monorepo 上下文)
|
||
|
||
删除 `IMAGE_TAG` 环境变量依赖。`docker compose up --build` 自动判断变更的服务。
|
||
|
||
### 2.5 docker-compose.tools.yml(预拉镜像)
|
||
|
||
用于一次性拉取所有 CI/构建需要的镜像到本地:
|
||
|
||
- CI 运行时:node:22-alpine、golang:1.22-alpine、bufbuild/buf:latest、docker:25-git
|
||
- 服务构建基础:node:20-alpine、golang:1.22-alpine、alpine:3.20
|
||
- 开发基础设施:mysql:8.0、redis:7-alpine
|
||
|
||
用法:`docker compose -f infra/docker-compose.tools.yml pull`
|
||
|
||
### 2.6 回滚策略
|
||
|
||
| 方式 | 操作 | 适用场景 |
|
||
| ---------- | --------------------------------------------------- | ---------------- |
|
||
| git revert | `git revert <bad-commit> && git push` → 自动触发 CI | 代码回滚(推荐) |
|
||
| 手动触发 | Actions → ci.yml → Run workflow → 填 commit_sha | 部署特定版本 |
|
||
|
||
### 2.7 actrunner 配置
|
||
|
||
```toml
|
||
container:
|
||
valid_volumes:
|
||
- /var/run/docker.sock
|
||
```
|
||
|
||
## 3. 实施步骤
|
||
|
||
1. 删除现有 4 个 workflow 文件(ci-ts.yml、ci-go.yml、ci-proto.yml、docker.yml、deploy.yml)
|
||
2. 创建 `.github/workflows/ci.yml`(合并单 workflow)
|
||
3. 改造 `infra/docker-compose.deploy.yml`(build 替代 image)
|
||
4. 创建 `infra/docker-compose.tools.yml`(预拉镜像)
|
||
5. 更新 `.trae/rules/project_rules.md` §15(no-push 模式规范)
|
||
6. 更新 `docs/standards/cicd-runbook.md`(删除 registry 章节,新增本地构建章节)
|
||
7. 提交并推送
|
||
|
||
## 4. 与旧方案对比
|
||
|
||
| 维度 | 旧方案(push 到 registry) | 新方案(no-push 本地构建) |
|
||
| --------------- | -------------------------- | ------------------------------ |
|
||
| workflow 文件数 | 4 个 | 1 个 |
|
||
| 镜像推送 | push 到 Gitea Registry | 不推送 |
|
||
| 部署方式 | compose pull + up | compose up --build |
|
||
| 自建镜像 | 依赖 node-with-docker:22 | 全用官方镜像 |
|
||
| 回滚 | 切换 registry tag | git revert / workflow_dispatch |
|
||
| 构建产物保留 | registry 保留历史 | 不保留 |
|
||
|
||
## 5. 风险与缓解
|
||
|
||
| 风险 | 缓解 |
|
||
| ------------------------- | ---------------------------------------------- |
|
||
| 本地镜像被清理后无法回滚 | 回滚走 git revert + 重新 build,不依赖镜像缓存 |
|
||
| docker.sock 挂载安全风险 | actrunner 仅在部署服务器运行,已隔离 |
|
||
| 构建慢 | layer cache 在宿主机本地,未变更的层秒过 |
|
||
| Gitea workflow_run 不支持 | 用 needs 串联,不用 workflow_run |
|