フィーチャー トグルをスタンドアロンで使用する
App Lifecycle Manager のフィーチャー トグルをスタンドアロン サービスとして使用して、アプリケーションの機能の可用性を管理する方法について説明します。これらのアプリケーションが App Lifecycle Manager によってデプロイまたは管理されていない場合でも、この方法を使用できます。
はじめに
このクイックスタートでは、インフラストラクチャ プロビジョニング(Terraform ブループリントを使用した VM や Cloud Run サービスのデプロイなど)に App Lifecycle Manager を使用せずに、App Lifecycle Manager の堅牢な機能フラグ設定と制御されたロールアウト機能を使用する方法について説明します。このアプローチは、アプリケーション インフラストラクチャを個別に管理しているが、安全なフィーチャー トグル管理に App Lifecycle Manager を使用したい場合に最適です。
このスタンドアロン アプローチでは、次のことを行います。
- 軽量の App Lifecycle Manager リソースを使用してシステムをモデル化する: App Lifecycle Manager
Unitsを作成して、既存のインフラストラクチャのコンポーネント(特定のマイクロサービス デプロイ、テナント環境、単一のバイナリ インスタンスなど)を表します。これらのユニットは、フラグ構成のターゲットとしてのみ機能し、App Lifecycle Manager ブループリントを使用したインフラストラクチャのデプロイは行いません。 - フラグを定義して配布する: App Lifecycle Manager API または Google Cloud コンソールを使用して、フィーチャー トグルを作成します。App Lifecycle Manager
Rolloutsを使用してライフサイクルを管理し、モデル化されたUnitsに構成変更を安全かつ段階的に反映します。これにより、フラグのみを管理する場合でも、運用の整合性と安全性が確保されます。 - アプリケーションとの統合: アプリケーション コード(ローカル、オンプレミス、セルフマネージド クラウドなど、どこでも実行可能)で
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 リソース(App offering、Unit Kind、Unit)を作成して、インフラストラクチャをデプロイせずにアプリケーション コンポーネントをモデル化します。
- ユニットの種類に関連付けられたフィーチャー トグル リソースを定義します。
- 配布戦略を定義するフラグ ロールアウト メカニズム(ロールアウトの種類)を作成します。
- App Lifecycle Manager のロールアウトを使用して、初期フラグ構成を配布します。
- App Lifecycle Manager フラグサービスに接続し、モデル化されたユニットのフラグを評価するサンプル Python アプリケーションをローカルで実行します。
- フラグの値を更新し、新しいフラグ リリースを作成して、変更を配布します。
- アプリケーションが更新されたフラグ値を取得することを確認します。
始める前に
-
Google アカウントにログインします。
Google アカウントをまだお持ちでない場合は、新しいアカウントを登録します。
-
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 theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
Enable the App Lifecycle Manager and SaaS Config APIs, if any are not already enabled.
Roles required to enable APIs
To enable APIs, you need the
serviceusage.services.enablepermission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.-
Install the Google Cloud CLI.
-
If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.
-
To initialize the gcloud CLI, run the following command:
gcloud init -
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 theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
Enable the App Lifecycle Manager and SaaS Config APIs, if any are not already enabled.
Roles required to enable APIs
To enable APIs, you need the
serviceusage.services.enablepermission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.-
Install the Google Cloud CLI.
-
If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.
-
To initialize the gcloud CLI, run the following command:
gcloud init -
Python をインストールする: サンプル アプリケーションを実行するマシンに Python 3.7 以降がインストールされていることを確認します。また、依存関係をインストールするために pip も必要です。
python --version
pip --version
-
アプリケーションのデフォルト認証情報(ADC)用に gcloud を認証する: ローカルの Python スクリプトは、ADC を使用して Google Cloud サービスに対する認証を行います。ユーザー アカウントを使用してログインします。
gcloud auth application-default login
-
アプリケーション ID 権限を付与する: アプリケーションには、SaaS Config サービスからフラグ構成を読み取る権限が必要です。アプリケーションが使用する ID に `roles/saasconfig.viewer` ロールを付与します。このクイックスタートでは、ユーザー アカウントで ADC をローカルで使用するため、メールアドレスにロールを付与します。
PROJECT_ID は実際の Google Cloud プロジェクト ID に、YOUR_EMAIL_ADDRESS は CLI ログインに関連付けられているメールアドレスに置き換えます。gcloud projects add-iam-policy-binding PROJECT_ID \ --member="user:YOUR_EMAIL_ADDRESS" \ --role="roles/saasconfig.viewer"
最小限の App Lifecycle Manager リソースを作成する
App Lifecycle Manager でインフラストラクチャをデプロイしていなくても、フラグを安全に整理、ターゲット設定、配布するには、いくつかのリソースが必要です。これらのリソースは、App Lifecycle Manager 内の既存のアプリケーション コンポーネントを表します。
変数を定義する: リソース名とロケーションの環境変数を設定します。
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"アプリのオファリングを作成する: これは、フラグを含むサービスの構成の最上位コンテナとして機能します。
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}ユニットの種類を作成する: モデリングするコンポーネントの種類を定義します。重要なのは、Google がインフラストラクチャを管理していないため、ブループリントを提供していないことです。
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}ユニットを作成する: これは、アプリケーションの特定のインスタンスを表します。
gcloud beta app-lifecycle-manager units create ${UNIT_ID} \ --project=${PROJECT_ID} \ --unit-kind=${UNIT_KIND_ID} \ --location=${LOCATION_1}
フィーチャー トグルを定義してロールアウトする
次に、実際のフィーチャー トグルを作成し、App Lifecycle Manager のロールアウト メカニズムを使用して、作成したユニットで構成を利用できるようにします。
フラグ変数を定義する:
export FLAG_ID="standalone-flag-01" export FLAG_KEY="enable-beta-feature"フラグリソース、リビジョン、リリースを作成します。
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ロールアウトの種類を作成する: フラグの変更を配布する戦略を定義します。
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ロールアウトを作成する: 配布プロセスを開始します。
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ロールアウトをモニタリングする: 続行する前に、デプロイが成功していることを確認します。
gcloud beta app-lifecycle-manager rollouts describe ${ROLLOUT_ID_1} \ --project=${PROJECT_ID} \ --location=global
スタンドアロン インフラストラクチャを構成する
スタンドアロン設定では、独自のアプリケーション ホスティング(Cloud Run や GKE など)を管理し、App Lifecycle Manager を構成の同期のみに使用します。アプリケーション コードはデプロイ全体で標準のままです。実行時に FLAGD_SOURCE_PROVIDER_ID 環境変数が存在し、SaaS Config Service に接続することのみが必要です。
構築されたパスを環境変数として渡すことで、App Lifecycle Manager のユニット定義を標準の Terraform デプロイ定義にマッピングできます。
インフラストラクチャを定義する: デプロイ テンプレートのパスをマッピングします(例:
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}" } } } }変数の値を定義する: 関連する変数ファイル(
terraform.tfvarsなど)で構成ユニットのパラメータを指定します。project_id = "PROJECT_ID" region = "LOCATION_1" unit_id = "UNIT_ID"
サンプル アプリケーションを統合して実行する
モデル化されたユニット構成を使用して App Lifecycle Manager フラグ サービスに接続するサンプル Python アプリケーションをローカルで実行します。
プロジェクトのディレクトリとファイルを作成します。
mkdir saas_flags_standalone_app cd saas_flags_standalone_apprequirements.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.txtapp.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)アプリケーションを実行します。
export FLAGD_SOURCE_PROVIDER_ID="projects/${PROJECT_ID}/locations/${LOCATION_1}/featureFlagsConfigs/${UNIT_ID}" python app.py初期フラグ値を確認する: 2 つ目のターミナルでローカル エンドポイントに対してチェックを実行します。
curl http://localhost:8080
フラグを更新して変更を配布する
フラグ定義のランタイム状態を変更し、接続されたターゲットに更新を配布します。
フラグリソースを更新します。
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アップデートの新しいロールアウトを作成します。
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新しいロールアウトをモニタリングする:
gcloud beta app-lifecycle-manager rollouts describe ${ROLLOUT_ID_2} \ --project=${PROJECT_ID} \ --location=global実行中のアプリケーションで変更を確認します。
curl http://localhost:8080
クリーンアップ
このページで使用したリソースについて、 Google Cloud アカウントに課金されないようにするには、次の手順を実施します。
app.pyが実行されているターミナルでCtrl+Cを押して、ローカル Python アプリケーションを停止します。- フラグの状態を設定します。
- 新しいロールアウトを作成して、廃止されたフラグを削除します。
ロールアウトが完了し、廃止されたフラグが削除されたら、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ローカル ディレクトリを削除します。
cd .. rm -rf saas_flags_standalone_app
次のステップ
- コンセプトの詳細については、App Lifecycle Manager のフィーチャー トグルの概要をご覧ください。
- フィーチャー トグルのデプロイのクイックスタートを試して、フラグが App Lifecycle Manager で管理されるデプロイとどのように緊密に統合されるかを確認します。