为什么我放弃了传统方案,改用 ArgoCD

devops进阶9 分钟阅读2026/10/24

为什么我放弃了传统方案,改用 ArgoCD

一切始于一次凌晨三点的发布事故

先说说我是怎么“入坑” ArgoCD 的。

去年我们团队维护着一套十几个微服务的 Kubernetes 集群,部署方式是很多公司都熟悉的组合:CI 流水线(Jenkins)在构建完成后,执行一段 kubectl apply -f k8s/ 的脚本。听起来很简单对吧?

问题出现在一个周五晚上。一个同事改了 Deployment 的副本数,想临时扩容应对流量高峰。改完之后不到十分钟,流水线恰好因为另一个不相关的提交被触发,kubectl apply 一跑,副本数直接被打回去了。线上服务响应变慢,告警响到凌晨。

事后复盘时我们发现了一个更深层的问题:集群里的实际状态,和 Git 仓库里的声明,早就对不上了。有人在集群里手动改过 resource limits,有人用 kubectl edit 紧急改过环境变量,这些变更都没有回到代码仓库。Git 说是 A,集群跑的是 B,谁也不知道哪个才是“真相”。

这就是我决定认真研究 GitOps 和 ArgoCD 的直接原因。

传统 CI 部署方式的几个痛点

在动手之前,我先总结一下当时方案的四个问题,你可以对照看看自己是不是也中招了:

  1. 推模式(Push)没有兜底:CI 推完一次就完事了。之后集群里发生任何漂移,没人知道,也没人纠正。
  2. 凭证散落各处:Jenkins 需要 kubeconfig 或 ServiceAccount token 才能操作集群,CI 服务器一旦被攻破,等于把整个集群交出去了。
  3. 发布状态不透明:“现在线上跑的是哪个版本的配置?”这个问题要靠人肉去集群里查。
  4. 回滚靠嘴喊:回滚要么 re-run 旧流水线,要么手动 kubectl rollout undo,和 Git 历史完全脱节。

第一次尝试:踩的坑比想的多

安装与初始配置

安装本身很顺利:

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

然后我做的第一件事是改默认 admin 密码(这一步别忘,不然 admin 密码就是 argocd-server Pod 的名字,任何能看到 Pod 列表的人都能登录):

argocd account update-password

接着我在 UI 里创建了第一个 Application,指向我们的 Git 仓库。同步成功,Pod 起来了——当时我觉得这也太简单了。

第一个坑:Application 卡在 OutOfSync 死循环

第二天问题来了。ArgoCD 一直显示某个 Deployment 是 OutOfSync,自动同步反复执行,改了又改。

原因是我们的 Helm chart 会往 Deployment 里注入一个带时间戳的 annotation,每次渲染出来的结果都不一样。ArgoCD 一对比:“诶,不一样”,就同步;同步完渲染又是新时间戳,又不一样……无限循环。

解决办法是在 Application 里配置 ignoreDifferences:

ignoreDifferences:
  - group: apps
    kind: Deployment
    jsonPointers:
      - /spec/template/metadata/annotations

或者更根本一点,把 chart 里那个时间戳直接删掉。我们选了后者,因为给 ArgoCD 喂“确定性”的渲染输出,比不停地打补丁健康得多。

第二个坑:CRD 不会被自动同步

我们用了一堆 CRD(Prometheus Operator 的、Istio 的)。第一次同步后我天真地以为万事大吉,结果后来升级 Operator 时才发现 CRD 版本停在了旧版本上。

ArgoCD 默认不管 CRD 的更新(只管首次安装)。解法是用 argocd app sync --resources 显式同步,或者把 CRD 放到一个单独的、用 Replace=true 同步策略的 Application 里专门管理。这也是我后来形成的一个架构习惯:CRD 单独一个 Application,和业务应用解耦。

第三个坑:Secret 不能明文进 Git

GitOps 的一切都在 Git 里,那数据库密码怎么办?总不能明文提交吧。

我们试了两个方案:

  • Sealed Secrets:用集群的公钥加密,只有集群内的 controller 能解密。简单,但密钥轮换麻烦,密文和集群绑死了。
  • External Secrets Operator:Git 里只存 ExternalSecret 引用,真实值放在 Vault 或云厂商的 Secrets Manager 里。

我们最终选了后者。Git 里长这样:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: payment-db
spec:
  secretStoreRef:
    name: vault-backend
    kind: ClusterSecretStore
  target:
    name: payment-db-credentials
  data:
    - secretKey: password
      remoteRef:
        key: payment/db
        property: password

稳定下来后的仓库结构

踩完坑之后,我们的仓库长这样,推荐直接抄:

gitops-repo/
├── apps/                    # 每个 Application 一个文件
│   ├── payment.yaml
│   └── order.yaml
├── clusters/
│   ├── prod/
│   └── staging/
└── services/
    ├── payment/
    │   ├── Chart.yaml
    │   ├── values.yaml          # 公共默认值
    │   ├── values-prod.yaml
    │   └── values-staging.yaml
    └── order/
        └── ...

核心技巧是 App of Apps 模式:一个根 Application 指向 apps/ 目录,里面每个文件定义一个子 Application。新服务上线只需要加一个 YAML 文件,ArgoCD 会自动发现并部署。

每个 Application 的关键配置:

syncPolicy:
  automated:
    prune: true        # Git 里删了资源,集群里也删
    selfHeal: true     # 有人手动改集群,自动改回来
  syncOptions:
    - CreateNamespace=true

selfHeal: true 就是对我那次凌晨事故的直接回应——现在再有人在集群里手动改东西,ArgoCD 会在几分钟内把它掰回 Git 声明的状态。注意 prune: true 要慎用,建议先在 staging 集群上开,prod 环境观察一段时间再说。

回滚体验:这是我最满意的部分

现在回滚是这样的:git revert 那个提交,push,ArgoCD 自动同步,完事。整个回滚有完整的审计记录,和代码历史完全一致。发版日再也不用有人盯着流水线了——合并到 main 分支就是发布,ArgoCD 大约三分钟内就能收敛到目标状态。

实用建议

  1. 渐进式迁移:先让 ArgoCD 以“只读”方式接入现有集群(automated 关掉),观察它报的 drift,清理干净后再开自动同步。
  2. 用 sync window 限制发布时段:我们给 prod 配了工作时间段同步窗口,周五晚上想发布?ArgoCD 会给你排到下周一。
  3. 前置 hook 处理数据库迁移:Job 类型加上 argocd.argoproj.io/hook: PreSync,同步前自动跑 migration。
  4. 保留 CI:ArgoCD 只接管 CD,构建、测试、打镜像仍然在 CI 里做。ArgoCD Image Updater 可以监控新镜像并自动更新 Git 里的 tag,形成闭环。

诚实的局限性

  • 多集群管理有学习成本:官方推荐用 ApplicationSet,但概念不少,我们花了两三周才理顺。
  • UI 有误导性:UI 上的资源树很好看,但复杂应用的同步失败原因藏得很深,最终还是得看 argocd app diff 和 controller 日志。
  • 不是所有资源都适合 GitOps:比如频繁变更的配置中心数据,硬塞进 Git 会让仓库变成垃圾场,这类东西还是留给专业的配置服务。
  • 团队纪律是前提:GitOps 的价值建立在“Git 是唯一事实来源”上。如果有人还是习惯 kubectl apply,那一切白搭。我们是通过把开发者的 kubeconfig 收紧成只读权限来强制执行的。

一句话总结:ArgoCD 解决的不是“怎么部署”,而是“怎么让集群永远和你说的一致”。如果你的团队已经体会过配置漂移的痛,那它值得这份迁移成本。

相关 Agent

D

Docker

Docker 是一个容器化平台,允许开发者将应用及其依赖项打包成轻量级、可移植的容器。它简化了跨环境的开发、测试和部署过程。该描述强调它最适合容器化和开发环境,提供免费方案和团队方案,团队方案从每用户每月5美元起。

了解更多 →