K8s 高級 #6 GitOps — ArgoCD / Flux

読了 11分

K8s 高級シリーズの最後の記事です。#1 CNI から #5 オブザーバビリティ までクラスタのデータプレーン・権限・ポリシー・拡張・観測を 1 層ずつ積み上げてきました。この記事はそのすべてのマニフェストがクラスタに入る 方式自体 を扱います — GitOps です。kubectl apply を人が手で回す代わりに、マニフェストの source of truth を git に置いてクラスタ内のコントローラが git を watch して自動で同期する運用モデルです。ArgoCD と Flux がこのモデルの 2 つの標準実装で、シリーズ最後の記事として 2 つのツールのモデル・運用パターン・シリーズ振り返り・次のトラックまで 1 サイクルでまとめます。

このシリーズは K8s 高級 6 編です。

Push モデルと Pull モデル #

まず GitOps が登場する前の標準だったモデルと比較します。CI/CD パイプラインがクラスタにマニフェストを適用する方式は大きく 2 つの道です。

モデル流れ
PushCI パイプラインがクラスタの API サーバに直接 kubectl apply。CI システムがクラスタの資格情報を保有。
Pull (GitOps)クラスタ内のコントローラが git を watch。マニフェストが変更されるとコントローラが自動で同期。

伝統的な CD パイプラインは push モデルでした。GitHub Actions や Jenkins がビルド後 kubectl apply -f manifests/ を回して終わりでした。このモデルの問題は 3 つです。

  • CI システムがクラスタの強い資格情報を持っている — CI システムが侵害されるとクラスタも侵害されます。
  • Drift が見えない — 誰かがクラスタに直接 kubectl edit を回すと git のマニフェストと実際のクラスタが食い違うのに、その食い違いを検知する標準メカニズムがありません。
  • 複数のクラスタへの拡張が難しい — クラスタ N 個に同じマニフェストを適用するには N 回 kubectl apply を回さなければなりません。

GitOps モデルはこの 3 つを一度に解いた道です。クラスタ内のコントローラが git を watch するので外部でクラスタの資格情報を持つ必要がなく、そのコントローラが同期状態を継続的に見ているので drift を自動で検知し、各クラスタが自分の git を watch するモデルなので N 個拡張が自然です。

GitOps の 4 原則 #

OpenGitOps プロジェクトが整理した GitOps の 4 原則は次のとおりです。

原則意味
Declarativeシステムの desired state が宣言的に表現される
Versioned and Immutabledesired state が git のような変更不可能な保存所に保管される
Pulled Automatically承認済みの変更が自動でシステムに適用される
Continuously Reconciledコントローラが desired state と実際の state の差を継続的に縮める

K8s のマニフェストは declarative で、git は versioned + immutable です。ArgoCD と Flux がその上に pull + reconciliation を加えて GitOps を完成させます。

ArgoCD — Application CRD 中心のモデル #

ArgoCD は Intuit が作って CNCF に寄贈した GitOps ツールです。最大の特徴は 豊かな Web UI です。クラスタのすべての Application の同期状態、drift、マニフェストの変更履歴を 1 つの画面で見られるので運用チームの参入障壁が低いです。

Application CRD — ArgoCD の単位 #

ArgoCD が git からマニフェストを取ってきてクラスタに同期する単位が Application CRD です。

application-my-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/manifests.git
    targetRevision: main
    path: apps/my-app/overlays/prod
  destination:
    server: https://kubernetes.default.svc
    namespace: my-app
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

このマニフェストが ArgoCD に適用されると次のことが自動で起こります。

  1. ArgoCD コントローラが repoURLpath ディレクトリを git から取ってくる
  2. Kustomize / Helm / 一般 YAML を自動認識してマニフェストをレンダリング
  3. クラスタの destination に同期 (automated.selfHeal: true なので drift を自動回復)
  4. git のマニフェストが変更されると自動で再同期 (automated)
  5. git から消えたオブジェクトはクラスタからも削除 (prune: true)

App of Apps — Application の束管理 #

複数の Application を 1 か所で管理するパターンが App of Apps です。1 つの Application の source が他の Application マニフェストの入っているディレクトリを指す構造です。

App of Apps ディレクトリ構造
manifests/
  apps/
    root.yaml              ← ルート Application (ArgoCD に手動で適用)
    children/
      app-a.yaml           ← Application: app-a
      app-b.yaml           ← Application: app-b
      app-c.yaml           ← Application: app-c
  ...

ルート Application 1 個だけを ArgoCD に最初に登録すれば、その中で子 Application が順に作られて、各子 Application が再び自分のマニフェストを同期します。クラスタに新しいアプリを追加するには git に新しい子 Application 1 枚を追加するだけで終わりです。

Sync Wave — 順序のある適用 #

マニフェスト適用に順序が必要なケースがあります — Namespace を先に作って、その中に ConfigMap を作って、その次に Deployment を立てる順序。ArgoCD は annotation でこの順序を表現します。

順序表現 — argocd.argoproj.io/sync-wave
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "0"   # Namespace
---
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "1"   # ConfigMap, Secret
---
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "2"   # Deployment, StatefulSet

低い wave が先に適用されて、その wave のオブジェクトがすべて healthy 状態になった後に次の wave が進行します。CRD を先に作ってその CRD のインスタンスを適用するパターンがもっともよく出会う使いどころです。

Flux — 小さなコンポーネントの束 #

Flux は Weaveworks が作った GitOps ツールで ArgoCD と同じカテゴリのツールですがアプローチが違います。Flux v2 は 1 つの大きなコンポーネントではなく 複数の小さなコントローラの束 として設計されています。

Flux コントローラ役割
source-controllergit / Helm 保存所 / OCI イメージからマニフェストを fetch
kustomize-controllerKustomize マニフェストを適用
helm-controllerHelmRelease オブジェクトで Helm chart を適用
notification-controllerSlack / Teams / GitHub などにイベント通知
image-automation-controllerコンテナイメージの新しいバージョンを git に自動 commit

各コントローラが自分の CRD を持ち、その CRD のマニフェストですべての動作が表現されます。

GitRepository + Kustomization — Flux の基本束 #

git 保存所登録
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: manifests
  namespace: flux-system
spec:
  interval: 1m
  url: https://github.com/myorg/manifests.git
  ref:
    branch: main
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: my-app
  namespace: flux-system
spec:
  interval: 5m
  path: ./apps/my-app/overlays/prod
  prune: true
  sourceRef:
    kind: GitRepository
    name: manifests
  targetNamespace: my-app

GitRepository が git を watch し、Kustomization がその git の 1 つのディレクトリをクラスタに適用します。2 つのオブジェクトの分離のおかげで同じ git を複数の Kustomization が異なる path で指せます。

HelmRelease — Helm chart の GitOps 化 #

HelmRelease — Helm chart もマニフェストで表現
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: prometheus
  namespace: monitoring
spec:
  interval: 10m
  chart:
    spec:
      chart: kube-prometheus-stack
      version: "55.x"
      sourceRef:
        kind: HelmRepository
        name: prometheus-community
  values:
    prometheus:
      prometheusSpec:
        retention: 30d

helm install を手で回す代わりに HelmRelease マニフェストで表現すれば Helm chart のインストール・アップグレードも GitOps の流れの中に入ってきます。

ArgoCD vs Flux — 選択の肌理 #

次元ArgoCDFlux
モデル1 つの大きなコンポーネント + 豊かな UI小さなコントローラの束 + CLI 中心
参入障壁低 (UI で開始)中 (CRD マニフェストで開始)
マルチテナンシーAppProject で表現namespace 単位の分離
マルチクラスタ1 つの ArgoCD が複数のクラスタを管理可能各クラスタに Flux 1 つ (hub-spoke 可能)
Helm サポート1 級HelmRelease CRD で 1 級
イメージ自動アップデートargocd-image-updater (別途)image-automation-controller (内蔵)

選択の肌理は通常次に従います。

  • 運用チームが GUI を好み、1 つの画面ですべてのクラスタを見たいなら ArgoCD が自然です。
  • すべての運用をマニフェストで表現したく、小さなコンポーネントの束を好むなら Flux が合います。

両方のツールとも CNCF の卒業プロジェクトで運用規模で固まっています。一方を間違えて大きな事故になる種類の決定ではありません。

ディレクトリ構造パターン #

GitOps repo のディレクトリ構造は運用チームのスタイルによって分かれますが、よく見るパターンが 2 つあります。

1. env-per-folder — 環境別分岐 #

環境を最上位に
manifests/
  base/
    my-app/
      deployment.yaml
      service.yaml
  envs/
    dev/
      kustomization.yaml      ← base + dev patch
    staging/
      kustomization.yaml
    prod/
      kustomization.yaml

Kustomize の base + overlay パターンをそのまま活用した構造です。環境別の差(replicas、image tag、resources)が overlay にパッチとして入ります。

2. app-per-folder + branch-per-env #

アプリを最上位に、環境はブランチで
manifests/        (main branch = prod)
  apps/
    my-app/
      deployment.yaml
      service.yaml
    other-app/
      ...

manifests-dev/    (dev branch)
manifests-staging/ (staging branch)

ブランチを環境分岐として使うモデルです。環境の差が commit で表現されて audit が自然ですが、ブランチ間の sync 負担が大きいです。

運用では env-per-folder がより頻繁に使われます。変更の流れが 1 つのブランチ(main)内で起こるので PR レビューが単純です。

Secret を git にどうアップロードするか #

GitOps の大きな宿題の 1 つが秘密を git に置く道です。K8s Secret を平文で git にアップロードすることはできません。標準ツールが 3 つあります。

ツールモデル
Sealed SecretsBitnami が作ったツール。秘密を SealedSecret として暗号化して git にアップロード。クラスタ内のコントローラが自分のキーでのみ復号化可能。
External Secrets Operatorgit には外部秘密保存所(AWS Secrets Manager、Vault など)の参照だけ置き、コントローラが K8s Secret として同期。
SOPS + age/PGPgit に暗号化された YAML を直接アップロード。ArgoCD / Flux 両方とも SOPS 統合をサポート。

External Secrets Operator がもっともよく使われる道です。秘密の source of truth が外部保存所にあり、K8s にはその参照だけ入ってくるので秘密の回転が外部保存所で一度に終わります。#2 IRSA と組み合わせれば秘密保存所アクセスの資格情報すらクラスタ内に静的に置かなくて済みます。

運用時に押さえておく原則 #

1. auto-sync vs manual sync — 環境別分岐 #

syncPolicy.automated をオンにすると git の変更が即座にクラスタに反映されます。dev / staging は自動、prod は手動(または PR マージ後自動)で分岐を置くのが一般的です。prod に自動 sync を掛けるときは syncOptions: PruneLast=true で削除を最後に処理するなどの安全装置を一緒に押さえます。

2. drift detection の意味 #

GitOps コントローラは git と実際のクラスタの差を継続的に比較します。誰かが kubectl edit で直接修正するとその変更は即座に drift として検知され、selfHeal: true なら git のマニフェストで再び上書きされます。これが GitOps の強みですが、同時に罠でもあります — コントローラが自動生成するフィールド(status、自動ラベル)は drift のように見えてはいけません。 ArgoCD / Flux 両方とも ignoreDifferences 設定で無視するフィールドを書けます。

3. Helm value 変更の影響 #

HelmRelease の values を変えるとその chart が作ったすべてのオブジェクトが再デプロイされます。意図しない再デプロイが起こらないように values 変更の影響範囲を PR 段階で dry-run で事前に確認するのが良いです。

4. マルチクラスタの hub-spoke モデル #

クラスタ N 個を GitOps で管理するときの標準モデルが 2 つあります。

  • 各クラスタが自分の GitOps コントローラを持つ — クラスタ自己完結的、外部依存少ない
  • 1 つの hub クラスタの GitOps コントローラが spoke クラスタ群を管理 — 運用単純化、hub の可用性が critical

ArgoCD は両方のモデルがよく合い、Flux は最初のモデルが自然です。

シリーズ振り返り — K8s 高級 6 編で手に入ったもの #

最後の記事なので 6 編を一度押さえておきます。

  • #1CNI 深さ。K8s ネットワークモデルの 4 条件、CNI インターフェース、iptables / IPVS / eBPF のデータプレーン、Calico と Cilium の比較。
  • #2RBAC / ServiceAccount 深さ。Aggregated ClusterRole、Impersonation、projected token、IRSA / Workload Identity で K8s ServiceAccount をクラウド IAM と接続。
  • #3Admission Controller。API サーバの 5 段階フロー、mutating / validating webhook、OPA Gatekeeper と Kyverno のポリシーエンジン比較。
  • #4CRD と Operator パターン。K8s API 自体を拡張する道、controller-runtime ベース Operator の骨格、ownerReference / finalizer / status subresource。
  • #5オブザーバビリティ。メトリクス / ログ / トレースの 3 軸、Prometheus + kube-state-metrics、Loki、OpenTelemetry、Grafana、Alertmanager。
  • #6 — GitOps。マニフェストの source of truth を git に置く運用モデル、ArgoCD と Flux、ディレクトリ構造と秘密管理。

基礎シリーズがマニフェスト 1 枚のモデルを、中級シリーズがそのマニフェストが運用クラスタで動く深さを、高級シリーズがその上にポリシーエンジン・拡張・観測・同期の深さを 1 層ずつ加えました。この 20 編をすべて追ってきた時点なら K8s を導入して運用する人の視野 — 「どの CNI を導入するか、どのポリシーエンジンを導入するか、どのオブザーバビリティスタックを選ぶか、GitOps パイプラインをどう組むか」を決定する段階の視野が手に入ります。

次のトラック — K8s 実戦 #

高級シリーズまでが K8s のオブジェクトモデルとポリシーの深さを扱ったとすれば、K8s 実戦 6 編はその上に本物のサービスを 1 つ載せて運用する 1 サイクルです。中級 #7 で事前に整理した表を再び持ってくると次のとおりです。

テーマ説明
EKS クラスタセットアップAWS EKS クラスタを最初から、IAM、VPC、ノードグループ、アドオン。
アプリデプロイ骨格Deployment + Service + Ingress + ConfigMap + Secret の 1 セット、Helm chart で整理。
DB 連動RDS / Aurora を Pod から安全に呼ぶ道、Secrets Manager 統合、コネクションプール。
CI/CD パイプラインGitHub Actions でコンテナビルド → ECR push → ArgoCD sync。
モニタリング・アラームCloudWatch + Prometheus、核心アラームルールセット、on-call 流れ。
運用チェックリストアップグレード、バックアップ・リカバリ、コスト点検、セキュリティ点検の定期運用サイクル。

基礎・中級・高級トラックが K8s をマニフェスト次元で理解する道だったとすれば、実戦トラックは EKS の上に 1 つのサービスを最初から最後まで追う道です。抽象ではなく本当の導入事例でトラックを閉じます。

締めくくり #

K8s 高級シリーズ 6 編を締めくくります。この記事ではマニフェストの source of truth を git に置く GitOps モデル — push 対 pull、ArgoCD の Application CRD と sync wave、Flux の小さなコントローラの束、ディレクトリ構造、Sealed Secrets / External Secrets で秘密を git に置く道までを 1 サイクルで整理しました。シリーズ全体で見ると、基礎 7 編・中級 7 編がマニフェストとその運用の深さだったとすれば、高級 6 編はその上にポリシー・拡張・観測・同期の肌理を 1 層ずつ加えた段階でした。次のトラックである K8s 実戦 6 編では EKS クラスタセットアップからアプリデプロイ骨格、DB 連動、CI/CD パイプライン、モニタリング・アラーム、運用チェックリストまで — 本物のサービスを 1 つ載せる 1 サイクルを最初から最後まで追います。

X