緑ランプは誰がつけるのか
一言でいうと
Argo CDのヘルスは、種類ごとに異なる判定ルールが作り出します。組み込みのルールがないCRDは、argocd-cmにLuaで直接書いてあげる必要があり、そのルールは、サーバーなしでargocd admin settings resource-overrides healthを使って、その場で試せます。
なぜヘルスが同期と別にあるのか
GitOpsを学ぶときに最初に出会う軸は同期です。リポジトリに書かれたものと、クラスターにあるものが同じかどうかです。ところが、この軸だけでは答えられない質問が1つ残ります。同じではあるけれど、正しく動いているのかという質問です。リポジトリに書かれたイメージのタグが存在しなくても、Deploymentオブジェクト自体は、リポジトリとまったく同じように作られます。同期の軸は緑で、Podは1つも起動しません。そのため、Argo CDは軸を2つに分けます。同期は「宣言と実物が同じか」、ヘルスは「実物が本来の役割を果たしているか」です。2つの軸が別々にあって初めて、現場で最もよく出会う状態である「SyncedなのにDegraded」を表現できます。
ヘルスの値は6つです。Healthy、Progressing、Degraded、Suspended、Missing、Unknownです。アプリ全体のヘルスは、子リソースの値を集めて、最も悪いほうに決まります。そのため、子の1つのルールが間違っているだけでも、アプリ全体が間違った色で見えます。
どう動くのか
Deployment、StatefulSet、Service、Ingress、Job、PVCのような組み込みの種類には、Argo CDの中に判定コードがすでにあります。たとえばDeploymentは、statusのupdatedReplicas・readyReplicas・availableReplicasとobservedGenerationを見て、まだすべて立ち上がっていなければ、Progressingとともに「何個中何個」というメッセージを作ります。
CRDには、こうしたコードがありません。そのため、argocd-cmにルールを載せます。キーの名前が重要です。
data:
resource.customizations.health.example.com_Widget: |
hs = {}
if obj.status ~= nil and obj.status.phase == "Ready" then
hs.status = "Healthy"
hs.message = "widget is ready"
return hs
end
hs.status = "Progressing"
hs.message = "waiting for widget"
return hs
<그룹>_<종류>で、区切り文字はアンダースコアです(プレースホルダーは、順にグループと種類です)。ここで種類の名前をマニフェストのkindと違うように書くと、エラーは出ません。単に、ルールがないかのように動作します。この種類のミスが長く生き残る理由です。
Luaの断片は、objというグローバル変数でリソースをまるごと受け取り、statusとmessageを埋めたテーブルを返します。ルールを書くときに最もよく抜かしてしまうのが、statusがまだない瞬間です。作られたばかりでコントローラーが手を付ける前のリソースには、status自体がありません。ここでDegradedを出すと、新しく作ったリソースが毎回赤信号で始まり、アラートを設定したチームは、すぐにそのアラートを切ります。デフォルトの分岐はProgressingである必要があります。
Suspendedは、別に語る価値があります。人がわざと止めておいたもの(メンテナンス中のパイプライン、停止したCronJob)を指す欄です。これをDegradedにすると、計画されたメンテナンスのたびにページャーが鳴ります。そして、分岐の順序が結果を変えます。止めてあるリソースのstatus.phaseがまだReadyなら、Readyの分岐を先に書いたルールは、緑を出してしまいます。
現場での姿
最もよくある事故は「CRDがいつも緑」です。Operatorが作ったデータベースリソースが、何時間もプロビジョニングに失敗しているのに、画面には何の表示もありません。Argo CDが嘘をついたのではなく、判定するルールを誰も書いてあげなかったので、そのリソースがヘルスの計算に参加しなかっただけです。アラートは、たいていユーザーのほうが先に出します。
2番目によくあるのは、ルールが静かに古くなることです。Operatorをバージョンアップしたらstatus.phaseがstatus.conditionsに変わったのに、argocd-cmのLuaはそのままです。ルールは今や常にデフォルトの分岐に進み、すべてのリソースがProgressingで固まります。誰もエラーを見られません。そのため、ルールを書いたら、サンプルリソースと期待する判定を表にまとめて、リポジトリに一緒に置くことが、ルール自体と同じくらい重要です。この表をCIで1回実行すれば、フィールド名が変わった日にすぐ赤信号が点きます。
このラボ環境の限界
ラボのPodには、Argo CDコントローラーがありません。そのため、「ルールを反映したら画面の色が変わった」は見られず、ヘルスがDegradedなので同期が止まるといったコントローラーの動作も確認できません。その代わり、判定を実際に行うそのコードがCLIの中にそのまま入っているので、argocd-cm1枚とリソースのYAML1枚だけで、同じ答えを得られます。
次のラボですること
組み込みの判定をまず見て、ルールがないCRDがどんな文を出すかを確認します。そのあとLuaを1つずつ増やして、Healthy・Degraded・Progressing・Suspendedの4つの欄をすべて作ってみて、キーの名前を1文字間違えたときに何が起きるかを、目で見ます。最後に、サンプルと期待値を表にまとめて、一度に実行する検査スクリプトを作ります。