フリート全体でチームのリソースを管理する

このページでは、Config Sync と Terraform を使用して、クラスタ フリートのチームスコープ リソースを動的に作成する方法について説明します。Config Sync は、フリートチーム管理の機能を拡張し、フリート全体でインフラストラクチャとクラスタ構成を作成、管理できるようにします。

このガイドは、チームスコープやフリートの Namespace など、フリートチーム管理のコンセプトに精通していることを前提としています。詳細については、フリートチーム管理の概要をご覧ください。

サンプル構成を使用したエンドツーエンドのチュートリアルについては、サンプル リポジトリのフリート テナンシーのチュートリアルをご覧ください。

Terraform で Config Sync がサポートするフィールドの一覧については、GKE フリート機能の Terraform リファレンス ドキュメントをご覧ください。

ワークフローの例

プラットフォーム管理者は、チームごとにニーズが異なるクラスタ フリート全体でリソースを動的に作成したいと考えています。たとえば、特定の NetworkPolicy をバックエンド チームの Namespace に適用し、フロントエンド チームの Namespace には適用したくない場合があります。このシナリオの場合、Namespace 全体でチームスコープのリソースを作成するには、次のことを行います。

  1. チームのリソースを管理するフリートを選択または作成します。
  2. 信頼できる情報源を設定します。信頼できる情報源には、チームスコープでフリートレベルの Namespace を選択するために使用する NamespaceSelector オブジェクトと、それらの Namespace 間で同期するリソース(NetworkPolicy など)が含まれます。
  3. Config Sync のフリートレベルのデフォルト構成を作成します。Config Sync は、前の手順で作成した信頼できる情報源から同期するときに、これらのデフォルトを使用します。この Config Sync の設定は、フリートで作成された新しいクラスタに適用されます。

  4. フリートにクラスタを作成します。

  5. Config Sync が Namespace 内のリソースを検出して調整できるように、フロントエンドとバックエンドのチームスコープと Namespace を作成します。

これらの手順が完了すると、Config Sync は NamespaceSelector に基づいて NetworkPolicy を作成し、バックエンド チームの Namespace に適用します。リソースを変更または追加すると、Config Sync は構成ファイル、チームスコープ、フリート Namespace、フリート メンバーに対する変更を検出して適用します。

料金

Config Sync とフリートチーム管理機能を利用できるのは、GKE Enterprise を有効にしたユーザーだけです。GKE Enterprise の料金の詳細については、GKE の料金ページをご覧ください。

始める前に

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Google Cloud CLI をインストールします。
  3. gcloud CLI を初期化するには:

    gcloud init
  4. Google Cloud プロジェクトを作成または選択します

    • Google Cloud プロジェクトを作成します。

      gcloud projects create PROJECT_ID

      PROJECT_ID は、作成する Google Cloud プロジェクトの名前に置き換えます。

    • 作成した Google Cloud プロジェクトを選択します。

      gcloud config set project PROJECT_ID

      PROJECT_ID は、実際の Google Cloud プロジェクト名に置き換えます。

  5. Google Cloud CLI をインストールします。
  6. gcloud CLI を初期化するには:

    gcloud init
  7. Google Cloud プロジェクトを作成または選択します

    • Google Cloud プロジェクトを作成します。

      gcloud projects create PROJECT_ID

      PROJECT_ID は、作成する Google Cloud プロジェクトの名前に置き換えます。

    • 作成した Google Cloud プロジェクトを選択します。

      gcloud config set project PROJECT_ID

      PROJECT_ID は、実際の Google Cloud プロジェクト名に置き換えます。

  8. 構成ファイルを保存する信頼できる情報源(Git リポジトリまたは OCI イメージ)を作成するか、この情報源にアクセスできるようにします。このガイドの例では、Git リポジトリを使用しています。

必要なロール

フリートのチームリソースを作成するために必要な権限を取得するには、プロジェクトに対して次の IAM ロールを付与するよう管理者に依頼してください。

ロールの付与の詳細については、アクセス権の管理をご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

ユーザーの認証情報を取得する

このガイドの Terraform コマンドをローカル環境で実行するには、次のコマンドを実行して新しいユーザー認証情報を取得します。

gcloud auth application-default login

フリートを設定する

このセクションでは、フリートを作成して、必要なサービスを有効にします。

フリートを設定する手順は次のとおりです。

  1. フリート構成の Terraform ファイルのディレクトリを作成します。このディレクトリに、main.tf ファイルと variables.tf ファイルを追加します。

  2. variables.tf ファイルに次の変数を追加します。

    variable "project" {
      type = string
      description = "GCP project ID"
    }

  3. main.tf ファイルに次のリソースを追加します。

    terraform {
      required_providers {
        google = {
          source = "hashicorp/google"
          version = ">= 5.16.0"
        }
      }
    }
    
    provider "google" {
      # project variable must be provided at runtime
      project = var.project
    }
    
    # Enable API services
    resource "google_project_service" "services" {
      for_each = toset([
        "gkehub.googleapis.com",
        "container.googleapis.com",
        "connectgateway.googleapis.com",
        "cloudresourcemanager.googleapis.com",
        "iam.googleapis.com",
        "anthos.googleapis.com",
        "anthosconfigmanagement.googleapis.com",
      ])
      service = each.value
      disable_on_destroy = false
    }
    
    # Declare a fleet in the project
    resource "google_gke_hub_fleet" "default" {
      display_name = "demo"
    
      depends_on = [google_project_service.services]
    }
  4. PROJECT_ID 変数をエクスポートします。

    export TF_VAR_project=PROJECT_ID
    

    PROJECT_ID は、フリートを作成するプロジェクト ID に置き換えます。

  5. 作成したディレクトリで Terraform を初期化します。

    terraform init
    
  6. Terraform で示した変更が、想定されているプランと一致していることを確認します。

    terraform plan
    
  7. フリートを作成して API を有効にし、サービス アカウントを作成します。

    terraform apply
    

    すべてのサービスが有効になるまでに数分かかることがあります。

信頼できる情報源を設定する

このセクションでは、信頼できる情報源に構成ファイルを追加します。使用するチームスコープごとに NamespaceSelector オブジェクトが必要です。たとえば、フロントエンド チームとバックエンド チームがある場合、チームごとに NamespaceSelector オブジェクトを作成する必要があります。NamespaceSelector オブジェクトは、チームスコープ内の Namespace のすべてまたは一部を選択します。信頼できる情報源に、NetworkPolicy などのチームリソースを追加できます。これらのリソースを作成するときに NamespaceSelector を参照すると、Config Sync はこれらのリソースを Namespace 間で動的にデプロイして同期できます。

信頼できるソースを設定するには、次の操作を行います。

  1. 信頼できる情報源で、Config Sync から同期する構成ファイルのディレクトリを作成します。

  2. チームごとに、構成ディレクトリに NamespaceSelector オブジェクトを作成します。

    apiVersion: configmanagement.gke.io/v1
    kind: NamespaceSelector
    metadata:
       name: NAMESPACE_SELECTOR_NAME
    spec:
      mode: dynamic
      selector:
        matchLabels:
          fleet.gke.io/fleet-scope: SCOPE_NAME
    

    次のように置き換えます。

    • NAMESPACE_SELECTOR_NAME: NamespaceSelector オブジェクトの名前(backend-scope など)。
    • SCOPE_NAME: チームスコープの名前(例: backend)。

    フリートの Namespace に含まれる Namespace には、自動的にラベル fleet.gke.io/fleet-scope: SCOPE_NAME が付きます。NamespaceSelector は、そのラベルを使用して、チームスコープのすべてのフリート Namespace を選択します。Namespace を含める例と除外する例については、NamespaceSelector の例をご覧ください。

  3. Namespace 間で同期するオブジェクトを作成します。

    オブジェクトを特定のチームにのみ同期するには、そのオブジェクトのメタデータに次のアノテーションを設定します。

    annotations:
      configmanagement.gke.io/namespace-selector: NAMESPACE_SELECTOR_NAME
    

    たとえば、バックエンド チームの NetworkPolicy は次のようになります。

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: be-deny-all
      annotations:
        configmanagement.gke.io/namespace-selector: backend-scope # Actuate this resource in the namespaces with labels matched by the namespace selector
    spec:
      ingress:
      - from:
        - podSelector: {}
      podSelector:
        matchLabels: null

Config Sync のフリートレベルのデフォルトを作成する

このセクションでは、Config Sync のフリートレベルのデフォルトを作成します。これにより、フリートで作成されたすべてのクラスタに同じ Config Sync 構成が適用されます。

Config Sync のフリートレベルのデフォルト構成を作成するには、次の操作を行います。

  1. フリートのデフォルト構成の Terraform ファイル用にディレクトリを作成します。このディレクトリに、main.tf ファイルと variables.tf ファイルを追加します。

  2. variables.tf ファイルに次の変数を追加します。

    variable "project" {
      type = string
      description = "GCP project ID"
    }

  3. main.tf ファイルに次のリソースを追加し、Config Sync の構成を行います。

    git

    terraform {
      required_providers {
        google = {
          source = "hashicorp/google"
          version = ">=5.16.0"
         }
       }
     }
    
    provider "google" {
      project = var.project
    }
    
    resource "google_gke_hub_feature" "feature" {
      name = "configmanagement"
      location = "global"
      provider = google
      fleet_default_member_config {
        configmanagement {
        version = "VERSION"
     config_sync {
       source_format = "unstructured"
       git {
         sync_repo = "REPO"
         sync_branch = "BRANCH"
         policy_dir = "DIRECTORY"
         secret_type = "SECRET"
            }
          }
        }
      }
    }
    

    次のように置き換えます。

    • VERSION: (省略可)Config Sync のバージョン番号。バージョン 1.17.0 以降に設定する必要があります。空白のままにすると、デフォルトで最新バージョンが使用されます。
    • REPO: 構成ファイルを含むリポジトリの URL。
    • BRANCH: リポジトリ ブランチ。例: main
    • DIRECTORY: 同期するリポジトリの最上位レベルを表す Git リポジトリ内のパス。
    • SECRET: Secret 認証タイプ。

    Config Sync の git ブロックでサポートされている設定の一覧については、GKE Hub 機能の Terraform リファレンス ドキュメントをご覧ください。

    OCI

    terraform {
      required_providers {
        google = {
          source = "hashicorp/google"
          version = ">=5.16.0"
         }
       }
     }
    
    provider "google" {
      project = var.project
    }
    
    resource "google_gke_hub_feature" "feature" {
      name = "configmanagement"
      location = "global"
      provider = google
      fleet_default_member_config {
        configmanagement {
        version = "VERSION"
        config_sync {
        source_format = "unstructured"
        oci {
         sync_repo = "REPO"
         policy_dir = "DIRECTORY"
         secret_type = "SECRET"
         }
        }
        }
      }
    }
    

    次のように置き換えます。

    • VERSION: Config Sync のバージョン番号。バージョン 1.17.0 以降に設定する必要があります。空白のままにすると、デフォルトで最新バージョンが使用されます。
    • REPO: 構成ファイルを含む OCI イメージ リポジトリの URL。
    • DIRECTORY: 同期するリソースを含むディレクトリの絶対パス。ルート ディレクトリを使用する場合は空白のままにします。
    • SECRET: Secret 認証タイプ。

    Config Sync の oci ブロックでサポートされている設定の一覧については、GKE Hub 機能の Terraform リファレンス ドキュメントをご覧ください。

    たとえば、次の main.tf ファイルは、Git リポジトリから同期するように Config Sync を構成し、config ディレクトリ内のすべてのオブジェクトを同期します。

    terraform {
      required_providers {
        google = {
          source = "hashicorp/google"
          version = ">= 5.16.0"
        }
      }
    }
    
    provider "google" {
      project = var.project
    }
    
    resource "google_gke_hub_feature" "feature" {
      name = "configmanagement"
      location = "global"
      provider = google
      fleet_default_member_config {
        configmanagement {
          # version = "1.17.0" # Use the default latest version; if specifying a version, it must be at or after 1.17.0
          config_sync {
            source_format = "unstructured"
            git {
              sync_repo = "https://github.com/GoogleCloudPlatform/anthos-config-management-samples"
              sync_branch = "main"
              policy_dir = "fleet-tenancy/config"
              secret_type = "none"
            }
          }
        }
      }
    }
  4. 作成したディレクトリで Terraform を初期化します。

    terraform init
    
  5. Terraform で示した変更が、想定されているプランと一致していることを確認します。

    terraform plan
    
  6. フリート メンバーのデフォルト構成を作成します。

    terraform apply
    

フリートにクラスタを作成する

このセクションでは、共有クラスタ構成を作成し、フリートにクラスタを作成します。

新しいクラスタを作成してフリートに登録するには、次の操作を行います。

  1. クラスタ構成の Terraform ファイル用のディレクトリを作成します。このディレクトリに、main.tf ファイルと variables.tf ファイルを追加します。

  2. variables.tf ファイルに次の変数を追加します。

    variable "project" {
      type = string
      description = "GCP project ID"
    }

  3. すべてのクラスタで使用されるデフォルト値(プロジェクト ID やフリート ID など)を含む cluster.tf ファイルを作成します。

    variable "location" {
      type = string
    }
    
    variable "cluster_name" {
      type = string
    }
    
    data "google_project" "project" {
      provider = google
    }
    
    resource "google_container_cluster" "cluster" {
     provider = google
     name               = var.cluster_name
     location           = var.location
     initial_node_count = 3
     project = data.google_project.project.project_id
     fleet {
       project = data.google_project.project.project_id
     }
     workload_identity_config {
       workload_pool = "${data.google_project.project.project_id}.svc.id.goog"
     }
     deletion_protection = false
    }
    
  4. main.tf ファイルに次のリソースを追加します。

    terraform {
      required_providers {
        google = {
        source = "hashicorp/google"
        version = ">=5.16.0"
        }
      }
    }
    
    provider "google" {
      project = var.project
    }
    
    module "MODULE_NAME" {
      source = "CLUSTER_CONFIGURATION_FILEPATH"
      cluster_name = "CLUSTER_NAME"
      location="CLUSTER_LOCATION"
    }
    

    次のように置き換えます。

    • MODULE_NAME: クラスタ モジュールに付ける名前。MODULE_NAMECLUSTER_NAME は同じ値にすることができます。例: us-east-cluster
    • CLUSTER_CONFIGURATION_FILEPATH: 作成した cluster.tf ファイルの相対パス。
    • CLUSTER_NAME: クラスタの名前。MODULE_NAMECLUSTER_NAME は同じ値にすることができます。例: us-east-cluster
    • CLUSTER_LOCATION: クラスタのロケーション。例: us-east1

    クラスタは必要な数だけ作成できます。たとえば、次の main.tf ファイルは、異なるリージョンに 3 つのクラスタを作成します。

    terraform {
      required_providers {
        google = {
          source = "hashicorp/google"
          version = ">= 5.16.0"
        }
      }
    }
    
    provider "google" {
      project = var.project
    }
    
    module "us-west-cluster" {
      source = "./cluster"
      cluster_name = "us-west-cluster"
      location="us-west1-a"
    }
    
    module "us-east-cluster" {
      source = "./cluster"
      cluster_name = "us-east-cluster"
      location="us-east1-b"
    }
    
    module "us-central-cluster" {
      source = "./cluster"
      cluster_name = "us-central-cluster"
      location="us-central1-c"
    }
  5. 作成したディレクトリで Terraform を初期化します。

    terraform init
    
  6. Terraform で示した変更が、想定されているプランと一致していることを確認します。

    terraform plan
    
  7. クラスタを作成します。

    terraform apply
    

チームスコープとフリートの Namespace を構成する

このセクションでは、チームスコープを作成し、これらのスコープにクラスタを関連付けます。次に、必要なフリートの Namespace を作成します。たとえば、各チームに 1 つずつ、各スコープに 1 つずつ作成します。Config Sync は、Namespace 全体にリソースを作成します。

チームスコープと Namespace を構成する手順は次のとおりです。

  1. チームスコープと Namespace の構成用 Terraform ファイルのディレクトリを作成します。このディレクトリに、main.tf ファイルと variables.tf ファイルを追加します。

  2. variables.tf ファイルに次の変数を追加します。

    variable "project" {
      type = string
      description = "GCP project ID"
    }
    

  3. main.tf ファイルに次のリソースを追加します。

    1. プロバイダ情報を追加します。

      terraform {
        required_providers {
          google = {
            source = "hashicorp/google"
            version = ">=5.16.0"
           }
         }
       }
      
      provider "google" {
        project = var.project
      }
      
    2. チームスコープ リソースを追加します。

      resource "google_gke_hub_scope" "scope" {
        provider = google
        for_each = toset([
          "SCOPE_NAME",
          "SCOPE_NAME_2",
        ])
        scope_id = each.value
      }
      

      次のように置き換えます。

      • SCOPE_NAME: チームスコープの名前(例: backend)。
      • SCOPE_NAME_2: 追加のチームスコープ(作成した場合)。

      チームスコープは必要な数だけ追加できます。クラスタにフリートの Namespace が作成されると、その Namespace には自動的に fleet.gke.io/fleet-scope: SCOPE_NAME というラベルが付けられます。これにより、Config Sync は Kubernetes リソースの同期時に存在する Namespace を NamespaceSelector ラベルに基づいて選択できるようになります。

      たとえば、フロントエンド チームとバックエンド チームの両方のスコープを含むチームスコープの Terraform リソースは、次のようになります。

      resource "google_gke_hub_scope" "scope" {
        provider = google
        for_each = toset([
          "backend",
          "frontend",
        ])
        scope_id = each.value
      }
    3. チームスコープに適用するクラスタごとにフリート メンバーシップ バインディングを追加します。

      resource "google_gke_hub_membership_binding" "membership-binding" {
        provider = google
        for_each = {
          MEMBERSHIP_BINDING_NAME = {
            membership_binding_id = "MEMBERSHIP_BINDING_ID"
            scope = google_gke_hub_scope.scope["SCOPE_NAME"].name
            membership_id = "CLUSTER_NAME"
            location = "CLUSTER_LOCATION"
          }
          MEMBERSHIP_BINDING_NAME_2 = {
            membership_binding_id = "MEMBERSHIP_BINDING_ID_2"
            scope = google_gke_hub_scope.scope["SCOPE_NAME_2"].name
            membership_id = "CLUSTER_NAME_2"
            location = "CLUSTER_LOCATION_2"
          }
        }
        membership_binding_id = each.value.membership_binding_id
        scope = each.value.scope
        membership_id = each.value.membership_id
        location = each.value.location
      
        depends_on = [google_gke_hub_scope.scope]
      }
      

      次のように置き換えます。

      • MEMBERSHIP_BINDING_NAME: メンバーシップ バインディング名。例: us-east-backend
      • MEMBERSIP_BINDING_ID: メンバーシップ バインディング ID。これは MEMBERSHIP_BINDING_NAME と同じにすることもできます。
      • SCOPE_NAME: NamespaceSelector の作成時にチームスコープに指定したラベルセレクタ。例: backend
      • CLUSTER_NAME: クラスタの作成時に作成したクラスタの名前。例: us-east-cluster
      • CLUSTER_LOCATION: クラスタのロケーション。例: us-east1

      クラスタごとにフリート メンバーシップ バインディングを定義する必要があります。クラスタのチームスコープを定義しない場合、そのクラスタは Namespace に作成されません。たとえば、us-east1us-west1us-central1 の 3 つのリージョンにクラスタがあり、us-central1 クラスタがフロントエンド チーム専用の場合、メンバーシップ バインディング リソースは次のようになります。

      resource "google_gke_hub_membership_binding" "membership-binding" {
        provider = google
        for_each = {
          us-east-backend = {
            membership_binding_id = "us-east-backend"
            scope = google_gke_hub_scope.scope["backend"].name
            membership_id = "us-east-cluster"
            location = "us-east1"
          }
          us-west-backend = {
            membership_binding_id = "us-west-backend"
            scope = google_gke_hub_scope.scope["backend"].name
            membership_id = "us-west-cluster"
            location = "us-west1"
          }
          us-east-frontend = {
            membership_binding_id = "us-east-frontend"
            scope = google_gke_hub_scope.scope["frontend"].name
            membership_id = "us-east-cluster"
            location = "us-east1"
          }
          us-west-frontend = {
            membership_binding_id = "us-west-frontend"
            scope = google_gke_hub_scope.scope["frontend"].name
            membership_id = "us-west-cluster"
            location = "us-west1"
          }
          us-central-frontend = {
            membership_binding_id = "us-central-frontend"
            scope = google_gke_hub_scope.scope["frontend"].name
            membership_id = "us-central-cluster"
            location = "us-central1"
          }
        }
      
        membership_binding_id = each.value.membership_binding_id
        scope = each.value.scope
        membership_id = each.value.membership_id
        location = each.value.location
      
        depends_on = [google_gke_hub_scope.scope]
      }
    4. チームに定義する Namespace を追加します。

      resource "google_gke_hub_namespace" "fleet_namespace" {
        provider = google
      
        for_each = {
          FLEET_NAMESPACE = {
            scope_id = "SCOPE_NAME"
            scope_namespace_id = "FLEET_NAMESPACE_ID"
            scope = google_gke_hub_scope.scope["SCOPE_NAME"].name
          }
          FLEET_NAMESPACE_2 = {
            scope_id = "SCOPE_NAME"
            scope_namespace_id = "FLEET_NAMESPACE_ID_2"
            scope = google_gke_hub_scope.scope["SCOPE_NAME"].name
          }
      
      }
      
        scope_namespace_id = each.value.scope_namespace_id
        scope_id = each.value.scope_id
        scope = each.value.scope
      
        depends_on = [google_gke_hub_scope.scope]
      }
      

      次のように置き換えます。

      • FLEET_NAMESPACE: Namespace に付ける名前。例: backend-a
      • SCOPE_NAME: NamespaceSelector の作成時にチームスコープに指定したラベルセレクタ。例: backend
      • FLEET_NAMESPACE_ID: Namespace の ID。これは FLEET_NAMESPACE と同じでかまいません。

      たとえば、フロントエンド チームとバックエンド チームの両方にそれぞれ 2 つの Namespace を用意する場合、フリートの Namespace リソースは次のようになります。

      resource "google_gke_hub_namespace" "fleet_namespace" {
        provider = google
      
        for_each = {
          bookstore = {
            scope_id = "backend"
            scope_namespace_id = "bookstore"
            scope = google_gke_hub_scope.scope["backend"].name
          }
          shoestore = {
            scope_id = "backend"
            scope_namespace_id = "shoestore"
            scope = google_gke_hub_scope.scope["backend"].name
          }
          frontend_a = {
            scope_id = "frontend"
            scope_namespace_id = "frontend-a"
            scope = google_gke_hub_scope.scope["frontend"].name
          }
          frontend_b = {
            scope_id = "frontend"
            scope_namespace_id = "frontend-b"
            scope = google_gke_hub_scope.scope["frontend"].name
          }
        }
      
        scope_namespace_id = each.value.scope_namespace_id
        scope_id = each.value.scope_id
        scope = each.value.scope
      
        depends_on = [google_gke_hub_scope.scope]
      }
  4. 作成したディレクトリで Terraform を初期化します。

    terraform init
    
  5. Terraform で示した変更が、想定されているプランと一致していることを確認します。

    terraform plan
    
  6. フリート スコープと Namespace を作成します。

    terraform apply
    

フリート スコープと Namespace を作成すると、Config Sync は新しい Namespace とそのスコープを検出し、フリートの Namespace 内のリソースを選択して、構成ファイルと調整します。

リソースが正しいクラスタに適用されていることを確認するには、nomos status を使用するか、Google Cloud コンソールで Config Sync の [PACKAGES] タブに移動し、[表示] ラジオボタンを [Cluster] に変更します。

[PACKAGES] に移動

Config Sync は、信頼できる情報源に保存されている構成に従って、チームスコープに基づいて Namespace 間でリソースを同期します。新しいリソースを追加するたびに、正しい NamespaceSelector アノテーションが含まれていれば、Config Sync はチームの Namespace 全体でそのリソースを自動的に調整します。

Config Sync の設定を既存のクラスタに適用する場合は、Config Sync のインストール ガイドのフリートレベルのデフォルトの構成の手順をご覧ください。

次のステップ