TT Lab
开始
学习 学习路径 课程

GitOps 与 Argo CD

因为总是 OutOfSync 就忽略,结果真正的漂移也看不见了

在 TT Lab 中继续学习

目标

亲手在 argocd-cm 和 Application 这两处编写忽略规则,并用 CLI 的 diff 确认规则实际会把哪些行从比较中排除。亲眼看一看忽略得太宽时,会有什么东西跟着一起消失。

为什么重要

启用自动同步之后,很快就会遇到“总是 OutOfSync”。原因是 HPA 修改的 replicas、Webhook 插入的 sidecar、控制器添加的注解——这些东西无法写进仓库,却必然会出现在集群里。忽略规则就是处理它们的工具,但它有一种只往一个方向倾斜的力——忽略得宽,界面就安静下来;忽略得窄,界面就一直吵闹。 所以每个人都会倒向宽的一侧。宽规则的代价不会马上显现,要等到几个月后有人手工改了镜像却没有人知道的那一天才会暴露。养成习惯,不靠猜测来写规则,而是亲眼确认“这条规则会删掉的行”之后再提交,就能避免这个代价。

步骤

  1. 在 /root/ga-ignore/live.yaml 中创建 ga-ignore 命名空间的 Deployment web——spec.replicas 为 4,容器有两个:app(镜像 nginx:1.25)和 sidecar(镜像 envoy:1.31),并在 metadata.annotations 中放置 deployment.kubernetes.io/revision: "7"。/root/ga-ignore/argocd-cm.yaml 是 data: {} 的空 ConfigMap。把 argocd admin settings resource-overrides ignore-differences /root/ga-ignore/live.yaml --argocd-cm-path /root/ga-ignore/argocd-cm.yaml 的输出保存到 /root/ga-ignore/none.txt。
  2. 在 /root/ga-ignore/argocd-cm-pointer.yaml 中放置键 resource.customizations.ignoreDifferences.apps_Deployment,并用 jsonPointers 只忽略 /spec/replicas 一项。把针对 /root/ga-ignore/live.yaml 的输出保存到 /root/ga-ignore/pointer.txt。
  3. 在 /root/ga-ignore/argocd-cm-jq.yaml 中用一个 jqPathExpressions,只忽略名称为 sidecar 的容器的 image。把输出保存到 /root/ga-ignore/jq.txt。app 容器的镜像不能被排除。
  4. 在同一个 /root/ga-ignore/argocd-cm-both.yaml 中同时放置 jsonPointers(/spec/replicas)和 jqPathExpressions(sidecar 镜像),并把输出保存到 /root/ga-ignore/both.txt。两者都要被排除,而 app 容器的镜像必须保留。
  5. 在 /root/ga-ignore/argocd-cm-wide.yaml 中用 jsonPointers 忽略 /spec 整个,并把输出保存到 /root/ga-ignore/wide.txt。这份输出里连容器镜像那一行都包含在内——也就是说,即使有人偷偷修改镜像,也不会被比较发现。
  6. 在 /root/ga-ignore/argocd-cm-mfm.yaml 中用 managedFieldsManagers 只放 kubectl 一项,并把输出保存到 /root/ga-ignore/mfm-only.txt。接着在 /root/ga-ignore/argocd-cm-mfm2.yaml 中同时放置同样的 managedFieldsManagers 和 jsonPointers(/metadata/annotations),并把输出保存到 /root/ga-ignore/mfm-plus.txt。看一看两份输出有什么不同。
  7. 在同一个 /root/ga-ignore/argocd-cm-updates.yaml 中放置两个键——resource.customizations.ignoreDifferences.apps_Deployment 用 jsonPointers 忽略 /spec/replicas,resource.customizations.ignoreResourceUpdates.apps_Deployment 用 jsonPointers 忽略 /metadata/annotations。针对同一个文件,把 ignore-differences 的输出保存到 /root/ga-ignore/updates-diff.txt,把 ignore-resource-updates 的输出保存到 /root/ga-ignore/updates-upd.txt。
  8. 在 /root/ga-ignore/application.yaml 中创建 Application ga-ignore-web(命名空间 argocd,项目 default),并应用到 kwok 集群。在 spec.ignoreDifferences 中放一个 group 为 apps、kind 为 Deployment 的条目,其中同时放入 /spec/replicas 指针和用来选出 sidecar 镜像的 jq 表达式。然后在 /root/ga-ignore/ignore-matrix.tsv 中写至少四行 <ConfigMap파일>\t<찾을 글자>\t<yes|no>(占位符依次为 ConfigMap 文件、要查找的字符、yes 或 no),用 /root/ga-ignore/check-ignore.sh 全部检查,并把输出保存到 /root/ga-ignore/ignore-result.txt。脚本只写到标准输出,只要有一行不匹配就必须以非 0 退出码结束。

参考

先看没有规则时的输出

在 /root/ga-ignore/live.yaml 中创建 ga-ignore 命名空间的 Deployment web——spec.replicas 为 4,容器有两个:app(镜像 nginx:1.25)和 sidecar(镜像 envoy:1.31),并在 metadata.annotations 中放置 deployment.kubernetes.io/revision: "7"。/root/ga-ignore/argocd-cm.yaml 是 data: {} 的空 ConfigMap。把 argocd admin settings resource-overrides ignore-differences /root/ga-ignore/live.yaml --argocd-cm-path /root/ga-ignore/argocd-cm.yaml 的输出保存到 /root/ga-ignore/none.txt。

如果一条规则都没有,这条命令不会编造判定,而是说“没有配置”。后面的步骤会一直把这个文件当作材料,所以请把值设置准确。

指向一个字段并把它排除

在 /root/ga-ignore/argocd-cm-pointer.yaml 中放置键 resource.customizations.ignoreDifferences.apps_Deployment,并用 jsonPointers 只忽略 /spec/replicas 一项。把针对 /root/ga-ignore/live.yaml 的输出保存到 /root/ga-ignore/pointer.txt。

JSON 指针是沿斜杠向下的路径。输出中以 < 开头的行就是“被排除在比较之外的行”——只应少掉 replicas 这一行,容器镜像必须原样保留。

要在数组中按条件挑选,只有 jq 可以

在 /root/ga-ignore/argocd-cm-jq.yaml 中用一个 jqPathExpressions,只忽略名称为 sidecar 的容器的 image。把输出保存到 /root/ga-ignore/jq.txt。app 容器的镜像不能被排除。

JSON 指针只能按位置编号指向数组,所以顺序一变,就会忽略掉不该忽略的元素。用 jq 表达式则可以像 select(.name == "sidecar") 这样按条件挑选。表达式请从 .spec.template.spec.containers[] 开始写。

在一条规则中同时使用两种方式

在同一个 /root/ga-ignore/argocd-cm-both.yaml 中同时放置 jsonPointers(/spec/replicas)和 jqPathExpressions(sidecar 镜像),并把输出保存到 /root/ga-ignore/both.txt。两者都要被排除,而 app 容器的镜像必须保留。

针对同一个类型的规则块只有一个,两个列表并排放在其中。如果想把规则按类型拆成多个块,键会重复,只剩后面那一个。

忽略得太宽,漂移就永远看不到

在 /root/ga-ignore/argocd-cm-wide.yaml 中用 jsonPointers 忽略 /spec 整个,并把输出保存到 /root/ga-ignore/wide.txt。这份输出里连容器镜像那一行都包含在内——也就是说,即使有人偷偷修改镜像,也不会被比较发现。

消除 OutOfSync 最快的办法就是忽略得宽,所以这也是现场最常犯的错误。请比较第 4 步的输出和这份输出里是否能看到 nginx 这个字符串。

按管理者名称忽略的规则无法预览

在 /root/ga-ignore/argocd-cm-mfm.yaml 中用 managedFieldsManagers 只放 kubectl 一项,并把输出保存到 /root/ga-ignore/mfm-only.txt。接着在 /root/ga-ignore/argocd-cm-mfm2.yaml 中同时放置同样的 managedFieldsManagers 和 jsonPointers(/metadata/annotations),并把输出保存到 /root/ga-ignore/mfm-plus.txt。看一看两份输出有什么不同。

这条规则是按“是谁写的字段”而不是按“哪个字段”来决定要忽略的对象。所以光看资源 YAML 算不出会排除什么,预览命令仅凭这个列表也什么都渲染不出来。

同步判定与唤醒调谐循环是不同的旋钮

在同一个 /root/ga-ignore/argocd-cm-updates.yaml 中放置两个键——resource.customizations.ignoreDifferences.apps_Deployment 用 jsonPointers 忽略 /spec/replicas,resource.customizations.ignoreResourceUpdates.apps_Deployment 用 jsonPointers 忽略 /metadata/annotations。针对同一个文件,把 ignore-differences 的输出保存到 /root/ga-ignore/updates-diff.txt,把 ignore-resource-updates 的输出保存到 /root/ga-ignore/updates-upd.txt。

这两个键的目的不同——前者是“这个差异不算 OutOfSync”,后者是“这个变更不会唤醒调谐循环”。后者是减轻控制器负载的旋钮,不会改变同步判定。请如实记录两份输出有什么不同。

只对单个应用生效的规则,以及回归检查

在 /root/ga-ignore/application.yaml 中创建 Application ga-ignore-web(命名空间 argocd,项目 default),并应用到 kwok 集群。在 spec.ignoreDifferences 中放一个 group 为 apps、kind 为 Deployment 的条目,其中同时放入 /spec/replicas 指针和用来选出 sidecar 镜像的 jq 表达式。然后在 /root/ga-ignore/ignore-matrix.tsv 中写至少四行 <ConfigMap파일>\t<찾을 글자>\t<yes|no>(占位符依次为 ConfigMap 文件、要查找的字符、yes 或 no),用 /root/ga-ignore/check-ignore.sh 全部检查,并把输出保存到 /root/ga-ignore/ignore-result.txt。脚本只写到标准输出,只要有一行不匹配就必须以非 0 退出码结束。

全局规则(argocd-cm)对所有应用生效,而 Application 的规则只对该应用生效。两者会合并后应用,所以先在全局放宽、再在应用里收窄是做不到的——收窄方向的规则,从一开始就应该放在应用一侧。表中请混入像 argocd-cm-wide.yaml 与 nginx 这样确认“这条规则会不会删掉这个字符”的行。