综合练习
这一课你将能做到
- 为本站 monorepo 拼出完整 CI:
backend 与 platform 并行,触发与 paths 合理,缓存与产物就位
- 列出 CD 选件清单(Docker→GHCR、GitOps bump、SSH 备选)与对应 secrets,并写进仓库文档草稿
- 用
helm template 与 Actions 日志完成一次「从失败到复绿」的排错演练
为什么要学
前面每课拆开讲:workflow、job、step、secret、缓存、Java、Node、镜像、部署、PR 门禁。真正干活时它们必须在一份(或两份)YAML 里协作,还要能向队友说明「红了看哪」。
本课不引入新概念,而是把已学零件装回本站仓库叙事:backend/ + platform/ + deploy/ + 可选 GitOps。完成后,你应能在真实仓库启用流水线,并向别人完整讲出从 push 到上线的链路。
先建立图像
目标架构(教学版)
.github/workflows/
ci.yml → PR/push:backend verify ∥ platform lint/test/build
docker.yml → main:build-push GHCR(needs 测试或信任受保护的 main)
(可选)gitops-bump.yml → PR 更新 deploy/env/prod/*-values.yaml 的 tag
deploy/
charts/backend/
env/dev|prod/*-values.yaml
Secrets(按需)
GITHUB_TOKEN(内置)
SSH_PRIVATE_KEY / DEPLOY_HOST / DEPLOY_USER(若 VPS)
(避免长期全能 kubeconfig,优先 GitOps)
人话:CI 是每天必跑的门禁;Docker/GitOps 是发车流程;secrets 是钥匙串——钥匙越少越好,门禁越硬越好。
| 验收项 | 通过标准 |
|---|
| CI | PR 上 backend、platform 可设为 required |
| 缓存 | 第二次跑明显依赖加速 |
| 镜像 | main 能推 sha tag(若启用 docker.yml) |
| 部署叙事 | 能画出本站选的 Push 或 GitOps 路径 |
| 文档 | README 有「如何看 Actions 日志排错」小节 |
跟着做
步骤 1:落地 ci.yml 双 job
按前几课合并最小可行版:
name: CI
on:
pull_request:
branches: [main]
paths:
- 'backend/**'
- 'platform/**'
- '.github/workflows/**'
push:
branches: [main]
paths:
- 'backend/**'
- 'platform/**'
- '.github/workflows/**'
workflow_dispatch:
permissions:
contents: read
jobs:
backend:
runs-on: ubuntu-latest
defaults:
run:
working-directory: backend
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "21"
cache: maven
- run: |
chmod +x mvnw
./mvnw -B verify
platform:
runs-on: ubuntu-latest
defaults:
run:
working-directory: platform
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
cache-dependency-path: platform/package-lock.json
- run: npm ci
- run: npm run lint
- run: npm test
- name: build
env:
NEXT_PUBLIC_API_BASE: http://localhost:8080
run: npm run build
步骤 2:打开分支保护
Settings 中把 backend 与 platform(以实际 check 名为准)设为 required,才能合入 main。用一次故意失败验证「挡合并」,修复后复绿。
步骤 3:CD 清单勾选(选做但要写明)
在笔记或 docs/ci.md 草稿中勾选你启用的路径:
仓库若已有 docker.yml / bump 工作流:读懂并补文档,优先于推倒重来。
步骤 4:渲染 Helm 确认 values 有意义
helm template backend ./deploy/charts/backend \
-f deploy/env/dev/backend-values.yaml
在输出中定位镜像字段;想象把它改成新 sha 后,Argo 会拉取什么。这步保证「改 values」不是在改一个无效字段。
步骤 5:排错演练(必做口述)
- 打开 Actions → 失败 run → 失败 job → 失败 step
- 读该 step 最后 50 行,判断是依赖、测试断言还是 env 问题
- 本地复现同一命令(
./mvnw -B verify 或 npm run build)
- 修复 → push → 看 PR check 复绿
把这四步写进 README 的「如何看 Actions 日志排错」小节。
步骤 6:路线图与 secrets 表收尾
- 在 devops / full-stack 路线图勾选 GitHub Actions 节点
- 贴一张 secrets 表(只有名字与用途,无真实值):
| Name | 用途 |
|---|
GITHUB_TOKEN | 内置;推 GHCR 需配 packages: write |
SSH_PRIVATE_KEY | VPS 部署(若用) |
DEPLOY_HOST / DEPLOY_USER | VPS 地址与账号 |
| (无)长期全能 kubeconfig | 用 GitOps 代替 |
git → docker → kubernetes → helm-gitops → github-actions
讲清楚要点
- 因为零件课不等于系统,所以最后要用一份真实 ci.yml 把 Java 与 Node 门禁并列起来——这才是 monorepo 门禁的完整定义。
- 因为没有分支保护就没有强制力,所以练习必须包含 required checks——红测不可合。
- 因为 CD 有多条路,所以综合练习要求「选型写清楚」而不是假装只有一种正确——SSH 与 GitOps 都可,但密钥模型完全不同。
- 因为镜像与 values 解耦,所以只推 GHCR 不等于已部署——还要改声明并触发同步。
- 因为故障会落在日志里,所以排错顺序是从失败 step 反推到本地命令——少盲目点 Re-run 白烧分钟。
- 因为文档是团队记忆,所以 secrets 清单与排错入口应留在仓库——比躺在聊天记录里持久。
你可能会懵的地方
-
「仓库已经有 workflow,还要不要按课文覆盖?」
以仓库现况为准:能跑通就对照课文查缺补漏,缺失才添加。本课目标是能力,不是制造重复文件战争。
-
「paths 导致文档 PR 不能合?」
required check 因 paths 未运行会永久卡住。策略:文档也触发一个轻量 job,或放宽 paths,或调整保护规则。这是综合阶段的头号坑。
-
「本地绿、CI 红,查什么?」
顺序:Node/JDK 版本是否与 CI 钉的一致 → 锁文件是否提交 → 是否依赖本机 .env → 行尾符/文件权限(mvnw 可执行位)。
-
「综合练习要不要真推生产?」
不必。验收停在:CI 绿、保护开启、部署路径能讲清。真推送应在有权限的环境里由你主动执行,并提前想好回滚。
错法对照
| 错法 | 问题 | 正解 |
|---|
| 只写 backend CI | 前端回归漏检 | 双 job 并行 |
| 有 YAML 无保护规则 | 门禁形同虚设 | require checks |
| 推镜像当完成部署 | 环境可能未变 | values/GitOps 或明确 SSH 步骤 |
| 排错只点 Re-run | 重复烧分钟,错误复现 | 先读失败 step 再本地复现 |
卡点急救
- workflow 改坏了 main 上的流水线:因为分支保护管不住
.github/workflows/ 的直接修改(或你临时关了保护),先回滚该 merge commit 或 revert;之后把 ci.yml 的修改也纳入 PR 流程,并给流水线文件设置 CODEOWNERS 指定审阅人。
- 私有仓库分钟数告急:开
paths 过滤 + concurrency 取消过时 run;缓存依赖;把 matrix 砍到必要版本;若仍紧张,评估把高频检查留给本地 pre-push 钩子,CI 只做门禁级验证。
- 多人协作时 check 名对不上:统一在 README 记录「本仓库 required checks 清单」;job 改名必须同步更新分支保护并在 PR 描述里提醒全员。
面试常问
-
完整讲述「从 push 到上线」你们仓库的流水线设计。
参考答案(可背):开发者 push 或开 PR → Actions 触发 CI:backend 与 platform 两个 job 并行,各自干净 runner 上 checkout、装 JDK21/Node20(带依赖缓存)、跑 mvnw verify 与 npm ci/lint/test/build;两个 job 都绿且 PR 通过分支保护(required checks + review)才能合入 main;main 的 push 触发 Docker workflow,多阶段构建镜像并推 GHCR,tag 用 commit sha;随后(GitOps)自动开 PR 更新 deploy/env/prod 的 image.tag,人审合并后 Argo CD 同步集群拉新镜像;出问题按 sha 回滚或 revert bump PR。每个环节都能答出「为什么这么设计」。
-
如果 CI 经常失败或很慢,你会怎么系统性优化?
先分类再动手:失败类——区分环境差异(版本/锁文件/env)、时序问题(服务未就绪)、真 bug,用「本地复现同命令」收敛;耗时类——并行化 job、依赖与层缓存、paths 过滤、concurrency 取消、分级门禁(PR 快检查、main 全量);可观测类——每个 job 加 timeout、日志可读命名、失败 step 直接跳转。优化的前提是先有数据:看 run 历史的 job 耗时分布,不凭感觉。
-
新人入职第一天,你会给他哪些「看懂这条流水线」的文档?
三份:① README 的流水线小节——两个 workflow 的职责与触发规则、required checks 清单;② secrets 表——每个名字的用途与 owner(不含值);③ 排错四步——失败 run → 失败 step → 本地复现 → 修复复绿。目标是新人 30 分钟内能独立看懂红的 PR 并知道自己该修哪。
自测三问
- 默写 ci.yml 里 backend 与 platform 两个 job 的关键步骤关键词。
- 若 required check 因
paths 没跑出来,会发生什么?三种处理方式是什么?
- 用五句话讲述本站从 push 到(GitOps)上线的完整链路。
小结一句话
双端并行 CI + 分支保护是底线;Docker/GitOps/SSH 是可选 CD;会读日志才算真正会用 Actions。
延伸