GKEのConfig Sync・Policy Controller・Config Connectorの使い分けまとめ

GKE(Google Kubernetes Engine)を単一クラスタで使う段階では、Deployment、Service、IngressなどのKubernetesリソースを理解することが中心になります。一方で、クラスタやチームが増えてくると、設定をどうそろえるか、危険な設定をどう防ぐか、Google Cloudリソースまで同じ運用モデルで扱うか、という論点が出てきます。

この記事では、『GKE Fleet・マルチクラスタGKE・MCSの関係まとめ』で見た複数クラスタ構成の続きとして、Config Sync、Policy Controller、Config Connectorの役割を整理します。これらの機能は単一クラスタでも使えますが、個別管理のずれや運用ルールのばらつきが目立ちやすいのは複数クラスタ構成です。そのため本記事では、複数クラスタ運用を主な文脈にして、同期ポリシー制御Google Cloudリソース管理の違いを見ていきます。

この記事でわかること
  • Config Sync、Policy Controller、Config Connectorの役割の違い
  • 3つがGKEやFleetの運用でどこに関係するか
  • Config SyncとPolicy Controllerを組み合わせる理由
  • Config ConnectorとTerraformの見方の違い

GKE運用統制におけるConfig Sync・Policy Controller・Config Connectorの立ち位置

Config Sync、Policy Controller、Config Connectorは、どれもGKEやKubernetesの文脈で出てくるため混ざりやすいです。ただし、見ている対象は違います。

仕組み主な管理対象答える問い
Config SyncKubernetes設定Gitリポジトリなどに置いた設定を、どのクラスタへ反映するか
Policy ControllerKubernetes APIに入るリソースその設定や変更を、クラスタに入れてよいか
Config ConnectorGoogle CloudリソースCloud Storage bucketやPub/Sub topicなどを、Kubernetes経由で管理するか

関係を図にすると次のようになります。

flowchart TB
  Repo["Gitリポジトリ"]
  ConfigSync["Config Sync"]

  subgraph Fleet["Fleet"]
    subgraph Cluster["GKEクラスタ"]
      Policy["Policy Controller"]
      K8s["Kubernetesリソース"]
      CcResource["Config Connector用リソース"]
      Connector["Config Connector"]
    end
  end

  Cloud["Google Cloudリソース"]

  Repo --> ConfigSync
  ConfigSync -->|"同期"| K8s
  ConfigSync -->|"同期"| CcResource
  Policy -. "判定" .-> K8s
  CcResource --> Connector
  Connector -->|"Google Cloud API"| Cloud

図では、GitリポジトリからGKEクラスタへ設定を同期する役割がConfig Syncです。ここでいうKubernetesリソースは、Deployment、Service、Namespace、RBAC、NetworkPolicyなど、Kubernetes APIで管理する設定や管理対象を指します。Policy Controllerは、クラスタに入るKubernetesリソースがポリシーに違反していないかを判定します。

Google Cloudリソースは、Cloud Storage bucket、Pub/Sub topic、IAM設定など、Google Cloud APIで管理するリソースを指します。Config Connectorは、Kubernetes上に作られたConfig Connector用リソースをもとにGoogle Cloud APIを呼び出し、Google Cloudリソースを管理します。

つまり、3つは同じ「GKE運用」の話に見えても、設定を配るのか設定を検査するのかGoogle Cloudリソースを管理するのかで分かれます。

Config SyncはKubernetes設定をGitなどから同期する

Config Syncは、Gitリポジトリなどを設定の正とし、その内容をGKEクラスタへ同期する仕組みです。

GitOpsという考え方では、Gitのようなバージョン管理システムを設定の正として扱います。手元から各クラスタへ kubectl apply を繰り返すのではなく、レビュー済みの設定をリポジトリに置き、クラスタ側がその状態へ近づくようにします。

Config Syncの同期元には、GitリポジトリのほかにOCI image(Open Container Initiative形式のイメージ)やHelm chart(Kubernetes設定をパッケージ化する形式)も使えます。ただし、本記事では仕組みを理解しやすいように、Gitリポジトリを設定の正にする例で説明します。

Config Syncが役立つのは、クラスタが増えたときです。クラスタごとにnamespace、RBAC(Role-Based Access Control。Kubernetes上の権限制御)、NetworkPolicy、Policy Controllerの制約などを手作業で入れていると、設定の差分が見えにくくなります。あるクラスタだけ古い設定のまま残る、誰かが直接変更してGit上の定義とずれる、といった状態も起きます。

Config Syncを使うと、中央の設定を複数クラスタへ同期し、クラスタの状態が設定の正からずれたときに戻せます。ここでの中心は、Kubernetes設定の配布と差分の修正です。

Gitリポジトリには、たとえば次のようなKubernetes manifestを置きます。これは app というnamespaceを作る単純な例です。

apiVersion: v1
kind: Namespace
metadata:
  name: app
  labels:
    team: backend

Config Syncで同期したくなる変更には、次のようなものがあります。

変更例同期したい理由
全クラスタに共通namespaceを追加するアプリ配置先や管理単位をクラスタ間でそろえるため
RBACのRoleやRoleBindingを更新するチームごとの操作権限を手作業でばらつかせないため
NetworkPolicyを追加するPod間通信の許可範囲をクラスタ間でそろえるため
Policy Controllerの制約を配布する禁止したい設定や監査ルールを複数クラスタへ同じ形で入れるため

Config Syncは、このようなmanifestを読み取り、対象クラスタのKubernetes APIへ適用します。その結果として、各クラスタ内にNamespaceなどのKubernetesリソースが作成・更新されます。

flowchart TB
  Repo["Gitリポジトリ"]
  Manifest["Kubernetes manifest"]
  ConfigSync["Config Sync"]

  subgraph Fleet["Fleet"]
    subgraph ClusterA["GKEクラスタ A"]
      ResA["Kubernetesリソース"]
    end

    subgraph ClusterB["GKEクラスタ B"]
      ResB["Kubernetesリソース"]
    end
  end

  Repo --> Manifest
  Manifest --> ConfigSync
  ConfigSync --> ResA
  ConfigSync --> ResB

この図では、Gitリポジトリに置いたKubernetes manifestをConfig Syncが読み取り、複数のGKEクラスタへKubernetesリソースとして反映しています。Config Syncは、アプリケーションの通信制御そのものやGoogle Cloudリソース作成そのものを担当するのではなく、クラスタに適用するKubernetes設定をそろえる役割です。

Policy Controllerは入れてよい設定かを判定する

Policy Controllerは、Kubernetesクラスタに対してプログラム可能なポリシーを適用し、設定がルールに違反していないかを監査または強制する仕組みです。

Policy Controllerは、Open Policy Agent Gatekeeperをベースにしています。Open Policy Agentは、ポリシーをコードとして扱うためのオープンソースの仕組みです。Gatekeeperは、そのポリシー判定をKubernetes APIへの適用時や既存リソースの監査に組み込むためのプロジェクトです。

たとえば、次のようなルールをクラスタに適用したい場面があります。

  • 特定のコンテナイメージレジストリ以外を使わせない
  • privileged modeのコンテナを禁止する
  • namespaceに必須ラベルを付けさせる
  • Service Meshで必要な設定の抜け漏れを監査する

Config Syncが「設定をクラスタへ届ける」仕組みだとすると、Policy Controllerは「その設定を入れてよいか」を判定する仕組みです。ポリシー違反をすぐブロックする強制だけでなく、まず監査して違反を見つける使い方もできます。

Config Sync経由の場合、Pull RequestがマージされるとConfig Syncがmanifestをクラスタへ同期しようとします。そのmanifestがKubernetes APIに入る段階で、Policy ControllerがAdmission Controllerとして判定します。つまり、Policy ControllerがGitのPull Requestを直接ブロックするわけではないので注意が必要です。

たとえば、privileged modeのコンテナを禁止するポリシーがあるクラスタに、次のようなPod manifestを同期しようとするとします。

apiVersion: v1
kind: Pod
metadata:
  name: privileged-sample
spec:
  containers:
    - name: app
      image: nginx
      securityContext:
        privileged: true

このmanifestがConfig Syncで同期される場合、流れは次のようになります。

flowchart TB
  Pr["Pull Request"]
  Repo["Gitリポジトリ"]
  ConfigSync["Config Sync"]
  Api["Kubernetes API"]
  Policy["Policy Controller"]
  Cluster["GKEクラスタ"]
  Error["同期エラー"]

  Pr -->|"マージ"| Repo
  Repo --> ConfigSync
  ConfigSync -->|"manifestを適用"| Api
  Api -->|"Admission判定"| Policy
  Policy -->|"許可"| Cluster
  Policy -. "拒否" .-> Error

この図では、Pull Requestのマージ自体をPolicy Controllerが止めるわけではありません。止まるのは、Config SyncがmanifestをKubernetes APIへ適用しようとしたタイミングです。上のPod manifestは securityContext.privilegedtrue になっているため、privileged mode禁止のポリシーに違反します。そのため、強制モードではこのPodはクラスタに作成されず、Config Sync側では同期エラーとして見えます。

一方で、事前チェックをCIに組み込めば、Pull Request段階でポリシー違反を検出する運用もできます。ただし、それはCI側に検査を追加した場合の話です。Policy Controller本体の基本的な判定位置は、Kubernetes APIへの適用時と、既存リソースに対する監査です。

監査モードでは、違反したリソースをただちに拒否するのではなく、クラスタ内にあるリソースがルールに合っているかを検出します。既存クラスタにいきなり強制を入れると影響が大きい場合は、まず監査で違反状況を把握し、その後に強制へ進める使い方ができます。

Policy Controllerの制約自体もKubernetesリソースとして扱えるため、Config Syncで複数クラスタへ配布できます。つまり、Config SyncとPolicy Controllerは競合するものではなく、ポリシーを配る役割ポリシーで判定する役割として組み合わせられます。

Config ConnectorはGoogle CloudリソースをKubernetesから管理する

Config Connectorは、Google CloudリソースをKubernetes経由で管理するためのアドオンです。

Kubernetesには、Custom Resource Definition(CRD)という拡張の仕組みがあります。CRDは、Kubernetes APIに独自のリソース種類を追加するための仕組みです。Config Connectorはこの仕組みを使い、Cloud Storage bucket、Pub/Sub topic、IAM(Identity and Access Management。Google Cloudの権限管理)設定などのGoogle CloudリソースをKubernetesリソースとして表現します。

Config Connectorの中心は、Kubernetesの宣言とGoogle Cloud APIの橋渡しです。KubernetesにConfig Connector用のリソースを作ると、Config ConnectorのコントローラがGoogle Cloud APIを呼び出し、実際のGoogle Cloudリソースを作成・更新・削除します。

flowchart TB
  Manifest["Kubernetes manifest"]
  Api["Kubernetes API"]
  Connector["Config Connector"]
  Resource["Google Cloudリソース"]

  Manifest --> Api
  Api --> Connector
  Connector -->|"Google Cloud API"| Resource

この図では、利用者がKubernetes manifestを適用し、Config ConnectorがGoogle Cloud APIを通じてGoogle Cloudリソースを管理しています。GKE上のPodを増やす話ではなく、Google Cloud側のリソースをKubernetesの管理モデルに寄せる話です。

具体例: Kubernetes manifestからCloud Storage bucketを作る

たとえば、アプリケーションのログやアップロードファイルを置くCloud Storage bucketを、アプリのKubernetes設定と同じ流れで管理したい場面を考えます。通常はGoogle Cloud Console、gcloud、Terraformなどで作るリソースですが、Config Connectorを使うとKubernetes manifestとして宣言できます。

Cloud Storage bucketは、Config Connectorでは次のような StorageBucket リソースとして表現します。metadata.name はbucket名として使われるため、実際にはグローバルに一意な名前にします。以下は説明用の例です。

apiVersion: storage.cnrm.cloud.google.com/v1beta1
kind: StorageBucket
metadata:
  name: example-app-logs-bucket
  annotations:
    cnrm.cloud.google.com/project-id: example-project-id
spec:
  location: ASIA-NORTHEAST1
  uniformBucketLevelAccess: true

このmanifestは、「example-project-id というGoogle Cloudプロジェクトに、example-app-logs-bucket というCloud Storage bucketを東京リージョンで作る」という宣言です。Kubernetes上では StorageBucket というリソースを追加する形ですが、実際に作られるものはGoogle Cloud側のCloud Storage bucketです。

このmanifestをKubernetes APIへ適用すると、Config Connectorがそれを監視し、Google Cloud APIを呼び出してCloud Storage bucketを作成します。manifestを変更すればbucket設定の更新、manifestを削除すれば対応するGoogle Cloudリソースの削除、というように、Kubernetesの宣言的な管理モデルでGoogle Cloudリソースを扱います。

注意点は、Google Cloud APIを呼び出す主体です。Config Connectorは、マニフェストを適用した人間ユーザーの権限ではなく、Config Connectorに割り当てたIAM Service Account(Google Cloud上の実行主体)の権限でGoogle Cloudリソースを変更します。そのため、Kubernetes上でConfig Connectorリソースを作れる人は、間接的にGoogle Cloudリソースを変更できることになります。

この性質はCI/CD(継続的インテグレーション/継続的デリバリー)と似ています。Gitリポジトリへマージできる人が、パイプラインの権限で本番へデプロイできるのと同じように、Config Connectorリソースを作れる人は、Config Connectorの権限でGoogle Cloudリソースを変更できます。したがって、Kubernetes RBACやリポジトリのレビュー権限を含めて管理する必要があります。

補足: 同じCloud Storage bucketをTerraformでもConfig Connectorでも作れる

直前のCloud Storage bucketは、Terraformでも作れます。たとえばTerraformでは、同じようなbucketを次のように宣言します。

resource "google_storage_bucket" "app_logs" {
  name                        = "example-app-logs-bucket"
  project                     = "example-project-id"
  location                    = "ASIA-NORTHEAST1"
  uniform_bucket_level_access = true
}

つまり、Cloud Storage bucketを作るだけなら、TerraformでもConfig Connectorでも実現できます。違いは、どこに宣言を書き、どの仕組みがGoogle Cloudへ反映するかです。

仕組み宣言を書く場所Google Cloudへ反映する方法
TerraformTerraformファイルterraform apply を実行して反映する
Config ConnectorKubernetes manifestKubernetes APIに入ったmanifestをもとに、Config ConnectorのコントローラがGoogle Cloudへ反映する

Terraformでは、Terraformファイルを変更し、terraform planterraform apply を実行してGoogle Cloudリソースへ反映します。そのとき、Terraform state(Terraformが管理対象の現在状態を記録する情報)を使って、どのリソースを作成・更新・削除するかを判断します。

Config Connectorでは、Kubernetes manifestをKubernetes APIへ適用します。Gitで管理している場合、変更の起点はPull Requestのマージです。マージ後にConfig SyncなどでmanifestがKubernetes APIへ入ると、Config ConnectorのコントローラがGoogle Cloudリソースへ反映します。

その後も、Config ConnectorのコントローラはGoogle Cloudリソースの状態を監視し、manifestで宣言した状態へ近づけ続けます。このように現在の状態を望ましい状態へ近づけ続ける制御ループをreconcileと呼びます。

使い分けとしては、そのGoogle Cloudリソースを基盤全体の設定として管理するのか、それともGKEアプリの設定に近いリソースとして管理するのかで考えると分かりやすいです。

ユースケース選びやすい仕組み理由
VPC、IAM、共有DBなど、複数アプリや環境の土台になるGoogle Cloudリソースを管理したいTerraformGKEに限らず、Google Cloud全体のIaC(Infrastructure as Code。インフラ設定をコードで管理する考え方)として使いやすいため
GKEアプリを追加・削除するタイミングで、そのアプリ専用のCloud Storage bucketやPub/Sub topicも一緒に作成・削除したいConfig Connectorアプリ用のKubernetesリソースと、アプリ専用のGoogle Cloudリソースを同じKubernetes API上で扱えるため
すでにTerraformで基盤管理が安定しているTerraformを継続同じリソースを複数の仕組みで管理すると、どちらが正なのか分かりにくくなるため

TerraformとConfig Connectorは、どちらか一方だけを使うものとは限りません。TerraformでネットワークやIAMなどの土台を管理し、Config Connectorで特定のGKEアプリ専用のbucketやtopicを管理する、という分け方もできます。

ただし、同じGoogle CloudリソースをTerraformとConfig Connectorの両方で管理しないようにします。どちらの宣言が正なのか分からなくなり、片方で変更した内容をもう片方が戻してしまう、といった混乱につながるためです。

Config Connectorに明確なデメリットがあるというより、管理責任の置き場所が変わる点に注意します。Kubernetes上でConfig Connectorリソースを作れる人が、間接的にGoogle Cloudリソースを変更できるため、Kubernetes RBACやレビュー権限の設計が重要になります。

すでにTerraformでGoogle Cloud基盤を管理しているなら、Config Connectorを無理に置き換えとして見る必要はありません。

3機能を組み合わせると役割分担がはっきりする

3つを組み合わせると、次のような役割分担になります。

flowchart TB
  Repo["Gitリポジトリ"]

  subgraph Cluster["GKEクラスタ"]
    ConfigSync["Config Sync"]
    Policy["Policy Controller"]
    K8s["Kubernetesリソース"]
    Connector["Config Connector"]
  end

  Cloud["Google Cloudリソース"]

  Repo -->|"設定の正"| ConfigSync
  ConfigSync -->|"同期"| K8s
  Policy -. "判定" .-> K8s
  K8s --> Connector
  Connector --> Cloud

この図では、Gitリポジトリに置いたKubernetes設定をConfig Syncが同期します。同期された設定は、Policy Controllerのポリシーで監査または強制されます。その中にConfig Connector用のリソースがあれば、Config ConnectorがGoogle Cloudリソースを管理します。

同じGitリポジトリに置けるからといって、3つが同じ役割になるわけではありません。Config Syncは配布、Policy Controllerは判定、Config ConnectorはGoogle Cloud APIへの反映を担当します。

この役割分担を押さえると、設計時の問いも分けやすくなります。

やりたいこと見る仕組み理由
複数クラスタのnamespaceやRBACをGitでそろえたいConfig SyncKubernetes設定を中央の正から同期するため
危険なPod(Kubernetesでアプリケーションを動かす最小単位)設定や運用ルール違反を止めたいPolicy ControllerKubernetes APIに入るリソースをポリシーで判定するため
Cloud Storage bucketやPub/Sub topicをKubernetes manifestで管理したいConfig ConnectorGoogle CloudリソースをKubernetes API経由で管理するため

まとめ

  • Config Syncは、Gitリポジトリなどを設定の正としてKubernetes設定をGKEクラスタへ同期する
  • Policy Controllerは、Kubernetesリソースがポリシーに違反していないかを監査または強制する
  • Config Connectorは、Kubernetes APIを通じてGoogle Cloudリソースを管理する
  • Config SyncとPolicy Controllerは、ポリシーを配る役割とポリシーで判定する役割として組み合わせられる
  • Config ConnectorはGoogle Cloudリソース管理をKubernetes側へ寄せる仕組みであり、既存のTerraform管理を必ず置き換えるものではない
  • 3つを混同しそうなときは、配布、判定、Google Cloud APIへの反映のどれをしたいのかで考える

参考

タグ: GCP, クラウド設計, システム設計