שימוש בהתראות על תכונות עצמאיות
במאמר הזה מוסבר איך להשתמש בדגלי תכונות של App Lifecycle Manager כשירות עצמאי לניהול הזמינות של תכונות באפליקציות, גם אם האפליקציות האלה לא נפרסות או מנוהלות על ידי App Lifecycle Manager.
מבוא
במדריך הזה נסביר איך להשתמש ביכולות החזקות של App Lifecycle Manager לניהול תכונות והשקה מבוקרת, בלי שתצטרכו להשתמש ב-App Lifecycle Manager להקצאת משאבים (למשל, פריסת מכונות וירטואליות או שירותי Cloud Run באמצעות תוכניות Terraform). הגישה הזו מתאימה אם אתם מנהלים את תשתית האפליקציה באופן עצמאי, אבל רוצים להשתמש ב-App Lifecycle Manager כדי לנהל את ה-feature flags בצורה בטוחה.
בגישה העצמאית הזו:
- יצירת מודל של המערכת באמצעות משאבי App Lifecycle Manager קלי משקל: יוצרים App Lifecycle Manager
Unitsכדי לייצג רכיבים של התשתית הקיימת (למשל, פריסה ספציפית של מיקרו-שירות, סביבת דייר, מופע בינארי יחיד). היחידות האלה משמשות רק כיעדים להגדרות של דגלים, ולא כוללות פריסה של תשתית באמצעות תוכניות בסיסיות של App Lifecycle Manager. - הגדרה והפצה של דגלים: משתמשים ב-App Lifecycle Manager API או במסוף Google Cloud כדי ליצור דגלי תכונות. כדי לוודא שהשינויים בהגדרות מופצים בצורה בטוחה והדרגתית ל-
Unitsהממודל, אפשר לנהל את מחזור החיים שלו באמצעות App Lifecycle ManagerRollouts. כך אפשר לשמור על עקביות ובטיחות תפעולית, גם כשמנהלים רק דגלים. - שילוב עם האפליקציה: משתמשים ב-OpenFeature SDK עם הספק
flagdבקוד האפליקציה (שפועל בכל מקום – באופן מקומי, on-premises, בענן בניהול עצמי). מגדירים את האפליקציה כך שתתחבר לשירות הדגלים של App Lifecycle Manager (saasconfig.googleapis.com), תבצע אימות ותזהה את עצמה באמצעות שם המשאב התואם שלUnitכדי לאחזר את ערכי הדגלים הנכונים.
הגישה הזו מאפשרת לכם ליהנות מהפצה מנוהלת ובטוחה של דגלים בלי לשנות את צינורות עיבוד הנתונים לפריסה או את הכלים לניהול התשתית.
ה-feature flags של App Lifecycle Manager נמצאים בגרסת טרום-השקה פרטית. כדי לקבל גישה, צריך להוסיף את המשתמש לרשימת ההיתרים. כדי לבקש גישה לארגון או לפרויקט, מלאו את הטופס הזה.
במדריך למתחילים הזה נשתמש באפליקציית Python בסיסית שפועלת באופן מקומי כדי להדגים את הגישה לדגלים, ולדמות את אופן השילוב של האפליקציה הקיימת שלכם.
מטרות
- מגדירים פרויקט חדש Google Cloud או משתמשים בפרויקט קיים.
- מפעילים את ממשקי ה-API הנדרשים (App Lifecycle Manager ו-SaaS Config).
- לתת את ההרשאות הנדרשות לניהול זהויות והרשאות גישה (IAM) כדי ליצור משאבים ולקרוא דגלים.
- יוצרים משאבים מינימליים של App Lifecycle Manager (הצעת אפליקציה, סוג יחידה, יחידה) כדי ליצור מודל של רכיב באפליקציה בלי לפרוס תשתית.
- מגדירים משאב של feature flag שמשויך לסוג היחידה.
- יוצרים מנגנון להשקת תכונות (סוג ההשקה) שמגדיר את אסטרטגיית ההפצה.
- מפיצים את ההגדרה הראשונית של הדגל באמצעות השקת גרסה של App Lifecycle Manager.
- מריצים באופן מקומי אפליקציית Python לדוגמה שמתחברת לשירות הדגלים של App Lifecycle Manager ומעריכה את הדגל עבור היחידה הממוּדלת.
- מעדכנים את ערך הדגל, יוצרים גרסה חדשה של הדגל ומפיצים את השינוי.
- מוודאים שהאפליקציה משתמשת בערך המעודכן של הדגל.
לפני שמתחילים
-
נכנסים לחשבון 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
-
אימות של gcloud ל-Application Default Credentials (ADC): סקריפט Python המקומי משתמש ב-ADC כדי לאמת את שירותי Google Cloud . נכנסים באמצעות חשבון המשתמש:
gcloud auth application-default login
-
מתן הרשאות לזהות האפליקציה: האפליקציה צריכה הרשאה לקרוא את הגדרות הדגלים משירות SaaS Config. מקצים את התפקיד `roles/saasconfig.viewer` לזהות שבה האפליקציה תשתמש. במדריך למתחילים הזה, שבו משתמשים ב-ADC באופן מקומי עם חשבון המשתמש, מקצים את התפקיד לכתובת האימייל שלכם:
מחליפים את PROJECT_ID במזהה הפרויקט Google Cloud ואת 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}יצירת סוג יחידה: כאן מגדירים את סוג הרכיב שמבצעים לו מודלינג. חשוב לציין שאנחנו לא מספקים תוכנית, כי אנחנו לא מנהלים את התשתית.
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}
הגדרה והשקה של ה-feature flag
עכשיו, יוצרים את ה-feature flag בפועל ומשתמשים במנגנון ההשקה של 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"
שילוב והרצה של אפליקציית הדוגמה
מריצים אפליקציית Python לדוגמה באופן מקומי כדי להתחבר לשירות הדגלים של App Lifecycle Manager באמצעות הגדרות היחידה שעוצבו.
יוצרים ספרייה וקבצים לפרויקט:
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יוצרים את הקובץ 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)מריצים את האפליקציה:
export FLAGD_SOURCE_PROVIDER_ID="projects/${PROJECT_ID}/locations/${LOCATION_1}/featureFlagsConfigs/${UNIT_ID}" python app.pyאימות ערך הדגל הראשוני: מריצים בדיקה מול נקודת הקצה המקומית בטרמינל משני.
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 על המשאבים שבהם השתמשתם בדף הזה, מבצעים את הפעולות הבאות.
- לוחצים על
Ctrl+Cבמסוף שבוapp.pyפועל כדי לעצור את אפליקציית 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
המאמרים הבאים
- למידע נוסף על הקונספט, קראו את הסקירה הכללית על ה-feature flags של App Lifecycle Manager.
- כדי לראות איך feature flags משתלבים בצורה הדוקה עם פריסות שמנוהלות על ידי App Lifecycle Manager, נסו את המדריך למתחילים בנושא פריסת feature flags.