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

CGOA — GitOps認定アソシエイト

一方向だけでは真実の源にならない

TT Labで続きを見る

一言でいうと

gitが唯一の信頼できる情報源だという主張は、双方向のときにだけ成り立ちます。automatedだけを有効にすると一方向になり、gitとクラスターが静かに分かれていきます。

なぜ双方向でなければならないのか

GitOpsの核となる主張は1つです。gitが唯一の信頼できる情報源であり、クラスターはそのコピーです。

その主張が成り立つには、双方向でなければなりません。

設定 行うこと
automated gitを直すとクラスターが追従します
selfHeal クラスターを直すと元に戻ります
prune gitから消したものをクラスターからも消します

automatedだけを有効にすると一方向です。kubectlで直接直したものがそのまま残り、gitとクラスターが静かに分かれていきます。たいていは急な障害のためです。明け方にkubectl scaleで増やし、朝になってgitへの反映を忘れます。すると、次のデプロイのときにその差が一度に元へ戻されます。

syncとhealthは別のことを表します

OutOfSyncでありながらHealthyであることもあります。誰かが手で直したものの、その状態で問題なく動いている場合です。逆にSyncedなのにDegradedであることもあります。

selfHealには代償があります

緊急対応ができません。そして、手で直したものが跡形もなく消えるので、直した人は自分の変更がなぜ消えたのかわかりません。そのため、「緊急対応もgitを経由する」ことを、チームが事前に合意しておく必要があります。

また、HPAと争います。gitにreplicasを書いておくと、HPAが増やすたびにArgoが元に戻します。

OutOfSyncが消えないとき

最もよく遭遇する運用上の問題です。gitとクラスターが同じに見えるのに、ずっとOutOfSyncのままです。原因はたいてい、誰かがフィールドを埋めていることです。

埋める主体 例 対応
アドミッションWebhook サイドカーの注入、デフォルトのラベル ignoreDifferencesでそのパスを除外します
コントローラー HPAのreplicas、clusterIP gitからそのフィールドを削除します
APIサーバーのデフォルト値 imagePullPolicy、terminationGracePeriodSeconds gitに明示して合わせます
# Application 스펙
spec:
  ignoreDifferences:
    - group: apps
      kind: Deployment
      jsonPointers:
        - /spec/replicas          # HPA 가 관리한다
    - group: ""
      kind: Service
      jsonPointers:
        - /spec/clusterIP         # API 서버가 정한다

何が違うのかは、画面ではなくコマンドで見ます。

argocd app diff <앱> --local ./manifests    # 로컬과 클러스터
argocd app get <앱> -o json | jq '.status.resources[] | select(.status!="Synced")'

同期の順序とウェーブ

リソースを一度に適用すると、順序の問題が起きます。CRDがないのにCRを適用したり、 DBが起動する前にアプリケーションが起動したりします。Argoはsync waveで順序を決めます。

metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "-1"   # 작을수록 먼저

Argoは、デフォルトの順序(ネームスペース → CRD → その他)を先に適用し、その中でウェーブを 見ます。ウェーブの間では、前のウェーブのリソースがHealthyになるまで待ちます。 そのため、Healthの判定がないカスタムリソースを前のウェーブに置くと、永遠に待ち続ける ことがあります。そのときはHookやヘルスチェックのLuaスクリプトを使うか、ウェーブをまとめます。

app of appsとプロジェクト

アプリケーションが数十個になると、Application自体をgitで管理します(app of apps)。 そうすると、新しいサービスの追加は、マニフェスト1枚をコミットする作業になります。

ここにAppProjectで柵を立てます。どのリポジトリから、どのクラスターの、どの ネームスペースに、どの種類のリソースを作れるかを制限します。これがないと、 誰かのApplication1つがkube-systemに触れてしまう可能性があります。

spec:
  sourceRepos: ["https://git.internal/labhub/*"]
  destinations:
    - namespace: "labhub-*"
      server: https://kubernetes.default.svc
  clusterResourceWhitelist: []       # 클러스터 범위 리소스는 아예 금지

実務で本当に大切なこと

selfHealを有効にする前に、緊急対応の手順を先に合意しておきます。手で直したものが跡形もなく消えるので、直した人は自分の変更がなぜなくなったのかわかりません。「緊急対応もgitを経由する」ことが合意されていないチームで有効にすると、明け方の障害が2回起きます。

HPAを使うワークロードは、gitからreplicasを外す必要があります。書いておくと、HPAが増やすたびにArgoが元に戻し、負荷が上がっている間、2つのコントローラーがお互いに争います。

Syncedの緑色の表示を、デプロイ完了と読んではいけません。syncはgitと同じという意味で、healthは正しく動いているという意味なので、SyncedでありながらDegradedという状態が実際に存在します。デプロイの判定は、2つの値を一緒に見る必要があります。

次のラボでは、本物のArgo CDの上にgitサーバーまで立てて、これらを自分で起こしてみます。