フィーチャー トグルをスタンドアロンで使用する

App Lifecycle Manager でデプロイまたは管理されていないアプリケーションでも、App Lifecycle Manager のフィーチャー トグルをスタンドアロン サービスとして使用して、アプリケーションの機能の可用性を管理する方法について説明します。

はじめに

このクイックスタートでは、インフラストラクチャのプロビジョニング(Terraform ブループリントを使用した VM や Cloud Run サービスのデプロイなど)に App Lifecycle Manager を使用しなくても、App Lifecycle Manager の堅牢なフィーチャー トグルと制御されたロールアウト機能を使用する方法について説明します。この方法は、アプリケーション インフラストラクチャを個別に管理しているが、安全なフィーチャー トグル管理に App Lifecycle Manager を使用 したい場合に最適です。

このスタンドアロン アプローチでは、次のことを行います。

  1. 軽量の App Lifecycle Manager リソースを使用してシステムをモデル化する: App Lifecycle Manager Units を作成して、既存のインフラストラクチャのコンポーネント(特定のマイクロサービス デプロイ、テナント環境、単一のバイナリ インスタンスなど)を表します。これらのユニットは、フラグ構成のターゲットとしてのみ機能し、App Lifecycle Manager ブループリントを使用したインフラストラクチャのデプロイは行いません
  2. フラグを定義して配布する: App Lifecycle Manager API または Google Cloud コンソールを使用して、フィーチャー トグルを作成します。App Lifecycle Manager Rollouts を使用してライフサイクルを管理し、モデル化された Units への構成変更を安全かつ段階的に伝播させます。これにより、フラグのみを管理する場合でも、オペレーションの一貫性と安全性が確保されます。
  3. アプリケーションと統合する: アプリケーション コード(ローカル、オンプレミス 、セルフマネージド クラウドなど、任意の場所で実行)で flagd プロバイダとともに OpenFeature SDK を使用します。App Lifecycle Manager フラグサービス(saasconfig.googleapis.com)に接続し、認証を行い、対応する Unit リソース名を使用して 自身を識別して、正しいフラグ値を取得するように構成します。

このアプローチでは、既存のデプロイ パイプラインやインフラストラクチャ管理ツールを変更することなく、マネージドで安全なフラグ配布のメリットを享受できます。

App Lifecycle Manager のフィーチャー トグルは限定公開プレビュー 版です。アクセスには許可リストへの登録が必要です。組織またはプロジェクトのアクセスをリクエストするには、こちらのフォームにご記入ください

このクイックスタートでは、ローカルで実行される基本的な Python アプリケーションを使用して、フラグへのアクセス方法を示し、既存のアプリケーションがどのように統合されるかをシミュレートします。

目標

  • 新しい Google Cloud プロジェクトを設定するか、既存のプロジェクトを使用します。
  • 必要な API(App Lifecycle Manager と SaaS Config)を有効にします。
  • リソースの作成とフラグの読み取りに必要な Identity and Access Management 権限を付与します。
  • インフラストラクチャをデプロイせずにアプリケーション コンポーネントをモデル化するために、最小限の App Lifecycle Manager リソース(SaaS オファリング、ユニットの種類、ユニット)を作成します。
  • ユニットの種類に関連付けられたフィーチャー トグルリソースを定義します。
  • 配布戦略を定義するフラグ ロールアウト メカニズム(ロールアウトの種類)を作成します。
  • App Lifecycle Manager のロールアウトを使用して、初期フラグ構成を配布 します。
  • App Lifecycle Manager フラグサービスに接続し、モデル化されたユニットのフラグを評価するサンプル Python アプリケーションをローカルで実行します。
  • フラグ値を更新し、新しいフラグリリースの作成し、変更を配布 します。
  • アプリケーションが更新されたフラグ値を取得していることを確認します。

始める前に

  1. ログイン Google アカウントにログインします。

    Google アカウントをまだお持ちでない場合は、 新しいアカウントを登録します

  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the App Lifecycle Manager and SaaS Config APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  5. Google Cloud CLI をインストールします。

  6. 外部 ID プロバイダ(IdP)を使用している場合は、まず連携 ID を使用して gcloud CLI にログインする必要があります。

  7. gcloud CLI を初期化するには、次のコマンドを実行します:

    gcloud init
  8. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  9. Verify that billing is enabled for your Google Cloud project.

  10. Enable the App Lifecycle Manager and SaaS Config APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  11. Google Cloud CLI をインストールします。

  12. 外部 ID プロバイダ(IdP)を使用している場合は、まず連携 ID を使用して gcloud CLI にログインする必要があります。

  13. gcloud CLI を初期化するには、次のコマンドを実行します:

    gcloud init
  14. Python をインストールする: サンプル アプリケーションを実行するマシンに Python 3.7 以降がインストールされていることを確認します。依存関係をインストールするには、pip も必要です。
    python --version
    pip --version
  15. アプリケーションのデフォルト認証情報(ADC)の gcloud を認証する: ローカル Python スクリプトは ADC を使用して Google Cloud サービスを認証します。ユーザー アカウントを使用してログインします。
    gcloud auth application-default login
  16. アプリケーション ID の権限を付与する: アプリケーションには、SaaS Config サービスからフラグ構成を読み取る権限が必要です。アプリケーションが使用する ID に `roles/saasconfig.viewer` ロールを付与します。このクイックスタートでは、ユーザー アカウントで ADC をローカルで使用するため、メールアドレスにロールを付与します。
        gcloud projects add-iam-policy-binding PROJECT_ID \
            --member="user:YOUR_EMAIL_ADDRESS" \
            --role="roles/saasconfig.viewer"
    PROJECT_ID は実際の Google Cloud プロジェクト ID に、YOUR_EMAIL_ADDRESS は CLI ログインに関連付けられたメールアドレスに置き換えます。

最小限の App Lifecycle Manager リソースを作成する

App Lifecycle Manager でインフラストラクチャをデプロイしていなくても、フラグを安全に整理、ターゲット設定、配布 するには、いくつかのリソースが必要です。これらのリソースは、App Lifecycle Manager 内の既存のアプリケーション コンポーネントを表します。

  1. 変数を定義する: リソース名とロケーションの環境変数を設定します。

    export PROJECT_ID="your-project-id"
    export SAAS_OFFERING_ID="standalone-flags-saas"
    export UNIT_KIND_ID="standalone-app-kind"
    export UNIT_ID="my-app-instance-01"
    export LOCATION_1="us-central1" # Example region where your app instance conceptually resides
    # Add more locations if your app components span multiple regions
    # export LOCATION_2="europe-west1"
    
  2. SaaS オファリングを作成する: これは、フラグなど、サービスの構成の最上位コンテナとして機能します。

    gcloud beta app-lifecycle-manager saas create ${SAAS_OFFERING_ID} \
        --project=${PROJECT_ID} \
        --location=global \
        --locations=name=${LOCATION_1} # Add --locations=name=${LOCATION_2} if using more regions
    
     gcloud beta app-lifecycle-manager saas create ${SAAS_OFFERING_ID} \
        --project=${PROJECT_ID} \
        --location=${LOCATION_1} \
        --locations=name=${LOCATION_1} 
    
  3. ユニットの種類を作成する: これは、モデル化するコンポーネントのタイプを定義します。インフラストラクチャを管理していないため、ブループリントは提供しません。

    gcloud beta app-lifecycle-manager unit-kinds create ${UNIT_KIND_ID} \
      --project=${PROJECT_ID} \
      --location=global \
      --saas=${SAAS_OFFERING_ID}
    
    gcloud beta app-lifecycle-manager unit-kinds create ${UNIT_KIND_ID} \
      --project=${PROJECT_ID} \
      --location=${LOCATION_1} \
      --saas=${SAAS_OFFERING_ID}
    
  4. ユニットを作成する: これは、アプリケーションの特定のインスタンスを表します。

    gcloud beta app-lifecycle-manager units create ${UNIT_ID} \
      --project=${PROJECT_ID} \
      --unit-kind=${UNIT_KIND_ID} \
      --location=${LOCATION_1} 
    

フィーチャー トグルを定義してロールアウトする

次に、実際のフィーチャー トグルを作成し、App Lifecycle Manager のロールアウト メカニズムを使用して、作成したユニットで構成を使用できるようにします。

  1. フラグ変数を定義する:

    export FLAG_ID="standalone-flag-01"
    export FLAG_KEY="enable-beta-feature" 
    
  2. フラグ リソース、リビジョン、リリースを作成する:

    gcloud beta app-lifecycle-manager flags create ${FLAG_ID} \
      --project=${PROJECT_ID} \
      --key=${FLAG_KEY} \
      --flag-value-type=BOOL \
      --location=global \
      --unit-kind=${UNIT_KIND_ID} \
    
    export FLAG_REVISION_ID_1="${FLAG_ID}-rev1"
    gcloud beta app-lifecycle-manager flags revisions create ${FLAG_REVISION_ID_1} \
      --project=${PROJECT_ID} \
      --flag=${FLAG_ID} \
      --location=global
    
    export FLAG_RELEASE_ID_1="${FLAG_ID}-rel1"
    gcloud beta app-lifecycle-manager flags releases create ${FLAG_RELEASE_ID_1} \
      --project=${PROJECT_ID} \
      --flag-revisions=${FLAG_REVISION_ID_1} \
      --unit-kind=${UNIT_KIND_ID} \
      --location=global
    
  3. ロールアウトの種類を作成する: フラグの変更を配布する戦略を定義します。

    export ROLLOUT_KIND_ID="standalone-flags-rollout-kind"
    
    gcloud beta app-lifecycle-manager rollout-kinds create ${ROLLOUT_KIND_ID} \
      --project=${PROJECT_ID} \
      --unit-kind=${UNIT_KIND_ID} \
      --rollout-orchestration-strategy=Google.Cloud.Simple.AllAtOnce \
      --location=global
    
  4. ロールアウトを作成する: 配布プロセスを開始します。

    export ROLLOUT_ID_1="${FLAG_ID}-rollout1"
    
    gcloud beta app-lifecycle-manager rollouts create ${ROLLOUT_ID_1} \
      --project=${PROJECT_ID} \
      --flag-release=${FLAG_RELEASE_ID_1} \
      --rollout-kind=${ROLLOUT_KIND_ID} \
      --location=global
    
  5. ロールアウトをモニタリングする: デプロイが成功してから続行します。

    gcloud beta app-lifecycle-manager rollouts describe ${ROLLOUT_ID_1} \
      --project=${PROJECT_ID} \
      --location=global
    

スタンドアロン インフラストラクチャを構成する

スタンドアロン設定では、アプリケーション ホスティング(Cloud Run や GKE など)を自分で管理し、App Lifecycle Manager は構成の同期のみに使用します。アプリケーション コードはデプロイ全体で標準のままです。SaaS Config サービスに接続するには、ランタイムに FLAGD_SOURCE_PROVIDER_ID 環境変数が存在する必要があります。

構築されたパスを環境変数として渡すことで、App Lifecycle Manager ユニット定義を標準の Terraform デプロイ定義にマッピングできます。

  1. インフラストラクチャを定義する: デプロイ テンプレート(standalone.tf など)のパスをマッピングします。

    variable "project_id" { type = string }
    variable "region"     { type = string }
    variable "unit_id"    { type = string }
    
    resource "google_cloud_run_v2_service" "standalone_app" {
      name     = "my-standalone-service"
      location = var.region
    
      template {
        containers {
          image = "us-central1-docker.pkg.dev/my-project/my-repo/my-image:latest"
    
          env {
            name  = "FLAGD_SOURCE_PROVIDER_ID"
            value = "projects/${var.project_id}/locations/${var.region}/featureFlagsConfigs/${var.unit_id}"
          }
        }
      }
    }
    
  2. 変数値を定義する: 関連する変数ファイル(terraform.tfvars など)に構成ユニット パラメータを指定します。

    project_id = "PROJECT_ID"
    region     = "LOCATION_1"
    unit_id    = "UNIT_ID"
    

サンプル アプリケーションを統合して実行する

モデル化されたユニット構成を使用して App Lifecycle Manager フラグサービスに接続するサンプル Python アプリケーションをローカルで実行します。

  1. プロジェクト ディレクトリとファイルを作成する:

    mkdir saas_flags_standalone_app
    cd saas_flags_standalone_app
    

    requirements.txt を作成します。

    google-auth
    grpcio>=1.49.1,<2.0.0dev
    openfeature-sdk==0.8.0
    openfeature-provider-flagd==0.2.2
    requests
    typing_extensions
    Flask>=2.0
    

    依存関係をインストールします。

    pip install -r requirements.txt
    
  2. app.py を作成する:

    import google.auth.transport.grpc
    import google.auth.transport.requests
    import grpc
    import logging
    import time
    import os
    import sys
    from flask import Flask, jsonify
    
    from openfeature import api
    from openfeature.contrib.provider.flagd import FlagdProvider
    from openfeature.contrib.provider.flagd.config import ResolverType
    
    app = Flask(__name__)
    
    logging.basicConfig(stream=sys.stdout, level=logging.INFO,
                        format='%(asctime)s - %(levelname)s - %(message)s')
    log = logging.getLogger(__name__)
    
    FLAG_KEY = os.environ.get("FLAG_KEY", "enable-beta-feature")
    DEFAULT_FLAG_VALUE = False 
    
    # CRITICAL: Read the Unit resource name from environment variable.
    # This identifies the application instance to the flag service.
    provider_id = os.environ.get("FLAGD_SOURCE_PROVIDER_ID")
    if not provider_id:
        log.critical("FATAL: FLAGD_SOURCE_PROVIDER_ID not set.")
        sys.exit("FLAGD_SOURCE_PROVIDER_ID not set")
    
    log.info(f"Initializing OpenFeature provider for Unit: {provider_id}")
    
    def add_x_goog_request_params_header(config_name):
        return lambda context, callback: callback([("x-goog-request-params", f'name={config_name}')], None)
    
    try:
        credentials, detected_project_id = google.auth.default(
            scopes=["https://www.googleapis.com/auth/cloud-platform"] 
        )
        auth_req = google.auth.transport.requests.Request() 
    
        configservice_credentials = grpc.composite_channel_credentials(
            grpc.ssl_channel_credentials(), 
            grpc.metadata_call_credentials( 
                google.auth.transport.grpc.AuthMetadataPlugin(credentials, auth_req)
            ),
            grpc.metadata_call_credentials(
                add_x_goog_request_params_header(provider_id)
            )
        )
    
        provider = FlagdProvider(
            resolver_type=ResolverType.IN_PROCESS,    
            host="saasconfig.googleapis.com",         
            port=443,                                 
            sync_metadata_disabled=True,              
            provider_id=provider_id,                  
            channel_credentials=configservice_credentials 
        )
    
        api.set_provider(provider)
        client = api.get_client()
    
        time.sleep(5)
    
        initial_flag_value = client.get_boolean_value(FLAG_KEY, DEFAULT_FLAG_VALUE)
        log.info(f"***** STARTUP FLAG CHECK ***** Flag '{FLAG_KEY}' evaluated to: {initial_flag_value}")
    
    except Exception as e:
        log.critical(f"FATAL: Failed to initialize OpenFeature provider: {e}", exc_info=True)
        sys.exit(f"Provider initialization failed: {e}")
    
    @app.route('/')
    def home():
        log.info(f"Request received for endpoint '/', evaluating flag: {FLAG_KEY}")
        try:
            flag_value = client.get_boolean_value(FLAG_KEY, DEFAULT_FLAG_VALUE)
            log.info(f"Evaluated flag '{FLAG_KEY}': {flag_value}")
            return jsonify({
                "flag_key": FLAG_KEY,
                "value": flag_value,
                "provider_id": provider_id 
            })
        except Exception as e:
            log.error(f"Error evaluating flag '{FLAG_KEY}': {e}", exc_info=True)
            return jsonify({
                "error": f"Failed to evaluate flag {FLAG_KEY}",
                "details": str(e),
            }), 500
    
    if __name__ == '__main__':
        port = int(os.environ.get('PORT', 8080))
        log.info(f"Starting Flask web server on host 0.0.0.0 port {port}")
        app.run(host='0.0.0.0', port=port)
    
  3. アプリケーションを実行します。

    export FLAGD_SOURCE_PROVIDER_ID="projects/${PROJECT_ID}/locations/${LOCATION_1}/featureFlagsConfigs/${UNIT_ID}"
    python app.py
    
  4. 初期フラグ値を確認する: セカンダリ ターミナルでローカル エンドポイントに対してチェックを実行します。

    curl http://localhost:8080
    

フラグを更新して変更を配布する

フラグ定義のランタイム状態を変更し、接続されているターゲットに更新を配布します。

  1. フラグ リソースを更新する:

    gcloud beta app-lifecycle-manager flags create ${FLAG_ID} \
        --project=${PROJECT_ID} \
        --key=${FLAG_KEY} \
        --flag-value-type=BOOL \
        --location=global \
        --unit-kind=${UNIT_KIND_ID}
    
    export FLAG_REVISION_ID_2="${FLAG_ID}-rev2"
    gcloud beta app-lifecycle-manager flags revisions create ${FLAG_REVISION_ID_2} \
      --project=${PROJECT_ID} \
      --flag=${FLAG_ID} \
      --location=global
    
    export FLAG_RELEASE_ID_2="${FLAG_ID}-rel2"
    gcloud beta app-lifecycle-manager flags releases create ${FLAG_RELEASE_ID_2} \
      --project=${PROJECT_ID} \
      --flag-revisions=${FLAG_REVISION_ID_2} \
      --unit-kind=${UNIT_KIND_ID} \
      --location=global
    
  2. 更新用の新しいロールアウトを作成する:

    export ROLLOUT_ID_2="${FLAG_ID}-rollout2"
    
    gcloud beta app-lifecycle-manager rollouts create ${ROLLOUT_ID_2} \
      --project=${PROJECT_ID} \
      --flag-release=${FLAG_RELEASE_ID_2} \
      --rollout-kind=${ROLLOUT_KIND_ID} \
      --location=global
    
  3. 新しいロールアウトをモニタリングする:

    gcloud beta app-lifecycle-manager rollouts describe ${ROLLOUT_ID_2} \
      --project=${PROJECT_ID} \
      --location=global 
    
  4. 実行中のアプリケーションの変更を確認する:

    curl http://localhost:8080
    

クリーンアップ

このページで使用したリソースについて、 Google Cloud アカウントに課金されないようにするには、 次の手順を実施します。

  1. app.py が実行されているターミナルで Ctrl+C を押して、ローカル Python アプリケーションを停止します。
  2. フラグの状態を設定します。
  3. 新しいロールアウトを作成して、不要になったフラグを削除します。
  4. ロールアウトが完了して不要になったフラグが削除されたら、App Lifecycle Manager リソースを削除します。

    gcloud beta app-lifecycle-manager rollouts delete ${ROLLOUT_ID_1} --project=${PROJECT_ID} --location=global --quiet 
    gcloud beta app-lifecycle-manager rollouts delete ${ROLLOUT_ID_2} --project=${PROJECT_ID} --location=global --quiet 
    gcloud beta app-lifecycle-manager rollout-kinds delete ${ROLLOUT_KIND_ID} --project=${PROJECT_ID} --location=global --quiet 
    gcloud beta app-lifecycle-manager flags releases delete ${FLAG_RELEASE_ID_1} --project=${PROJECT_ID} --location=global --quiet 
    gcloud beta app-lifecycle-manager flags releases delete ${FLAG_RELEASE_ID_2} --project=${PROJECT_ID} --location=global --quiet 
    gcloud beta app-lifecycle-manager flags delete ${FLAG_ID} --project=${PROJECT_ID} --location=global --quiet 
    gcloud beta app-lifecycle-manager units delete ${UNIT_ID} --project=${PROJECT_ID} --location=${LOCATION_1} --quiet 
    gcloud beta app-lifecycle-manager unit-kinds delete ${UNIT_KIND_ID} --project=${PROJECT_ID} --location=global --quiet 
    gcloud beta app-lifecycle-manager unit-kinds delete ${UNIT_KIND_ID} --project=${PROJECT_ID} --location=${LOCATION_1} --quiet 
    gcloud beta app-lifecycle-manager saas delete ${SAAS_OFFERING_ID} --project=${PROJECT_ID} --location=global --quiet 
    gcloud beta app-lifecycle-manager saas delete ${SAAS_OFFERING_ID} --project=${PROJECT_ID} --location=${LOCATION_1} --quiet 
    
  5. ローカル ディレクトリを削除します。

    cd ..
    rm -rf saas_flags_standalone_app
    

次のステップ