Menggunakan tombol fitur App Lifecycle Manager dengan Go

Panduan ini menjelaskan cara mengintegrasikan aplikasi Go Anda dengan flag fitur App Lifecycle Manager. Anda akan mempelajari cara menggunakan OpenFeature SDK dengan penyedia flagd untuk mengevaluasi flag yang dikelola oleh App Lifecycle Manager, sehingga Anda dapat mengontrol ketersediaan dan perilaku fitur secara dinamis di layanan Go Anda.

Panduan ini mengasumsikan bahwa Anda telah menyiapkan resource App Lifecycle Manager yang diperlukan (seperti penawaran SaaS, jenis unit, unit, flag, dan peluncuran) dengan menyelesaikan salah satu panduan memulai berikut:

Prasyarat

Sebelum memulai, pastikan Anda memiliki hal berikut:

  1. Go diinstal: Versi 1.23 atau yang lebih baru.
  2. Menyelesaikan Panduan Memulai flag fitur App Lifecycle Manager:
    • Berhasil menyelesaikan panduan memulai flag fitur terintegrasi atau mandiri untuk menyediakan unit target Anda.
    • Anda harus memiliki variabel atau nilai lingkungan dari panduan memulai tersebut, seperti PROJECT_ID, LOCATION_1 (region Unit Anda), UNIT_ID, dan FLAG_KEY.
  3. gcloud yang diautentikasi untuk Kredensial Default Aplikasi (ADC): Aplikasi Go menggunakan ADC untuk melakukan autentikasi dengan Google Cloud layanan. Jika berjalan secara lokal (untuk penggunaan mandiri, atau pengujian Docker lokal), pastikan Anda telah melakukan autentikasi di lingkungan Anda:

    gcloud auth application-default login
    
  4. Izin IAM: Identitas yang menjalankan aplikasi Go Anda memerlukan peran Identity and Access Management roles/saasconfig.viewer di Google Cloud project Anda untuk membaca konfigurasi flag:

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

    Ganti YOUR_PROJECT_ID dan YOUR_EMAIL_ADDRESS sebagaimana mestinya.

Memahami variabel lingkungan utama

Aplikasi Go Anda mengandalkan variabel lingkungan untuk terhubung ke konfigurasi flag yang benar dan mengevaluasi flag yang dimaksud.

  • FLAGD_SOURCE_PROVIDER_ID: Menentukan konfigurasi flag fitur mana yang akan diambil dari layanan App Lifecycle Manager. Harus berupa nama resource lengkap FeatureFlagConfig yang terkait dengan unit Anda.
    • Format: projects/PROJECT_ID/locations/LOCATION/featureFlagsConfigs/UNIT_ID
    • Contoh: projects/my-gcp-project/locations/us-central1/featureFlagsConfigs/my-app-instance-01

Menyiapkan project Go Anda

Sebelum dapat menjalankan aplikasi, inisialisasi modul Anda dan tambahkan logika inisialisasi dan evaluasi yang diperlukan.

  1. Buat direktori project:

    mkdir go-featureflag-app
    cd go-featureflag-app
    go mod init go-featureflag-app
    
  2. Buat kode aplikasi: Tambahkan file bernama main.go dengan konten berikut untuk menginisialisasi penyedia dan mengevaluasi flag.

    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. Buat go.mod: Menggunakan versi tertentu akan memastikan stabilitas.

    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. Dapatkan dependensi:

    go mod tidy
    go mod download
    

Menjalankan aplikasi Go

Anda dapat menjalankan aplikasi secara lokal menggunakan konfigurasi mandiri atau di-deploy sebagai container.

Menjalankan mandiri (secara lokal)

  1. Tetapkan variabel lingkungan:

    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. Jalankan aplikasi:

    go run main.go
    

Menjalankan terintegrasi (dalam container)

  1. Buat 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. Build dan kirim image:

    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. Deploy layanan: Perbarui cetak biru unit Anda untuk mereferensikan gcr.io/${PROJECT_ID}/my-go-app:latest dan deploy rilis baru menggunakan peluncuran App Lifecycle Manager.

Memverifikasi perubahan flag

Setelah aplikasi Anda berjalan, pastikan aplikasi tersebut mengevaluasi flag dengan benar.

  1. Amati nilai awal: Pastikan output mencatat nilai yang sesuai dengan status awal.
  2. Perbarui flag di App Lifecycle Manager: Ubah perilaku flag menggunakan Google Cloud konsol atau gcloud.
  3. Verifikasi nilai yang diperbarui: Jalankan kembali kompilasi lokal atau amati log container untuk melihat hasil yang diperbarui.

Langkah berikutnya