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

CGOA — GitOps 认证助理

推送之后,什么也没有发生

在 TT Lab 中继续学习

目标

在同一条提交流程中,测量 Argo CD 定期从 Git 拉取的路径,与通过 push Webhook 立即刷新的路径。 看看关掉轮询会让什么停下来,Webhook 要先确认什么才会被接受,以及在生产环境中如何把两者叠加使用。

为什么重要

GitOps 调谐器会主动拉取期望状态。触发拉取的有两种时机:按固定周期重新读取仓库的轮询, 以及仓库通知“刚刚有过 push”的事件。只用轮询,提交要等上一个周期才能生效,仓库一多, 这个周期就会变成 Git 服务器的负载。只用事件虽然快,但通知一旦丢失,提交就会悄悄停住。 而且任何人都能发送的 Webhook 会成为唤醒调谐器的攻击面,所以必须用签名确认发送方。 本实验还要确认:事件只是通知调谐器“现在就读取”,并不是部署指令。要部署什么,依然由 Git 决定。

步骤

  1. 创建裸仓库 /srv/bare/evt.git,克隆到 /root/cgoa-evt/repo,在 app/signal.yaml 中提交 ConfigMap signal(无 namespace,data rev: r1),并 push 到 main。在 /root/cgoa-evt/app.yaml 中编写并应用 Application evt(argocd 命名空间,project default,repoURL http://githttp.gitsrv.svc.cluster.local/cgi-bin/git/evt.git,targetRevision main,path app,目标命名空间 evt,自动同步 prune、selfHeal,CreateNamespace=true),确认 Synced。
  2. 在 ConfigMap argocd-cm 中加入 timeout.reconciliation: 30s 与 timeout.reconciliation.jitter: 0s,然后重启 argocd-application-controller StatefulSet 和 argocd-repo-server Deployment 两者。在新的控制器 Pod 日志中找到含有 appResyncPeriod 的那一行,原样保存到 /root/cgoa-evt/interval.txt;重启完成后,对 evt 执行一次 hard refresh。
  3. 把 app/signal.yaml 的 rev 改为 r2 并提交、push,在既不使用 refresh 也不使用 Webhook 的情况下,等到 evt 的 status.sync.revision 变成该提交。在 /root/cgoa-evt/poll.json 中写入 commit、pushed_at(push 之后的 Unix 秒)、synced_at(看到 revision 变化时的 Unix 秒),时间用数字表示。
  4. 把 argocd-cm 的 timeout.reconciliation 改为 0s,并重启控制器和 repo-server。然后把 rev 改为 r3 并 push,不发出任何请求,等待 40 秒以上,在 /root/cgoa-evt/nopoll.json 中写入 commit(r3 提交)、pushed_at、checked_at(等待之后确认时的 Unix 秒)、revision_at_check(此时 evt 的 status.sync.revision)。
  5. 向 argocd-server 服务的 /api/webhook 发送 GitHub push 事件。请求头为 X-GitHub-Event: push 和 Content-Type: application/json,正文是一个 JSON:ref 为 refs/heads/main,after 为 r3 提交,repository.html_url 为 http://githttp.gitsrv.svc.cluster.local/cgi-bin/git/evt。等到 evt 变为 r3 提交,然后在 /root/cgoa-evt/webhook.json 中写入 http_status(数字)、sent_at、synced_at。
  6. 把用 openssl rand -hex 16 生成的值保存到 /root/cgoa-evt/webhook-secret,并放入 Secret argocd-secret 的 webhook.github.secret 键。把 rev 改为 r4 并 push,先发送一个没有签名的 push 事件,等待 15 秒。接着,用该密钥对同一个正文文件做 HMAC-SHA256 签名,连同 X-Hub-Signature-256: sha256=<hex> 请求头一起发送,并等待同步。在 /root/cgoa-evt/secret.json 中写入 commit(r4)、unsigned_status、signed_status(数字)、revision_after_unsigned(无签名请求 15 秒后 evt 的 revision)、signed_synced_at。
  7. Webhook 可能丢失,所以要恢复轮询。把 argocd-cm 的 timeout.reconciliation 改为 120s,删除 timeout.reconciliation.jitter 键,然后重启控制器和 repo-server。把新控制器日志中的 appResyncPeriod 行保存到 /root/cgoa-evt/restored.txt,并对 evt 执行一次 hard refresh。Webhook 密钥保持不变。
  8. 在 /root/cgoa-evt/report.json 中写入 poll_seconds(第 3 步测得的 synced_at-pushed_at)、nopoll_synced(第 4 步确认时 r3 是否已部署,布尔值)、webhook_seconds(第 5 步的 synced_at-sent_at)、unsigned_accepted(无签名事件是否引起了部署,布尔值)、trigger(webhook)、safety_net(timeout.reconciliation)。

参考

跟踪 smart HTTP 仓库的应用

创建裸仓库 /srv/bare/evt.git,克隆到 /root/cgoa-evt/repo,在 app/signal.yaml 中提交 ConfigMap signal(无 namespace,data rev: r1),并 push 到 main。在 /root/cgoa-evt/app.yaml 中编写并应用 Application evt(argocd 命名空间,project default,repoURL http://githttp.gitsrv.svc.cluster.local/cgi-bin/git/evt.git,targetRevision main,path app,目标命名空间 evt,自动同步 prune、selfHeal,CreateNamespace=true),确认 Synced。

本实验的仓库地址使用 http:// 而不是 git://,githttp 服务器用 git-http-backend 对外提供 /srv/bare 下的仓库。先用 git ls-remote 确认能看到。

把拉取周期缩短为 30 秒

在 ConfigMap argocd-cm 中加入 timeout.reconciliation: 30s 与 timeout.reconciliation.jitter: 0s,然后重启 argocd-application-controller StatefulSet 和 argocd-repo-server Deployment 两者。在新的控制器 Pod 日志中找到含有 appResyncPeriod 的那一行,原样保存到 /root/cgoa-evt/interval.txt;重启完成后,对 evt 执行一次 hard refresh。

这个设置由两个组件在启动时读取。对控制器来说,它是重新比较应用的周期;对 repo-server 来说,它是缓存分支所指提交的时长。只重启控制器的话,即使每 30 秒比较一次,repo-server 也会继续返回旧提交。缓存在 Redis 中,所以重启之前以旧的过期时间(默认 3 分钟)保存的条目仍会留着,必须用 hard refresh 重新读取一次,新的过期时间才会生效。日志中的那一行用 Go 的 time.Duration 写法显示时长。

什么都不按,干等的时间

把 app/signal.yaml 的 rev 改为 r2 并提交、push,在既不使用 refresh 也不使用 Webhook 的情况下,等到 evt 的 status.sync.revision 变成该提交。在 /root/cgoa-evt/poll.json 中写入 commit、pushed_at(push 之后的 Unix 秒)、synced_at(看到 revision 变化时的 Unix 秒),时间用数字表示。

用 date +%s 测量时间。等待期间,每隔 2 秒只读取 revision。用 annotate 请求 refresh,这次测量就不再是轮询了。

关掉轮询,提交就停住了

把 argocd-cm 的 timeout.reconciliation 改为 0s,并重启控制器和 repo-server。然后把 rev 改为 r3 并 push,不发出任何请求,等待 40 秒以上,在 /root/cgoa-evt/nopoll.json 中写入 commit(r3 提交)、pushed_at、checked_at(等待之后确认时的 Unix 秒)、revision_at_check(此时 evt 的 status.sync.revision)。

0 表示关闭周期性刷新。请看重启后控制器日志中的 appResyncPeriod 变成了什么。受管对象发生变化的集群事件,与重新读取 Git,是两回事。

一次 push 事件要几秒

向 argocd-server 服务的 /api/webhook 发送 GitHub push 事件。请求头为 X-GitHub-Event: push 和 Content-Type: application/json,正文是一个 JSON:ref 为 refs/heads/main,after 为 r3 提交,repository.html_url 为 http://githttp.gitsrv.svc.cluster.local/cgi-bin/git/evt。等到 evt 变为 r3 提交,然后在 /root/cgoa-evt/webhook.json 中写入 http_status(数字)、sent_at、synced_at。

向服务的 ClusterIP 用 https 发送,因为是自签名证书,所以要用 curl -k。Argo CD 会把事件中的仓库地址与每个 Application 的 repoURL 对照,只刷新匹配的应用。在 commits[].modified 中放入被修改的文件路径,路径对照也会通过。

没有签名的事件,挡在门外

把用 openssl rand -hex 16 生成的值保存到 /root/cgoa-evt/webhook-secret,并放入 Secret argocd-secret 的 webhook.github.secret 键。把 rev 改为 r4 并 push,先发送一个没有签名的 push 事件,等待 15 秒。接着,用该密钥对同一个正文文件做 HMAC-SHA256 签名,连同 X-Hub-Signature-256: sha256=<hex> 请求头一起发送,并等待同步。在 /root/cgoa-evt/secret.json 中写入 commit(r4)、unsigned_status、signed_status(数字)、revision_after_unsigned(无签名请求 15 秒后 evt 的 revision)、signed_synced_at。

签名必须针对发送出去的原始字节来计算。把正文做成文件,用 curl --data-binary @파일(占位符为文件名)发送,并把同一个文件放进 openssl dgst -sha256 -hmac。argocd-server 会自行重新读取 Secret 的变化。

相信 Webhook,但把轮询恢复为兜底

Webhook 可能丢失,所以要恢复轮询。把 argocd-cm 的 timeout.reconciliation 改为 120s,删除 timeout.reconciliation.jitter 键,然后重启控制器和 repo-server。把新控制器日志中的 appResyncPeriod 行保存到 /root/cgoa-evt/restored.txt,并对 evt 执行一次 hard refresh。Webhook 密钥保持不变。

在 merge patch 中,要删除某个键,就把值设为 null 发送。删掉 jitter 后会使用默认值。请确认日志行里周期和 jitter 分别显示成什么。周期为 0 期间,repo-server 用默认的缓存过期时间(24 小时)保存了分支所指的提交。即使把周期改回来,那个条目仍然留着,所以必须用 hard refresh 重新读取一次,轮询才会重新看到新提交。

报告拉取与事件各自的作用

在 /root/cgoa-evt/report.json 中写入 poll_seconds(第 3 步测得的 synced_at-pushed_at)、nopoll_synced(第 4 步确认时 r3 是否已部署,布尔值)、webhook_seconds(第 5 步的 synced_at-sent_at)、unsigned_accepted(无签名事件是否引起了部署,布尔值)、trigger(webhook)、safety_net(timeout.reconciliation)。

用前面步骤留下的 JSON 文件里的数字来计算。评分器会把同一批文件与 Argo CD 同步记录再次对照。