# 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 && 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 |