K8s 高級 #6 GitOps — ArgoCD / Flux
K8s 高級シリーズの最後の記事です。#1 CNI から #5 オブザーバビリティ までクラスタのデータプレーン・権限・ポリシー・拡張・観測を 1 層ずつ積み上げてきました。この記事はそのすべてのマニフェストがクラスタに入る 方式自体 を扱います — GitOps です。kubectl apply を人が手で回す代わりに、マニフェストの source of truth を git に置いてクラスタ内のコントローラが git を watch して自動で同期する運用モデルです。ArgoCD と Flux がこのモデルの 2 つの標準実装で、シリーズ最後の記事として 2 つのツールのモデル・運用パターン・シリーズ振り返り・次のトラックまで 1 サイクルでまとめます。
このシリーズは K8s 高級 6 編です。
- #1 CNI 深さ — Calico / Cilium / eBPF
- #2 RBAC / ServiceAccount 深さ — Aggregated ClusterRole / Impersonation / IRSA / Workload Identity
- #3 Admission Controller — OPA Gatekeeper / Kyverno
- #4 CRD と Operator パターン — controller-runtime
- #5 オブザーバビリティ — Prometheus / Grafana / Loki / OpenTelemetry
- #6 GitOps — ArgoCD / Flux ← この記事
Push モデルと Pull モデル #
まず GitOps が登場する前の標準だったモデルと比較します。CI/CD パイプラインがクラスタにマニフェストを適用する方式は大きく 2 つの道です。
| モデル | 流れ |
|---|---|
| Push | CI パイプラインがクラスタの 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 Immutable | desired 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 です。
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 に適用されると次のことが自動で起こります。
- ArgoCD コントローラが
repoURLのpathディレクトリを git から取ってくる - Kustomize / Helm / 一般 YAML を自動認識してマニフェストをレンダリング
- クラスタの
destinationに同期 (automated.selfHeal: trueなので drift を自動回復) - git のマニフェストが変更されると自動で再同期 (
automated) - git から消えたオブジェクトはクラスタからも削除 (
prune: true)
App of Apps — Application の束管理 #
複数の Application を 1 か所で管理するパターンが App of Apps です。1 つの Application の source が他の Application マニフェストの入っているディレクトリを指す構造です。
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 でこの順序を表現します。
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-controller | git / Helm 保存所 / OCI イメージからマニフェストを fetch |
| kustomize-controller | Kustomize マニフェストを適用 |
| helm-controller | HelmRelease オブジェクトで Helm chart を適用 |
| notification-controller | Slack / Teams / GitHub などにイベント通知 |
| image-automation-controller | コンテナイメージの新しいバージョンを git に自動 commit |
各コントローラが自分の CRD を持ち、その CRD のマニフェストですべての動作が表現されます。
GitRepository + Kustomization — Flux の基本束 #
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-appGitRepository が git を watch し、Kustomization がその git の 1 つのディレクトリをクラスタに適用します。2 つのオブジェクトの分離のおかげで同じ git を複数の Kustomization が異なる path で指せます。
HelmRelease — Helm chart の GitOps 化 #
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: 30dhelm install を手で回す代わりに HelmRelease マニフェストで表現すれば Helm chart のインストール・アップグレードも GitOps の流れの中に入ってきます。
ArgoCD vs Flux — 選択の肌理 #
| 次元 | ArgoCD | Flux |
|---|---|---|
| モデル | 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.yamlKustomize の 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 Secrets | Bitnami が作ったツール。秘密を SealedSecret として暗号化して git にアップロード。クラスタ内のコントローラが自分のキーでのみ復号化可能。 |
| External Secrets Operator | git には外部秘密保存所(AWS Secrets Manager、Vault など)の参照だけ置き、コントローラが K8s Secret として同期。 |
| SOPS + age/PGP | git に暗号化された 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 編を一度押さえておきます。
- #1 — CNI 深さ。K8s ネットワークモデルの 4 条件、CNI インターフェース、iptables / IPVS / eBPF のデータプレーン、Calico と Cilium の比較。
- #2 — RBAC / ServiceAccount 深さ。Aggregated ClusterRole、Impersonation、projected token、IRSA / Workload Identity で K8s ServiceAccount をクラウド IAM と接続。
- #3 — Admission Controller。API サーバの 5 段階フロー、mutating / validating webhook、OPA Gatekeeper と Kyverno のポリシーエンジン比較。
- #4 — CRD と 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 サイクルを最初から最後まで追います。