Usar flags de recurso independentes

Aprenda a usar as flags de recurso do App Lifecycle Manager como um serviço independente para gerenciar a disponibilidade de recursos nos seus aplicativos, mesmo que eles não sejam implantados ou gerenciados pelo App Lifecycle Manager.

Introdução

Este guia de início rápido mostra como usar os recursos robustos de sinalização de recursos e lançamento controlado do App Lifecycle Manager sem precisar usar o App Lifecycle Manager para provisionamento de infraestrutura (como a implantação de VMs ou serviços do Cloud Run usando blueprints do Terraform). Essa abordagem é ideal se você gerenciar a infraestrutura do aplicativo de forma independente, mas quiser usar o App Lifecycle Manager para o gerenciamento seguro de flag de recurso.

Nessa abordagem independente, você vai:

  1. Modelar seu sistema com recursos leves do App Lifecycle Manager:crie Units do App Lifecycle Manager para representar componentes da sua infraestrutura atual (por exemplo, uma implantação de microsserviço específica, um ambiente de locatário, uma única instância binária). Essas unidades atuam apenas como destinos para configurações de flag e não envolvem a implantação de infraestrutura usando blueprints do App Lifecycle Manager.
  2. Definir e distribuir flags: use a API do App Lifecycle Manager ou o Google Cloud console para criar flags de recursos. Gerencie o ciclo de vida delas usando Rollouts do App Lifecycle Manager para garantir a propagação segura e gradual das mudanças de configuração para as Units modeladas. Isso oferece consistência e segurança operacional, mesmo ao gerenciar apenas flags.
  3. Integrar ao aplicativo: use o SDK do OpenFeature com o provedor flagd no código do aplicativo (executado em qualquer lugar: localmente, no local, na nuvem autogerenciada). Configure-o para se conectar ao serviço de flag do App Lifecycle Manager (saasconfig.googleapis.com), autenticar e se identificar usando o nome do recurso Unit correspondente para buscar os valores de flag corretos.

Essa abordagem permite que você se beneficie da distribuição de flags gerenciada e segura sem alterar os pipelines de implantação ou as ferramentas de gerenciamento de infraestrutura atuais.

As flags de recursos do App Lifecycle Manager estão em prévia particular. O acesso exige a inclusão na lista de permissões. Para solicitar acesso à sua organização ou projeto, preencha este formulário.

Este guia de início rápido usa um aplicativo Python básico executado localmente para demonstrar o acesso às flags, simulando como seu aplicativo atual seria integrado.

Objetivos

  • Configurar um novo Google Cloud projeto ou usar um já existente.
  • Ativar as APIs necessárias (App Lifecycle Manager e SaaS Config).
  • Conceder as permissões necessárias do Identity and Access Management para a criação de recursos e a leitura de flags.
  • Criar recursos mínimos do App Lifecycle Manager (SaaS Offering, Unit Kind, Unit) para modelar um componente de aplicativo sem implantar a infraestrutura.
  • Definir um recurso de flag de recurso associado ao tipo de unidade.
  • Criar um mecanismo de lançamento de flag (Rollout Kind) que defina a estratégia de distribuição.
  • Distribuir a configuração inicial da flag usando um lançamento do App Lifecycle Manager.
  • Executar um aplicativo Python de exemplo localmente que se conecta ao serviço de flag do App Lifecycle Manager e avalia a flag da unidade modelada.
  • Atualizar o valor da flag, criar uma nova versão da flag e distribuir a mudança.
  • Verificar se o aplicativo seleciona o valor da flag atualizado.

Antes de começar

  1. Faça login na sua Conta do Google.

    Se você ainda não tiver uma, inscreva-se agora.

  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. Instale a Google Cloud CLI.

  6. Ao usar um provedor de identidade (IdP) externo, primeiro faça login na gcloud CLI com sua identidade federada.

  7. Para inicializar a CLI gcloud, execute o seguinte comando:

    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. Instale a Google Cloud CLI.

  12. Ao usar um provedor de identidade (IdP) externo, primeiro faça login na gcloud CLI com sua identidade federada.

  13. Para inicializar a CLI gcloud, execute o seguinte comando:

    gcloud init
  14. Instalar o Python:verifique se o Python 3.7 ou mais recente está instalado na máquina em que você vai executar o aplicativo de exemplo. Você também precisa do pip para instalar dependências.
    python --version
    pip --version
  15. Autenticar a gcloud para o Application Default Credentials (ADC): o script Python local usa o ADC para autenticar Google Cloud serviços. Faça login usando sua conta de usuário:
    gcloud auth application-default login
  16. Permissões de identidade do aplicativo:seu aplicativo precisa de permissão para ler configurações de flag do serviço SaaS Config. Conceda o papel `roles/saasconfig.viewer` à identidade que o aplicativo vai usar. Para este guia de início rápido usando o ADC localmente com sua conta de usuário, conceda o papel ao seu endereço de e-mail:
        gcloud projects add-iam-policy-binding PROJECT_ID \
            --member="user:YOUR_EMAIL_ADDRESS" \
            --role="roles/saasconfig.viewer"
    Substitua PROJECT_ID pelo ID do seu Google Cloud projeto e YOUR_EMAIL_ADDRESS pelo e-mail associado ao login da CLI.

Criar recursos mínimos do App Lifecycle Manager

Mesmo que não estejamos implantando a infraestrutura com o App Lifecycle Manager, precisamos de alguns recursos para organizar, segmentar e distribuir nossas flags com segurança. Esses recursos representam os componentes do aplicativo atual no App Lifecycle Manager.

  1. Definir variáveis:defina variáveis de ambiente para nomes e locais de recursos.

    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. Criar uma oferta de SaaS:ela atua como um contêiner de nível superior para a configuração do serviço, incluindo flags.

    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. Criar um tipo de unidade:isso define o tipo de componente que você está modelando. É importante ressaltar que não fornecemos um blueprint porque não estamos gerenciando a infraestrutura.

    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. Criar uma unidade:ela representa uma instância específica do aplicativo.

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

Definir e lançar a flag de recurso

Agora, crie a flag de recurso real e use o mecanismo de lançamento do App Lifecycle Manager para disponibilizar a configuração dela para as unidades criadas.

  1. Definir variáveis de flag :

    export FLAG_ID="standalone-flag-01"
    export FLAG_KEY="enable-beta-feature" 
    
  2. Criar o recurso de flag, a revisão e a versão :

    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. Criar um tipo de lançamento:defina a estratégia de distribuição de mudanças de flag.

    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. Criar o lançamento:inicie o processo de distribuição.

    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. Monitorar o lançamento:verifique se a implantação foi bem-sucedida antes de continuar.

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

Configurar a infraestrutura independente

Em uma configuração independente, você gerencia sua própria hospedagem de aplicativos (por exemplo, Cloud Run ou GKE) e usa o App Lifecycle Manager apenas para sincronização de configuração. O código do aplicativo permanece padrão em todas as implantações. Ele só exige que a variável de ambiente FLAGD_SOURCE_PROVIDER_ID esteja presente no ambiente de execução para se conectar ao serviço SaaS Config.

É possível mapear as definições de unidade do App Lifecycle Manager nas definições de implantação padrão do Terraform transmitindo o caminho construído como uma variável de ambiente.

  1. Definir a infraestrutura:mapeie o caminho no modelo de implantação (por exemplo, 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. Definir os valores das variáveis:forneça os parâmetros da unidade de configuração em um arquivo de variáveis associado (por exemplo, terraform.tfvars).

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

Integrar e executar o aplicativo de exemplo

Execute um aplicativo Python de exemplo localmente para se conectar ao serviço de flag do App Lifecycle Manager usando as configurações de unidade modeladas.

  1. Criar diretório e arquivos do projeto :

    mkdir saas_flags_standalone_app
    cd saas_flags_standalone_app
    

    Crie 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
    

    Instale as dependências:

    pip install -r requirements.txt
    
  2. Criar 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. Execute o aplicativo :

    export FLAGD_SOURCE_PROVIDER_ID="projects/${PROJECT_ID}/locations/${LOCATION_1}/featureFlagsConfigs/${UNIT_ID}"
    python app.py
    
  4. Verificar o valor inicial da flag:execute uma verificação no endpoint local em um terminal secundário.

    curl http://localhost:8080
    

Atualizar a flag e distribuir a mudança

Modifique o estado do ambiente de execução da definição de flag e distribua a atualização para os destinos conectados.

  1. Atualizar o recurso de flag :

    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. Criar um novo lançamento para a atualização :

    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. Monitorar o novo lançamento :

    gcloud beta app-lifecycle-manager rollouts describe ${ROLLOUT_ID_2} \
      --project=${PROJECT_ID} \
      --location=global 
    
  4. Verificar a mudança no aplicativo em execução :

    curl http://localhost:8080
    

Limpar

Para evitar cobranças na conta do Google Cloud pelos recursos usados nesta página, siga as etapas abaixo.

  1. Pressione Ctrl+C no terminal em que app.py está em execução para interromper o aplicativo Python local.
  2. Defina o estado da flag.
  3. Crie um novo lançamento para remover flags obsoletas.
  4. Depois que o lançamento for concluído e as flags obsoletas forem removidas, exclua os recursos do 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. Exclua o diretório local:

    cd ..
    rm -rf saas_flags_standalone_app
    

A seguir