ArgoCD 常见问题与解决方案:我踩过的坑和填坑方法
一开始的问题
去年我们团队把三十多个微服务迁到 ArgoCD 做持续部署,本以为就是“装好、连上 Git、点个 Sync”的事。结果第一个月我就被半夜叫醒三次:应用卡在 Progressing、镜像明明推了却不更新、还有一次同步直接把生产数据库的 Secret 给清了。这篇文章就是把我踩过的坑,连同排查和解决办法,一次性讲清楚。
问题一:镜像推了,但 ArgoCD 不更新
这是我们遇到频率最高的问题。CI 流水线显示镜像已推送到 Harbor,但集群里的 Pod 还是旧版本。
排查第一件事:先看 ArgoCD 究竟认为 Git 里应该是什么。打开 Application 详情页,对比 Desired Manifest 和 Live Manifest。如果两者一致,说明 Git 内容没变——问题在 Git 侧,不在 ArgoCD。
最常见的根因是:CI 更新了 Git 仓库里的 tag,但 ArgoCD 默认三分钟才轮询一次。我们的 CI 里写了 git commit && git push,然后立刻检查部署状态,当然查不到。两种解法:
方案 A:Webhook。在 Git 仓库配置 webhook 指向 https://<argocd-server>/api/webhook,并在 ArgoCD 里配好 Git 凭证。配完后推送基本秒级触发同步检测。
方案 B:CI 结束时手动刷新:
argocd app get my-app --refresh
argocd app sync my-app
另一个隐蔽的坑:镜像 tag 用了 latest 或可变 tag。ArgoCD 是声明式的,Git 里写 latest,实际运行镜像变了,Git 和集群看起来“一致”,ArgoCD 认为无事可做。解决办法是每条流水线用不可变 tag(比如 git-sha 或时间戳),或者启用 Image Updater。我们最终用 git commit sha 作为 tag,可追溯性也更好。
问题二:Application 一直卡在 Progressing
有一次一个应用卡了四十分钟。kubectl get pods 看都是 Running 的,但 ArgoCD 状态就是 Healthy: Progressing。
原因:ArgoCD 判断健康状态靠的是内置的健康检查逻辑,主要看 Deployment 的 replicas 是否全部 ready。我们有个 Deployment 配了 readinessProbe 指向一个返回 500 的接口——Pod 是 Running,但永远 Not Ready。所以记住:卡 Progressing 时先看 Pod 是否真正 Ready,再看探针配置。
还有一类更诡异的情况:用了 kind: Job 或 CronJob 的资源。ArgoCD 对这些资源默认的健康判断有延迟。可以在 Application 的 diff 里确认没有实际差异,然后等 Job 完成即可。必要时给资源加注解:
metadata:
annotations:
argocd.argoproj.io/ignore-healthcheck: "true"
不过这个要慎用,掩盖问题不如修复问题。
问题三:OutOfSync 死循环
有个应用同步完几秒又变 OutOfSync,无限循环。argocd app diff my-app 显示 Helm 渲染的值每次都不一样——具体是我们的 Chart 里有个字段生成了随机值(比如 randAlphaNum 生成的密码)。
解法是加 ignoreDifferences:
# argocd-ignore.yaml (Application 里配置)
spec:
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas
这里我顺便加了 replicas 的忽略,因为 HPA 在动态调副本数,ArgoCD 总想把它改回 Git 里写的数字——这是另一个经典问题:用 HPA 时必须忽略 replicas 字段,否则 HPA 和 ArgoCD 会打架。
另外还有自动 pruning 引发的惨案:有一次我重构目录,把一个 Service 资源从 Chart 里删了,ArgoCD 自动同步时直接把生产 Service 删了。从那以后我规定:自动同步开启的情况下,selfHeal 可以开,但 prune 必须关,删除资源一律手动确认:
syncPolicy:
automated:
selfHeal: true
prune: false
问题四:Secret 管理和“明文进 Git”
GitOps 的原则是 Git 是唯一事实来源,但没人想把数据库密码明文提交。我们试过 Sealed Secrets,后来换成了 External Secrets Operator + Vault 的组合,Git 里只放 ExternalSecret 资源。这里注意一个问题:ArgoCD 默认会把 Secret 的 data 显示在 diff 里(虽然是混淆过的),建议配置:
resource.customizations:
secret.argoproj.io/Secret:
health.lua: ...
或者更简单地,在 Application 级别对 Secret 资源启用忽略。新版 ArgoCD 默认对 Secret data 做脱敏,确认你的版本 ≥ 2.x 即可。
问题五:App-of-Apps 与层级失控
服务多了以后,Application CRD 本身的管理成了问题。我们用 app-of-apps 模式:一个根 Application 指向一个专门存 Application 清单的仓库。这里有个坑:根应用删除子应用时,默认不会级联删除,会留下孤儿资源。给子应用的删除加级联,需要确认 cascade 行为,同时建议对所有 Application 资源加 finalizers 的理解——加了 resources-finalizer.argocd.argoproj.io 后,删 Application 会删真实资源,不加则只删记录。搞混这个的后果要么是资源泄漏,要么是误删。
实用技巧汇总
- 先看 diff 再动手:
argocd app diff <app>能解决 80% 的“为什么不同步”。 - 硬刷新:怀疑缓存问题时,UI 里点 Hard Refresh,或
argocd app get <app> --refresh --hard。 - 开启自动同步前先手动同步观察几天。
- 给每个环境独立的项目和仓库权限,用 ArgoCD 的 Project 做 RBAC,别都塞 default project。
- 保留一个紧急逃生通道:文档里写清楚
argocd app sync <app> --force的使用场景——它会在不比较的情况下直接 apply,仅限事故恢复。
诚实的评价
ArgoCD 大幅降低了我们对“谁在集群里改了什么”的焦虑,审计能力是实打实的。但它不是免维护的:健康检查逻辑偶尔和真实情况脱节,Helm 变量渲染和 Git diff 的对齐需要精心配置 ignoreDifferences,Secret 管理方案必须提前设计好而不是事后补救。如果你团队规模小、服务少于十个,一个简单的 CD 脚本可能更划算;一旦服务多了、多环境了、多人协作了,ArgoCD 的声明式模型回报会非常大。建议从非关键服务开始灰度接入,把本文这几个坑在测试环境先趟一遍。