午前2時のドリフトの惨劇
午前2時14分、ポケットベルが鳴り響きました。本番環境の重要なサービスが503エラーを吐き出していました。クラスターを調査したところ、原因が判明しました。デプロイ設定がリポジトリと一致していなかったのです。ルーティングのバグ修正に追われていたエンジニアが、CI/CDパイプラインをバイパスするためにkubectl editを使用していました。当座の問題は解決したものの、その変更をソースコードにコミットし忘れていたのです。
コードと乖離した瞬間、あなたのクラスターは「スノーフレーク(唯一無二の、再現不可能な存在)」になります。手動操作やプッシュ型の世界では、リポジトリは単なる「推奨事項」に過ぎず、信頼できる唯一の情報源(Source of Truth)ではありません。インフラをGitOpsに移行したことで、すべてが変わりました。チームの焦点は手動エラーの火消しから、ピアレビューによる安定性へと移り、夜もしっかり眠れるようになりました。
なぜ「プッシュ vs プル」論争でFluxCDが勝つのか
JenkinsやGitHub Actionsは通常「プッシュ」モデルを使用します。これらはスクリプトを実行し、kubectl applyを叩き、ネットワークが切断されないことを祈ります。もしクラスターに10秒間接続できなければプッシュは失敗し、環境は同期されないままになります。FluxCDはこの論理を逆転させます。Fluxはクラスター内に一連のコントローラーとして常駐し、Gitから設定を「プル」します。
Fluxは1分ごとにリポジトリを監視します。もし午前2時の手動編集のような不整合を検知すると、即座にクラスターの状態をコードに合わせるよう上書きします。許可を求めることはありません。真実を強制するのです。
Fluxコントロールプレーンのセットアップ
まずはFlux CLIとKubernetesクラスターが必要です。GKE、EKS、あるいはローカルのKindクラスターであっても、プロセスは同じです。Flux CLIは、SSHキーの生成やコントローラーのデプロイを含む複雑なブートストラッププロセスを一括で処理してくれるため、最適なツールです。
1. Flux CLIの取得
LinuxまたはmacOSの場合は、次のクイックスクリプトを使用してバイナリを取得します:
curl -s https://fluxcd.io/install.sh | sudo bash
# バイナリがパスに含まれていることを確認
flux --version
2. 事前チェック(Pre-flight Check)
すべてのクラスターがすぐにGitOpsを利用できる状態とは限りません。このチェックを実行して、KubernetesのバージョンとRBAC権限を確認してください:
flux check --pre
ブートストラップ:クラスターに「脳」を与える
bootstrapコマンドはGitOpsセットアップの基盤です。プライベートリポジトリを作成し(存在しない場合)、デプロイキーを設定し、Fluxコントローラーをflux-systemネームスペースにインストールします。これにより、Fluxは自己管理型になります。将来Flux自体をアップグレードしたい場合は、Git上のバージョン番号を変更するだけです。
認証情報のエクスポート
GitHubでrepo権限を持つ個人アクセストークン(PAT)を生成し、エクスポートします:
export GITHUB_TOKEN=ここにトークンを入力
export GITHUB_USER=ユーザー名
ブートストラップの実行
flux bootstrap github \
--owner=$GITHUB_USER \
--repository=fleet-infra \
--branch=main \
--path=./clusters/my-cluster \
--personal
約90秒後、アカウントに新しいプライベートリポジトリが作成されます。このリポジトリがクラスターの「脳」となります。
信頼できる唯一の情報源(Source of Truth)の定義
エンジンが起動したら、アプリケーションコードを指定する必要があります。Fluxは主に2つのリソースを使用します:GitRepository(コードの場所)とKustomization(適用方法)です。
1. アプリリポジトリの接続
webapp-configリポジトリの変更を30秒ごとにチェックするようFluxに指示します:
flux create source git webapp-repo \
--url=https://github.com/my-org/webapp-config \
--branch=main \
--interval=30s \
--export > ./clusters/my-cluster/webapp-source.yaml
2. デプロイ戦略の設定
Kustomizationリソースは実際の指示セットです。--prune=trueフラグは必ず使用してください。これにより、Git上でYAMLファイルを削除すると、Fluxがそのリソースを5分以内にクラスターから削除することを保証します。プルーニング(削除)を行わないと、クラスターは古い、孤立したサービスの墓場になってしまいます。
flux create kustomization webapp-deploy \
--target-namespace=production \
--source=webapp-repo \
--path="./deploy/prod" \
--prune=true \
--wait=true \
--interval=5m \
--export > ./clusters/my-cluster/webapp-kustomization.yaml
これらのファイルをfleet-infraにコミットします。数秒以内にFluxが新しい指示をプルし、デプロイを開始します。
強制力のテスト
信頼しつつも、検証は不可欠です。システムが動作することを証明するために、私はいつも「カオステスト」を行います。CLIを使用して、手動でデプロイを10個のレプリカにスケールさせます:
kubectl scale deployment my-webapp --replicas=10 -n production
ここでFluxのログを監視するか、調整(reconciliation)インターバルを待ちます。Fluxが、クラスターの状態(10レプリカ)がGitの状態(3レプリカ)に違反していることを検知するのがわかります。すると、自動的にポッドが元の数にスケールダウンされます。その瞬間、ようやく自分のインフラを完全に信頼できるようになったと実感するでしょう。
アラート設定:エラーを早期に発見する
本番環境のGitOpsには可視性が必要です。同期が失敗したかどうかを確認するためにCLIを叩き続ける必要はありません。FluxはSlackやMicrosoft Teamsと連携し、開発者が壊れたYAMLファイルをプッシュした瞬間にアラートを送信できます。
flux create alert-provider slack-notifier \
--type=slack \
--channel=ops-alerts \
--address=https://hooks.slack.com/services/XXXXX \
--export > ./clusters/my-cluster/slack-provider.yaml
今では「壊れたGitの状態」を営業時間内にキャッチできています。マニフェストが無効な場合、マージから15秒以内にチームにSlack通知が届きます。それが午前2時の緊急事態になるずっと前の段階で対処できるのです。
結論
FluxCDによるGitOpsは、クラスターをコードの鏡へと変えます。デプロイフェーズから「人間要素」を排除し、すべての変更をドキュメント化され、ピアレビューを経たプルリクエスト経由に強制します。最初は不自由(硬直的)に感じるかもしれません。しかし、99.9%の設定整合性と、あらゆるインフラ変更を監査できる能力は、現代のDevOpsチームにとって欠かせない標準となっています。

