Go で App Lifecycle Manager の機能フラグを使用する

このガイドでは、Go アプリケーションを App Lifecycle Manager の機能フラグと統合する方法について説明します。OpenFeature SDK と flagd プロバイダを使用して、App Lifecycle Manager で管理されるフラグを評価し、Go サービスで機能の可用性と動作を動的に制御する方法について説明します。

このガイドでは、次のいずれかのクイックスタートを完了して、必要な App Lifecycle Manager リソース(SaaS サービス、ユニットの種類、ユニット、フラグ、ロールアウトなど)がすでに設定されていることを前提としています。

前提条件

始める前に、次の準備をしてください。

  1. Go がインストールされている: バージョン 1.23 以降。
  2. App Lifecycle Manager の機能フラグのクイックスタートを完了している:
    • 統合またはスタンドアロンの機能フラグのクイックスタートを正常に完了して、ターゲット ユニットをプロビジョニングしている。
    • そのクイックスタートの環境変数または値(PROJECT_IDLOCATION_1(ユニットのリージョン)、UNIT_IDFLAG_KEY など)がある。
  3. アプリケーションのデフォルト認証情報(ADC)の gcloud を認証している: Go アプリケーションは ADC を使用して Google Cloud サービスを認証します。ローカルで実行している場合(スタンドアロンで使用する場合、またはローカル Docker テストの場合)は、環境で認証されていることを確認してください。

    gcloud auth application-default login
    
  4. IAM 権限: Go アプリケーションを実行する ID には、 プロジェクトに対する roles/saasconfig.viewer Identity and Access Management ロールが必要です。これにより、フラグ構成を読み取ることができます。 Google Cloud

    gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
        --member="user:YOUR_EMAIL_ADDRESS" \
        --role="roles/saasconfig.viewer"
    

    YOUR_PROJECT_IDYOUR_EMAIL_ADDRESS は適宜置き換えてください。

重要な環境変数について

Go アプリケーションは、環境変数を使用して正しいフラグ構成に接続し、目的のフラグを評価します。

  • FLAGD_SOURCE_PROVIDER_ID: App Lifecycle Manager サービスから取得するフィーチャー トグル構成を指定します。ユニットに関連付けられた FeatureFlagConfig の完全なリソース名である必要があります。
    • 形式: projects/PROJECT_ID/locations/LOCATION/featureFlagsConfigs/UNIT_ID
    • : projects/my-gcp-project/locations/us-central1/featureFlagsConfigs/my-app-instance-01

Go プロジェクトを設定する

アプリケーションを実行する前に、モジュールを初期化し、必要な初期化ロジックと評価ロジックを追加します。

  1. プロジェクト ディレクトリを作成します。

    mkdir go-featureflag-app
    cd go-featureflag-app
    go mod init go-featureflag-app
    
  2. アプリケーション コードを作成します。 次の内容の main.go という名前のファイルを追加して、プロバイダを初期化し、フラグを評価します。

    package main
    
    import (
        "context"
        "fmt"
        "log"
        "os"
    
        flagd "github.com/open-feature/go-sdk-contrib/providers/flagd/pkg"
        "github.com/open-feature/go-sdk/openfeature"
        "google.golang.org/grpc"
        "google.golang.org/grpc/credentials"
        "google.golang.org/grpc/credentials/oauth"
        "google.golang.org/grpc/metadata"
    )
    
    // GetNewFlagdProvider initializes a flagd provider configured for  App Lifecycle Manager
    func GetNewFlagdProvider(ctx context.Context) (*flagd.Provider, error) {
        providerID := os.Getenv("FLAGD_SOURCE_PROVIDER_ID")
        if providerID == "" {
            return nil, fmt.Errorf("FLAGD_SOURCE_PROVIDER_ID environment variable is not set")
        }
    
        creds, err := oauth.NewApplicationDefault(ctx)
        if err != nil {
            return nil, err
        }
    
        // Interceptor to inject the Unit name into headers for regional routing
        routingInterceptor := func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
            md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("name=%s", providerID))
            ctx = metadata.NewOutgoingContext(ctx, md)
            return streamer(ctx, desc, cc, method, opts...)
        }
    
        options := []flagd.ProviderOption{
            flagd.WithHost("saasconfig.googleapis.com"),
            flagd.WithPort(443),
            flagd.WithInProcessResolver(),
            flagd.WithProviderID(providerID),
            flagd.WithGrpcDialOptionsOverride([]grpc.DialOption{
                grpc.WithTransportCredentials(credentials.NewTLS(nil)),
                grpc.WithPerRPCCredentials(creds),
                grpc.WithStreamInterceptor(routingInterceptor),
            }),
        }
    
        return flagd.NewProvider(options...)
    }
    
    // InitializeFeatureManagement registers the provider globally
    func InitializeFeatureManagement(ctx context.Context) error {
        provider, err := GetNewFlagdProvider(ctx)
        if err != nil {
            return err
        }
        openfeature.SetProvider(provider)
        return nil
    }
    
    func main() {
    ctx := context.Background()
    InitializeFeatureManagement(ctx);
    
    // 1. Get Client
    client := openfeature.NewClient("simple-api")
    
    // 2. Create Evaluation Context
    evalCtx := openfeature.NewEvaluationContext()
    
    // 3. Evaluate Flag
    // Default to false if evaluation fails
    isEnhanced, err := client.BooleanValue(context.Background(), "enhanced-search", false, evalCtx)
    if err != nil {
    log.Printf("Flag evaluation failed: %v", err)
    }
    
    // 4. Return response
    if isEnhanced {
    fmt.Println("Enhanced search feature is enabled.")
    } else {
    fmt.Println("Enhanced search feature is disabled.")
    }
    
    }
    
  3. go.mod を作成します。 特定のバージョンを使用すると、安定性が確保されます。

    module go-featureflag-app
    
    go 1.23
    
    require (
        github.com/open-feature/go-sdk v1.15.1
        github.com/open-feature/go-sdk-contrib/providers/flagd v0.3.0
        google.golang.org/grpc v1.74.2
        golang.org/x/oauth2 v0.22.0
    )
    
  4. 依存関係を取得します。

    go mod tidy
    go mod download
    

Go アプリケーションを実行する

アプリケーションは、スタンドアロン構成を使用してローカルで実行することも、コンテナとしてデプロイすることもできます。

スタンドアロン(ローカル)で実行する

  1. 環境変数を設定します。

    export PROJECT_ID="your-gcp-project-id"
    export LOCATION_1="us-central1"
    export UNIT_ID="my-app-instance-01"
    export FLAGD_SOURCE_PROVIDER_ID="projects/${PROJECT_ID}/locations/${LOCATION_1}/featureFlagsConfigs/${UNIT_ID}"
    
  2. アプリケーションを実行します。

    go run main.go
    

統合(コンテナ化)を実行する

  1. Dockerfile を作成します。

    FROM golang:1.23 as builder
    WORKDIR /app
    COPY go.mod go.sum ./
    RUN go mod download
    COPY . .
    RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /go-featureflag-app .
    
    FROM gcr.io/distroless/static-debian11
    WORKDIR /
    COPY --from=builder /go-featureflag-app /go-featureflag-app
    ENTRYPOINT ["/go-featureflag-app"]
    
  2. イメージをビルドして push します。

    export PROJECT_ID="your-gcp-project-id"
    docker build -t gcr.io/${PROJECT_ID}/my-go-app:latest .
    docker push gcr.io/${PROJECT_ID}/my-go-app:latest
    
  3. サービスをデプロイします。 ユニット ブループリントを更新して gcr.io/${PROJECT_ID}/my-go-app:latest を参照し、App Lifecycle Manager のロールアウトを使用して新しいリリースをデプロイします。

フラグの変更を確認する

アプリケーションが実行されたら、フラグが正しく評価されることを確認します。

  1. 初期値を観察する: 出力に初期状態に対応する値が記録されていることを確認します。
  2. App Lifecycle Manager でフラグを更新する: コンソールまたは Google Cloud を使用してフラグの動作を変更します。gcloud
  3. 更新された値を確認する: ローカル コンパイルを再実行するか、コンテナログを観察して、更新された結果を確認します。

次のステップ