TT Lab
はじめる
学ぶ 学習パス コース

GitOpsとArgo CD

Application — デプロイそのものをオブジェクトにする

TT Labで続きを見る

一言でいうと

Argo CDのApplicationは、デプロイスクリプトではなく、「このリポジトリのこのパスが、あのクラスターのあのネームスペースになっているべきだ」という宣言であり、その宣言自体がクラスターの中のオブジェクトです。

なぜ必要なのか

デプロイパイプラインをCIスクリプトで組むと、デプロイの設定がパイプラインの定義の中に閉じ込められます。どのアプリがどのネームスペースに行くのか、誰がそのアプリをデプロイできるのかを知るにはスクリプトを読む必要があり、そのスクリプトはクラスターの外にあります。そのため、「このクラスターにデプロイされたアプリの一覧」を、クラスターに尋ねることができません。

Argo CDは、デプロイの関係そのものをカスタムリソースにして、この問題をなくします。kubectl get application -n argocdの1行で、このクラスターが何を、どこから、どんなポリシーで取り込んでいるかがすべて出てきます。デプロイがオブジェクトになれば、RBAC、監査ログ、そしてGitOps自身(Applicationを定義したYAMLもリポジトリにコミットする)まで、自然に付いてきます。

どう動くのか

Applicationの骨組みは、4つのかたまりです。

フィールド 何を決めるか
spec.source どこから読むか(repoURL、path、targetRevision)
spec.destination どこに入れるか(server(またはname)とnamespace)
spec.project どんな境界の中で動くか(AppProjectの名前)
spec.syncPolicy どう合わせるか(自動化・整理・リトライ)

syncPolicy.automatedには、スイッチが2つあります。pruneスイッチは「リポジトリから消したものを、クラスターからも消す」で、selfHealスイッチは「クラスターがリポジトリと違ってきたら、リポジトリ側に元に戻す」です。両方をオフにすると、Argo CDは差を画面に見せるだけのダッシュボードになります。

syncOptionsは、適用方式の細部です。CreateNamespace=trueは、対象のネームスペースを自動で作り、ServerSideApply=trueは、フィールドの所有権をサーバーが追跡するようにして、複数のコントローラーが同じオブジェクトに触れるときの衝突を減らします。PruneLast=trueは、ほかのリソースをすべて合わせたあとで最後に削除するようにして、削除事故の被害を小さくします。

retryは、失敗をどう再試行するかです。limitと、backoffのduration・factor・maxDurationで、指数バックオフを作ります。duration: 10s、factor: 2なら、10秒、20秒、40秒と間隔が開いていき、maxDurationで止まります。同じ間隔で無限にリトライすると、APIサーバーを叩く負荷装置になります。

順序制御の仕組みは、2つの層です。sync waveは、argocd.argoproj.io/sync-waveアノテーションの数字でリソースをグループにまとめ、小さい値から適用し、現在のウェーブがHealthyになるまで次に進みません。同じウェーブの中では、リソースの種類ごとのデフォルトの順序(Namespace → ConfigMap/Secret → RBAC → CRD → PV/PVC → Service → ワークロード → Ingress)が適用されます。その上で、フック(hook)が段階そのものを分けます。PreSync → Sync → PostSyncで、失敗するとSyncFailが動きます。フックはたいていJobで、argocd.argoproj.io/hookアノテーションで指定し、hook-delete-policyで後片付けのタイミングを決めます。デフォルトはBeforeHookCreationなので、フックのリソースは成功しても残っていて、次のsyncの直前に削除されます。失敗したマイグレーションJobのログを事後に見られるのは、このデフォルトのおかげです。

現場での姿

1つ目は、AppProjectは事故の範囲を決める塀だということです。sourceRepos、destinations、clusterResourceWhitelist、namespaceResourceBlacklistで、「どのリポジトリから、どのネームスペースへ、どの種類まで」デプロイできるかを決めます。sourceRepos: ["*"]にすると、プロジェクトを分けた意味がなくなります。打ち間違い1つで、他人のリポジトリを自分のクラスターにデプロイすることが可能になります。

2つ目は、無限同期です。HPAがspec.replicasを変えるのに、Argo CDがそれをドリフトと見て元に戻すと、HPAがまた変え、Argo CDがまた元に戻すループが生まれます。ignoreDifferencesで/spec/replicasを比較の対象から外して、ようやく止まります。ほかのコントローラーが所有するフィールドは、GitOpsの所有ではないという原則を、明示的に書いておく場所です。

3つ目は、ウェーブの分け方を間違えると、デプロイがそこで止まることです。決してHealthyにならないリソースを前のウェーブに置くと、後ろのウェーブは永遠に来ません。ウェーブは「先になければならないもの」にだけ使い、数は少なく保つほうが安全です。

次のラボですること

Argo CDのCRDをオフラインバンドルから適用して、Application・AppProjectの型をクラスターに登録し、argocdネームスペースにApplicationwebを自分で書きます。自動同期・整理・自己修復のスイッチとsyncOptions・リトライのバックオフを埋め、リポジトリのマニフェストにsync waveとPreSyncフックを付けます。そのあと、AppProjectplatformで境界を引いてアプリをその中に所属させ、最後に、クラスターに実際に存在するApplicationの一覧と一致する構成レポートを作ります。この環境にはArgo CDコントローラーがないので、ApplicationがひとりでにSyncedになることはありません。採点の対象は、宣言の正確さです。