| 维度 | 推式(Push) | 拉式(Pull / GitOps) |
|---|---|---|
| 谁执行部署 | CI 流水线 | 生产环境内的 Agent |
| 凭据在哪 | CI 侧(GitHub Secrets) | 生产侧(Agent 本地) |
| 安全模型 | CI 信任 → 生产 | 生产自治,CI 不信任 |
| 典型工具 | GitHub Actions + SSH/kubectl | Argo CD, Flux |
| 适用场景 | 小团队、早期项目、简单主机部署 | 中大规模、K8s 原生、多环境 |
| kubectl apply 在哪跑 | CI 里(已过时 ❌) | 集群内 Agent 里(推荐 ✅) |
为什么说"CI 里跑 kubectl apply"已过时?
文章目录
- 为什么说"CI 里跑 kubectl apply"已过时?
- 1. 🔐 安全风险 — "CI 信任 → 生产"模型脆弱
- 2. 🔁 状态漂移无法自愈
- 3. 🚫 网络打通困难
- 4. 📦 可观测性差
- 5. 🧪 环境一致性难保证
- 一句话总结
- ⚠️ 但也不是"绝对过时"
为什么说"CI 里跑 kubectl apply"已过时?
这主要源于安全性、可观测性和运维实践的演进。以下是核心原因:
1. 🔐 安全风险 — "CI 信任 → 生产"模型脆弱
| 问题 | 说明 |
|---|---|
| 凭据暴露面大 | CI 系统(如 GitHub Actions)需要持有生产集群的 kubeconfig/token,一旦 CI 被攻破(供应链攻击、恶意 PR 触发 workflow),生产集群就暴露了 |
| 权限难以收敛 | CI 需要集群级写权限,违反最小权限原则 |
| 审计困难 | 谁、何时、部署了什么,散落在 CI 日志里,难以统一审计 |
2. 🔁 状态漂移无法自愈
CI: kubectl apply → 完事 ✅ (然后就不管了)- CI 是一次性触发的,apply 完就结束了
- 如果有人手动改了集群(
kubectl edit),或者节点异常导致 Pod 挂了,CI 不会感知,也不会修复 - 结果:实际状态 ≠ Git 声明状态(状态漂移)
而Pull 模式(Argo CD / Flux)的 Agent 持续在集群内运行:
Agent: 每隔 N 秒 diff Git vs 集群 → 发现漂移 → 自动 reconcile ✅3. 🚫 网络打通困难
- CI 跑在公网(GitHub Actions 的 runner IP 不固定),要访问生产集群需要:
- 开放 API Server 公网端口(危险)
- 或者搭 VPN / Tunnels(增加复杂度)
- Pull 模式的 Agent从集群内部主动拉取 Git 仓库,不需要入站连接,网络模型更安全
4. 📦 可观测性差
| CI 推式 | GitOps 拉式 |
|---|---|
| 部署成功与否看 CI 日志 | Argo CD UI 实时展示所有资源状态、健康度、diff |
| 无统一视图 | Git 是唯一真相源(Single Source of Truth) |
| 回滚 = 重新跑 CI | 回滚 =git revert,Agent 自动同步 |
5. 🧪 环境一致性难保证
- CI 里的
kubectl版本、kustomize 版本、helm 版本可能与本地开发不一致 - Pull 模式的 Agent 运行在集群内,版本固定、环境一致、可复现
一句话总结
“CI 里 kubectl apply” = 把生产集群的钥匙交给一个临时的、不可控的外部系统,然后祈祷它不会被滥用。
“Agent 里 kubectl apply” = 集群自己看着 Git,自治、自愈、自闭环。
这就是为什么 Argo CD、Flux 等 GitOps 工具成为中大规模 K8s 部署的事实标准。
⚠️ 但也不是"绝对过时"
对于小团队、早期项目、单机 Docker/SSH 部署,CI 推式仍然够用且简单。表格也标注了这一点。"过时"更多指的是在 K8s 原生、多环境、中大规模场景下的最佳实践已经转向 Pull 模式。