制造漂移、观察它、再撤回
目标
亲手完成一个完整循环:主动制造漂移、计算差异并保存到文件,再恢复到声明状态。随后编写 sync wave 和 PreSync hook 清单,并检查集群以判断 prune 对象。
为什么这很重要
Argo CD 的协调循环并非魔法,它只是默认每 180 秒重复本实验中的操作:重新渲染、读取 live 状态、进行比较,并在策略允许时应用。亲手执行一次这个循环,就能切身体会 refresh 与 sync 为何是不同的操作,以及启用 selfHeal 会对运维纪律提出什么要求。判断 prune 对象也是如此——代理不会删除集群中的所有资源,而只会删除那些被标记为由它创建、且已从 Git 中消失的资源。如果不了解这一边界,就既无法解释“为什么那个没有被删除”,也无法解释“为什么这个被删除了”。本环境没有 Argo CD CRD,因此 wave 和 hook 需要以文件形式编写,评分也会读取这些文件。
步骤
- 在
/root/cgoa-drift/desired/orders.yaml中编写 Deploymentorders——namespace 为cgoa-drift,spec.replicas: 2,选择器和 Pod 标签为app: orders,容器名称为app,镜像为nginx:1.27-alpine。创建 namespacecgoa-drift,并使用kubectl apply -f应用该文件。 - 保持文件不变,只将集群中
orders的 replicas 改为5以制造漂移。然后用kubectl get ... -o jsonpath读取变更后的 live 值,并保存到/root/cgoa-drift/live-replicas.txt(稍后恢复后仍将其保留为证据)。 - 将
kubectl diff -f /root/cgoa-drift/desired/orders.yaml的输出保存到/root/cgoa-drift/drift.txt。文件中应显示 replicas 的差异。 - 重新应用原始清单,将 replicas 恢复为
2。 - 在
/root/cgoa-drift/wave/中创建三个文件。namespace.yaml——Namespacecgoa-wave,注解argocd.argoproj.io/sync-wave: "-2"。config.yaml——ConfigMaporders-wave-config(namespace 为cgoa-wave,data 中任意一个键),注解argocd.argoproj.io/sync-wave: "-1"。app.yaml——Deploymentorders-wave(namespace 为cgoa-wave),注解argocd.argoproj.io/sync-wave: "1"。 - 在
/root/cgoa-drift/hooks/db-migrate.yaml中编写 Jobdb-migrate——namespace 为cgoa-drift,注解argocd.argoproj.io/hook: PreSync、argocd.argoproj.io/hook-delete-policy: BeforeHookCreation、argocd.argoproj.io/sync-wave: "-1",spec.backoffLimit: 1,Pod 的restartPolicy: Never,容器名称为migrate。 - 判断 prune 对象。先在
/root/cgoa-drift/desired/config.yaml中声明并应用 ConfigMaporders-config(namespace 为cgoa-drift,data 中任意一个键)。然后以命令式方式创建名为legacy-config的 ConfigMap,位置是 namespacecgoa-drift,不要使用文件。最后,在/root/cgoa-drift/prune-candidates.txt中逐行写入 namespacecgoa-drift内那些未在desired/目录任何位置声明的 ConfigMap 名称。(Kubernetes 自动创建的kube-root-ca.crt不属于管理对象,因此应排除。)
参考
kubectl diff -f <파일> > out.txt在存在差异时退出码为 1。请附加|| true。- wave 编号必须是用引号括起的字符串。如果写成
sync-wave: -2,YAML 会将其解析为数字,导致注解值类型不匹配。 - 两个 hook 注解键
argocd.argoproj.io/hook与argocd.argoproj.io/hook-delete-policy彼此不同。 - 常见错误:在第 3 步保存
kubectl get -o yaml的结果。那只是 live 状态,并非差异。必须保存 diff。
声明并应用期望状态
在 /root/cgoa-drift/desired/orders.yaml 中编写 Deployment orders——namespace 为 cgoa-drift,spec.replicas: 2,选择器和 Pod 标签为 app: orders,容器名称为 app,镜像为 nginx:1.27-alpine。创建 namespace cgoa-drift,并使用 kubectl apply -f 应用该文件。
以声明式方式应用后,对象的注解中会保留最后应用的配置。以命令式方式创建则没有该注解——评分会检查这一差异。
手动修改以制造漂移
保持文件不变,只将集群中 orders 的 replicas 改为 5 以制造漂移。然后用 kubectl get ... -o jsonpath 读取变更后的 live 值,并保存到 /root/cgoa-drift/live-replicas.txt(稍后恢复后仍将其保留为证据)。
必须保持文件不变,只修改集群。可以使用一个用于更改副本数的命令式子命令。请用 jsonpath 提取变更后的 live 值并保存到文件中——恢复后它仍可作为证据。
计算差异并保存到文件
将 kubectl diff -f /root/cgoa-drift/desired/orders.yaml 的输出保存到 /root/cgoa-drift/drift.txt。文件中应显示 replicas 的差异。
kubectl diff -f <파일> 会向服务器发起 dry-run,以显示实际差异。存在差异时退出码为 1,因此重定向输出时要避免命令因此中断。
恢复到声明状态
重新应用原始清单,将 replicas 恢复为 2。
这是手动执行代理的 selfHeal 所做的工作。直接重新应用原始文件即可。
三个 sync wave 注解
在 /root/cgoa-drift/wave/ 中创建三个文件。namespace.yaml——Namespace cgoa-wave,注解 argocd.argoproj.io/sync-wave: "-2"。config.yaml——ConfigMap orders-wave-config(namespace 为 cgoa-wave,data 中任意一个键),注解 argocd.argoproj.io/sync-wave: "-1"。app.yaml——Deployment orders-wave(namespace 为 cgoa-wave),注解 argocd.argoproj.io/sync-wave: "1"。
wave 编号要写成字符串。请分配编号,使基础设施最先、配置其次、工作负载最后。
PreSync hook Job
在 /root/cgoa-drift/hooks/db-migrate.yaml 中编写 Job db-migrate——namespace 为 cgoa-drift,注解 argocd.argoproj.io/hook: PreSync、argocd.argoproj.io/hook-delete-policy: BeforeHookCreation、argocd.argoproj.io/sync-wave: "-1",spec.backoffLimit: 1,Pod 的 restartPolicy: Never,容器名称为 migrate。
hook 类型和删除策略使用不同的注解键。为了便于评审,最好明确写出默认删除策略。
判断 prune 对象
判断 prune 对象。先在 /root/cgoa-drift/desired/config.yaml 中声明并应用 ConfigMap orders-config(namespace 为 cgoa-drift,data 中任意一个键)。然后以命令式方式创建名为 legacy-config 的 ConfigMap,位置是 namespace cgoa-drift,不要使用文件。最后,在 /root/cgoa-drift/prune-candidates.txt 中逐行写入 namespace cgoa-drift 内那些未在 desired/ 目录任何位置声明的 ConfigMap 名称。(Kubernetes 自动创建的 kube-root-ca.crt 不属于管理对象,因此应排除。)
prune 对象是“存在于集群中,但不存在于声明目录中”的资源。请记住,由集群自动创建的对象不属于此范围。