שימוש בדגלי תכונות של App Lifecycle Manager עם Go

במדריך הזה מוסבר איך לשלב אפליקציות Go עם ה-feature flags של App Lifecycle Manager. תלמדו איך להשתמש ב-OpenFeature SDK עם הספק flagd כדי להעריך דגלים שמנוהלים על ידי App Lifecycle Manager, וכך לשלוט באופן דינמי בזמינות ובהתנהגות של תכונות בשירותי Go.

במדריך הזה אנחנו יוצאים מנקודת הנחה שכבר הגדרתם את המשאבים הנדרשים של App Lifecycle Manager (כמו הצעות לאפליקציות, סוגי יחידות, יחידות, דגלים והשקות) על ידי השלמת אחד מהמדריכים למתחילים הבאים:

דרישות מוקדמות

לפני שמתחילים, חשוב לוודא שהתנאים הבאים מתקיימים:

  1. Go installed: גרסה 1.23 ואילך.
  2. השלמתם את המדריך למתחילים בנושא Feature flags ב-App Lifecycle Manager:
    • השלמתם בהצלחה את ההגדרה של יחידת היעד באמצעות המדריך למתחילים בנושא דגלים של תכונות משולבות או עצמאיות.
    • אמורים להיות לכם משתני סביבה או ערכים מהמדריך למתחילים, כמו PROJECT_ID,‏ LOCATION_1 (האזור של היחידה), UNIT_ID ו-FLAG_KEY.
  3. אימות של gcloud באמצעות Application Default Credentials ‏ (ADC): האפליקציה ב-Go משתמשת ב-ADC כדי לאמת את שירותי Google Cloud . אם אתם מריצים את הפקודה באופן מקומי (לשימוש עצמאי או לבדיקת Docker מקומית), ודאו שביצעתם אימות בסביבה שלכם:

    gcloud auth application-default login
    
  4. הרשאות IAM: הזהות שמריצה את אפליקציית Go צריכה את תפקיד ניהול הזהויות והרשאות הגישה (IAM) של roles/saasconfig.viewer בפרויקט Google Cloud כדי לקרוא את הגדרות הדגלים:

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

    מחליפים את YOUR_PROJECT_ID ואת YOUR_EMAIL_ADDRESS בהתאם.

הסבר על משתני סביבה מרכזיים

אפליקציית Go מסתמכת על משתני סביבה כדי להתחבר להגדרת הדגל הנכונה ולהעריך את הדגל הרצוי.

  • ‫FLAGD_SOURCE_PROVIDER_ID: מציין איזו הגדרה של feature flag לאחזר משירות 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. יוצרים את קובץ האימג' ושולחים אותו:

    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. אימות הערך המעודכן: מריצים מחדש את הקומפילציה המקומית או בודקים את יומני הקונטיינר כדי לראות את התוצאה המעודכנת.

המאמרים הבאים