KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA
06 · 交付形态演进:从脚本到声明式,再到 Agentic DevOps — keel 龙骨
这一章回答:Jenkins、GitLab CI、GitHub Actions、GitOps、Argo CD、Kubernetes、阿里云效……这些名词之间的关系是什么,以及一个具体团队该停在哪种形态。
这一章回答:Jenkins、GitLab CI、GitHub Actions、GitOps、Argo CD、Kubernetes、阿里云效……这些名词之间的关系是什么,以及一个具体团队该停在哪种形态。
技术选型的失败大多来自用别人的形态解决自己的问题:三个人的项目上 K8s 是负担,五十个服务的公司只用 shell 脚本是灾难。这一章给的是匹配依据。
一、四层模型:别把不同层的东西横向比较
④ 编排与调度层 Kubernetes / ECS / Nomad / Docker Compose
↑ 决定容器在哪跑、跑几个、怎么被替换
③ 交付方式层 GitOps(Argo CD / Flux)/ 传统 CD 推送 / 人工执行
↑ 决定"期望状态"存在哪、谁来把现实对齐过去
② 流水线层 GitHub Actions / GitLab CI / Jenkins / 云效 / CircleCI
↑ 决定触发器、作业、缓存、产物、权限
① 基础设施层 Terraform / Pulumi / 云厂商模板
↑ 决定机器、网络、存储这些前置条件
最常见的新手错误是把 GitHub Actions 和 Kubernetes 放在一起比。 它们分别在 ② 和 ④,一个负责"构建与触发",一个负责"运行与调度";两者经常同时使用。
同理,Argo CD 是 ③ 层的东西,它不负责构建与测试(这由 CI 完成),只负责"把 Git 里声明的状态持续对齐到集群"。经典分工是:CI 构建镜像并更新 manifest 里的镜像版本 → GitOps 控制器检测到 Git 变化 → 集群自动跟进。
二、四种交付形态:按团队规模匹配
| 形态 | 描述 | 适合 | 不适合 | 主要成本 |
|---|---|---|---|---|
| 脚本化 | build.sh / deploy.sh,人工执行 |
单服务、单人维护、部署频率低 | 多人协作、需要审计 | 每次路径可能不同,故障难复述 |
| 流水线 CD(push 型) | CI 系统在流水线里执行部署命令 | 绝大多数中小团队(10 人以下、服务数 < 10) | 需要严格审计与 drift 治理 | CI 系统需要部署权限,凭据集中在 CI 侧 |
| GitOps(pull 型) | 集群内的控制器持续从 Git 拉取并对齐状态 | 多集群、多团队、K8s 已就位 | 小规模或非容器场景 | 多一套系统要维护,YAML 治理有学习成本 |
| Agentic DevOps | AI agent 参与流水线执行与修复(见第 1 门课 05 章) | 已有成熟流水线之上的增强 | 基础门禁都没搭好的团队 | 权限与审计复杂度上升 |
push 型 vs pull 型是这里最重要的概念差别:
push 型(CI 驱动): CI 系统持有集群凭据 → 主动执行 kubectl/helm/API
优点:直观、与流水线一体
缺点:凭据集中在 CI;集群外的变更(手工 kubectl)无人察觉
pull 型(GitOps): 集群内的控制器拉取 Git → 无人除外地将集群对齐到声明
优点:凭据不出集群;Git 是唯一事实源;自动发现并纠正配置漂移
缺点:多一层抽象;正在进行金丝雀时应用会显示 OutOfSync(需要用 ignoreDifferences 处理这类字段归属)
三、工具选型的四个真实依据
不要从"哪个工具火"开始,从这四个问题开始:
| 问题 | 影响 |
|---|---|
| 代码托管在哪? | GitHub → Actions 是最短路径;GitLab → GitLab CI;自建 Jenkins 通常因为历史包袱或内网合规要求 |
| 是否需要私有网络/内网部署? | 金融/政企常见:数据不出网 → 自建 runner 或内网 Jenkins/云效 |
| 是否已上 Kubernetes? | 没上:Compose/单机 + 脚本化就够;上了:Helm/Kustomize + Argo/Flux 才有意义 |
| 团队有没有人维护这套东西? | 这一条最容易被忽略。 没有人维护的 Jenkins 会在两年后变成"谁都不敢碰但所有人依赖"的东西 |
国内常见组合示例:GitHub/GitLab + 自建 runner(内网打包)+ 镜像推私有仓库 + Compose 或 K8s 滚动更新 + 云厂商的监控告警。这条路径覆盖了绝大多数中小团队的实际形态,也是你应该能对答如流的一条。
四、声明式带来的三个收益(和一个代价)
收益 ① 可审计:谁在什么时候把什么东西改成什么样,全在 Git 历史里
收益 ② 可回滚:回滚 = revert 一次提交,而不是"记得上次的手工操作"
收益 ③ 自动纠偏:控制器检测到实际状态偏离声明时会自动还原(或告警)
代价 任何东西都要 YAML 化——包括"临时改一下"这种想法的消失
代价那条值得展开:GitOps 会强制所有变更走流程,这在提升了可靠性的同时也会让"快速改一下"变得笨重。 因此生产走严格 GitOps、开发/调试环境保留手动通道,是常见的折中。
实践中的三条防坑规则:
- 自动清理(prune)要谨慎:打开 prune 后,"误删一个 YAML 文件"会直接变成"删掉生产资源"。关键资源用
Prune=false保护,并在 PR 评审阶段检查删除动作。 - 依赖顺序用 sync-wave 声明(CRD 先于自定义资源、命名空间先于其中的对象),否则同步会卡在
Progressing。 - OutOfSync 本身要告警:即使不开启自动纠偏,也要知道漂移正在发生——静默漂移是 GitOps 最大的失败模式。
五、进阶路线图:不要跳跃
阶段 A 脚本 → 流水线: 先把"每次都跑同样的检查"做实
阶段 B 流水线 → 不可变产物: 构建出带有版本与 digest 的产物,先停止在生产机上重新构建
阶段 C 产物 → 环境声明化: Compose/Helm 描述拓扑,配置与密钥外部化
阶段 D 环境 → GitOps 对齐: 控制器持续对齐,漂移自动发现
阶段 E 全套都已成熟时 → Agentic: 让 AI 参与失败归因、测试生成、自动修复,边界见第 1 门课 05 章
每个阶段都要先回答:"没有它,当前最痛的问题是什么?" 答不上来就不要上——因为下一阶段的复杂度是实打实要付的。
六、结合你的情况:怎么谈"我们公司没有这些"
面试时坦诚的分层话术(按顺序说,效果最好):
- 先讲现状:公司项目当时是"Compose + Nginx + 脚本化部署 + 日志轮转 + 值班窗口",规模和技术栈决定它在阶段 A/B 之间。
- 再讲自己做到哪一档:在开源项目里完整跑通了阶段 A 到 B,包括产物不可变、幂等发布、OIDC 免长期令牌、发布前产物冒烟。
- 然后讲取舍判断:不是所有团队都需要 GitOps——我会在什么条件下引入(多服务多集群、需要审计与漂移治理时),以及在什么条件下不引入(小规模、没有人专职维护 K8s)。
- 最后讲边界:没在线上百台规模验证过的东西,我不吹。
这套话术的杀伤力在于:它同时展示了做过、懂取舍、且诚实。 面试官分辨的是"背过理论"和"知道什么时候不该用",第 3 点通常是最缺的那部分。
动手:可观察结果
| 动作 | 产出物 | 判断标准 |
|---|---|---|
| 画出自己项目所处的层与形态 | 一张四层标注图 | 能指出哪一层缺失、缺了它的具体代价 |
| 对比 push 型与 pull 型 | 一份差异表 | 能回答"凭据在哪、漂移怎么被发现" |
| 写一份工具选型说明 | 一页 rationale | 至少回答四个依据中的三个 |
| 手工改一次集群里的某个字段 | 一次自动纠偏演示 | 手工改动集群后,控制器将其纠正回来 |
| 列出自己想引入下一阶段的触发条件 | 条件清单 | 条件是客观的(服务数/团队数/审计要求),不是"因为它很火" |
故障注入
| 注入方式 | 观察什么 | 说明的现象 |
|---|---|---|
| 手工 kubectl 改一个生产字段 | GitOps 是否发现并纠正 | 发现不了 → 漂移开始累积 |
| 打开 prune 然后误删一个 YAML | 对应的生产资源是否被删 | 这就是 prune 的风险;关键资源应被保护 |
| 把 CI 的部署凭据配置得过宽 | 谁能用它做什么 | 集中式凭据是 push 型最大的软肋 |
| 同步顺序依赖没声明 | sync 是否卡住 | CRD/命名空间顺序错误会卡在 Progressing |
| 为小规模项目强行引入 K8s | 半年后谁在维护它 | 没人维护的平台=团队风险源 |
自测题
- GitHub Actions 与 Kubernetes 分别属于四层模型里的哪一层?为什么不能横向比较?
- push 型 CD 与 GitOps pull 型在"凭据放在哪"和"漂移怎么被发现"上有什么区别?
- GitOps 的自动清理(prune)会带来什么具体的风险?怎么防?
- 工具选型四问中,哪一问最容易被忽略?忽略后通常怎么收场?
- 面试官问"你们公司没有 CI/CD"时,你的四步分层话术是什么?