Close

Verwenden von LaunchDarkly-Feature-Flags mit Bitbucket Pipelines

Portrait Warren Marusiak
Warren Marusiak

Senior Technical Evangelist

Das Bereitstellen von neuem Code in einer Produktionsumgebung ist riskant. Bugs können auch dann in die Produktionsumgebung gelangen, wenn der Code in Test- und Staging-Umgebungen Unit-Tests, Integrationstests und Systemtests durchlaufen hat. Bisher hatten Entwickler zwei Möglichkeiten, wenn ein Bug in die Produktionsumgebung gelangt war und Benutzer davon betroffen waren: Sie konnten ein Rollback für den fehlerhaften Code oder ein Rollforward auf eine Version mit Fix durchführen. Beide Varianten brauchten Zeit. Jetzt können Entwickler eine Funktion in einer Umgebung mit nur einem Klick aktivieren oder deaktivieren, indem sie die entsprechenden Codeänderungen in ein Feature-Flag einschließen. So können die Auswirkungen von fehlerhaftem Code auf Benutzer sofort gemildert werden und die Entwickler erhalten die Möglichkeit, auf sichere Weise einen Fix zu entwickeln und zu implementieren. In diesem Artikel wird dieser Prozess mit Bitbucket Pipelines und LaunchDarkly-Feature-Flags in der ImageLabeller-Demo-Anwendung demonstriert.

ImageLabeller-Feature-Flag-Demo

ImageLabeller ist eine kleine Anwendung, die maschinelles Lernen nutzt, um Images mit Stichwörtern zu versehen. ImageLabeller wird in fünf Umgebungen bereitgestellt: Test, Staging, Production-us-west-2, Production-us-east-1 und Production-ca-central-1. In diesem Artikel erfährst du, wie du mithilfe von Feature-Flags Änderungen an der SubmitImage-Komponente von ImageLabeller verwalten kannst. SubmitImage ist ein in Go geschriebenes AWS Lambda. Verwendet werden LaunchDarkly zum Verwalten von Feature-Flags, Bitbucket für die Quellcodekontrolle und Bitbucket Pipelines für CI/CD-Funktionen.

So verwendest du LaunchDarkly-Feature-Flags mit Bitbucket Pipelines

Bitte deinen lokalen LaunchDarkly-Administrator, ein Projekt und eine Umgebung zu erstellen. Der Screenshot unten zeigt ein Projekt namens "PMMImageLabellerDemo" mit fünf Umgebungen. Test und Staging sind Vorproduktionsumgebungen. Notiere den SDK-Schlüssel für jede Umgebung. Die SDK-Schlüssel werden später als Repository-Variablen in Bitbucket hinzugefügt.

In diesem Beispiel wird Bitbucket Pipelines in diesen Umgebungen bereitgestellt, wenn Code an einen Feature Branch committed wird. Production-us-west-2, Production-us-east-1 und Production-ca-central-1 sind Produktionsumgebungen, die AWS-Umgebungen entsprechen. Bitbucket Pipelines wird in diesen Umgebungen bereitgestellt, wenn Code von einem Feature Branch per Pull-Anfrage in "mainline" gemergt wird.

Screenshot: Bitbucket Pipelines

Erstelle in LaunchDarkly ein Feature-Flag für das Projekt. Wähle die Testumgebung aus und passe die Feature-Flag-Einstellungen an. Im Screenshot unten ist das Feature-Flag so eingestellt, dass es in der Testregion standardmäßig true zurückgibt. Wenn ein bestimmter Benutzer, AtlassianTestUser@atlassian.com, die Anfrage stellt, gibt das Feature-Flag den Wert false zurück. Auf diese Weise kann dieser benannte Benutzer, wie Testbenutzer in einer Systemtestsuite, den Code auf eine Weise ausführen lassen, während normale Benutzer in derselben Umgebung den Code anders ausführen lassen.

Dieses Verhalten kann für jede Umgebung separat angepasst werden. Mithilfe von Feature-Flags können Entwickler neuen Code in allen Regionen bereitstellen, die Ausführung des Codes aber nur in bestimmten Umgebungen zulassen. Im Fall dieser Demo ist das Flag so eingestellt, dass es in der Staging-Umgebung und in allen drei Produktionsumgebungen false zurückgibt. Der neue Code wird nur in der Testumgebung ausgeführt.

Screenshot: Benutzer-Targeting

Rufe die SDK-Schlüssel für die einzelnen Umgebungen aus LaunchDarkly ab. Füge dann in Bitbucket jedem Repository, das dieses Flag verwenden soll, Repository-Variablen hinzu. Der Screenshot unten zeigt, dass fünf Repository-Variablen hinzugefügt wurden. "ld_test_env" enthält den LaunchDarkly-SDK-Schlüssel für die Testumgebung. "ld_staging_env" enthält den LaunchDarkly-SDK-Schlüssel für die Staging-Umgebung. Diese Repository-Variablen werden später als Referenzen in der Datei "bitbucket-pipelines.yml" für das Repository verwendet.

SDK-Schlüssel

Die SDK-Schlüsselwerte können in der Datei "bitbucket-pipeline.yml" des Repositorys als Referenzen verwendet werden, wenn die SDK-Schlüssel als Repository-Variablen hinzugefügt wurden. Im unten dargestellten Snippet wird "STACK_PARAMETERS" dem Deployment-Schritt für production-ca-central-1 hinzugefügt. "STACK_PARAMETERS" sendet den Wert des entsprechenden SDK-Schlüssels als Parameter an die AWS CloudFormation-Datei "template.yml".

- pipe: atlassian/aws-sam-deploy:1.2.0
  variables:
    AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
    AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
    AWS_DEFAULT_REGION: 'ca-central-1'
    STACK_NAME: 'OpenDevOpsSubmitImage'
    CAPABILITIES: [ 'CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND' ]
    TEMPLATE: 'https://s3.amazonaws.com/open-devops-code-ca-central-1-${AWS_ACCOUNT_ID}/submit-image-packaged.yml'
    WAIT: 'true'
    DEBUG: 'true'
    S3_BUCKET: 'open-devops-code-ca-central-1-${AWS_ACCOUNT_ID}'
    SAM_TEMPLATE: 'build/template.yaml'
    STACK_PARAMETERS: '[{
      "ParameterKey": "LaunchDarklySDKKey",
      "ParameterValue": "${ld_prod_cac1_env}"
    }]'

Füge den Abschnitt "Parameter" mit LaunchDarklySDKKey vom Typ "String" zum Abschnitt "Parameter" der Datei "template.yml" des Repositorys hinzu. Dieser Parameter erhält den Wert des LaunchDarklySDKKEY "STACK_PARAMETER", der in der Datei "bitbucket-pipelines.yml" festgelegt wurde.

Parameters:
  LaunchDarklySDKKey:
    Type: String

Aktualisiere auch die AWS Lambda-Ressource für die SubmitImage-Funktion in der Datei "template.yml". Füge "LaunchDarklySDKKey" als Umgebungsvariable hinzu.

Resources:
  SubmitImageFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: submitImage/
      Handler: submit-image
      Runtime: go1.x
      Tracing: Active # https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html
      Policies:
        - AmazonDynamoDBFullAccess
        - AmazonS3FullAccess
      Events:
        CatchAll:
          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /submit-image
            Method: GET
      Environment:
        Variables:
          LaunchDarklySDKKey:
            Ref: LaunchDarklySDKKey

Die Umgebungsvariable "LaunchDarklySDKKey" wird in der AWS Lambda-Konsole angezeigt, nachdem Bitbucket Pipelines in der Umgebung bereitgestellt wurde. Der Wert dieses Schlüssels ist in der Umgebung eindeutig. Zum Beispiel unterscheidet sich die Umgebungsvariable "LaunchDarklySDKKey" in Test von derjenigen in Production-us-west-2.

Screenshot: Umgebungskonfigurationen

SubmitImage ist ein in Go geschriebenes AWS Lambda. Um LaunchDarkly mit Go zu verwenden, importiere die nachfolgend angegebenen Abhängigkeiten.

"gopkg.in/launchdarkly/go-sdk-common.v2/lduser"
ld "gopkg.in/launchdarkly/go-server-sdk.v5"

Füge eine Funktion hinzu, um den Feature-Flag-Wert aus LaunchDarkly zur Laufzeit abzurufen.

func getLaunchDarklyFlags(username string) (bool, error) {
  client, _ := ld.MakeClient(os.Getenv("LaunchDarklySDKKey"), 5 * time.Second)
  flagKey := "SubmitImageDemoFeature"

  userUuid, uuidErr := uuid.NewRandom()
  if uuidErr != nil {
    return false, uuidErr
  }

  var user lduser.User
  if(username == "") {
    user = lduser.NewAnonymousUser(userUuid.String())
  } else {
    user = lduser.NewUser(username)
  }

  showFeature, _ := client.BoolVariation(flagKey, user, false)

  if showFeature {
    return true, nil
  } else {
    return false, nil
  }
}

Rufe die Funktion mit einer leeren Zeichenfolge auf, um den Standard-Flag-Wert zu erhalten. Bei Aufruf mit einer Benutzer-E-Mail-Adresse wird der Zielwert zurückgegeben. Die oben gezeigte Einrichtung sollte für den anonymen Benutzer "true" und für den Benutzer AtlasianTestUser@atlassian.com "false" abrufen.

flagVal, flagErr  := getLaunchDarklyFlags("")
  if flagErr != nil {
    return "", flagErr
  }
  fmt.Println("DEMO flagVal for anonymous user: ", flagVal)

  flagVal, flagErr  = getLaunchDarklyFlags("AtlassianTestUser@atlassian.com")
  if flagErr != nil {
    return "", flagErr
  }
  fmt.Println("DEMO flagVal for AtlassianTestUser@atlassian.com: ", flagVal)

Überprüfe nach dem Ausführen des Codes in den AWS CloudWatch-Protokollen, ob die richtigen Flag-Werte abgerufen werden.

Screenshot: Protokollereignisse
Kopieren von Zielregeln

Unter Admin settings > API keys (Admin-Einstellungen > API-Schlüssel) kannst du eine Liste der API-Schlüssel für die einzelnen Umgebungen abrufen. Diese API-Schlüssel werden bei API-Aufrufen im Code an Split zurückgesendet, um die richtige Version eines Splits zu erhalten. In diesem Leitfaden werden für alle Umgebungen die serverseitigen Schlüssel verwendet.

Admin-Einstellungen

Wechsle zu deinem Bitbucket-Repository, dann zu den Repository-Einstellungen, dann zu den Repository-Variablen und füge Variablen für jeden API-Schlüssel hinzu.

Repository-Variablen in den Repository-Einstellungen

Bearbeite die Datei bitbucket-pipelines.yml und füge STACK_PARAMETERS dem AWS SAM-Deployment-Schritt hinzu. Dies wird pro Umgebung durchgeführt. Das folgende YAML-Snippet zeigt den Deployment-Schritt für die TEST-Region, die sich in AWS US-WEST-1 befindet. Daher verweist der Schritt auf die zuvor eingerichtete Repository-Variable split_test_env. Verwende die passende Repository-Variable für jede Umgebung.

- pipe: atlassian/aws-sam-deploy:1.2.0
  variables:
    AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
    AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
    AWS_DEFAULT_REGION: 'us-west-1'
    STACK_NAME: 'OpenDevOpsSubmitImage'
    CAPABILITIES: [ 'CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND' ]
    TEMPLATE: 'https://s3.amazonaws.com/open-devops-code-us-west-1-${AWS_ACCOUNT_ID}/submit-image-packaged.yml'
    WAIT: 'true'
    DEBUG: 'true'
    S3_BUCKET: 'open-devops-code-us-west-1-${AWS_ACCOUNT_ID}'
    SAM_TEMPLATE: 'build/template.yaml'
    STACK_PARAMETERS: '[{
      "ParameterKey": "SplitIOSDKKey",
      "ParameterValue": "${split_test_env}"
    }]'

Bearbeite die AWS CloudFormation-Datei "template.yml" und füge den Abschnitt "Parameter" hinzu, der auf den Split-SDK-Schlüssel verweist.

Parameters:
  SplitIOSDKKey:
    Type: String

Füge in der Datei "template.yml" jeder AWS Lambda-Ressource, die auf Split zugreifen muss, den Abschnitt "Umgebung" hinzu. Dieser Leitfaden zeigt

Environment:
  Variables:
    SplitIOSDKKey:
      Ref: SplitIOSDKKey

Importiere die nachfolgend genannten Abhängigkeiten in die Go-Datei, die das Split-SDK verwenden soll.

"github.com/splitio/go-client/v6/splitio/client"
"github.com/splitio/go-client/v6/splitio/conf"

Mit dieser Funktion wird ein Client erstellt und der Feature-Flag-Wert für das in der Split-UI erstellte "SubmitImageDemoSplit" abgerufen. Die Funktion erfordert nur einen Parameter: den Benutzernamen ("username").

func getSplitIOFlag(username string) (string, error) {
  splitIOSDKKey := os.Getenv("SplitIOSDKKey")

  cfg := conf.Default()
  factory, err := client.NewSplitFactory(splitIOSDKKey, cfg)
  if err != nil {
    fmt.Printf("SDK init error: %s\n", err)
    return "", err
  }

  splitClient := factory.Client()
  err = splitClient.BlockUntilReady(10)
  if err != nil {
    fmt.Printf("SDK timeout: %s\n", err)
    return "", err
  }

  treatment := splitClient.Treatment(username, "SubmitImageDemoSplit", nil)
  fmt.Printf("SPLIT_DEMO treatment is %s, username is %s\n", treatment, username)

  return treatment, nil
}

Rufe die Funktion mit einer E-Mail-Adresse auf. In diesem Fall wird bei someRandomUser@atlassian.com der Standardwert des Feature-Flags abgerufen, da der Benutzer nicht in einer mit dem Feature-Flag verknüpften Positivliste enthalten ist. Bei AtlassianTestUser@atlassian.com wird der Wert des Feature-Flags abgerufen, das der Positivliste zugeordnet ist, in der es enthalten ist.

Sieh dir die Ausgabe in den AWS CloudWatch-Protokollen an, nachdem der Code ausgeführt wurde. Du wirst bemerken, dass das Feature-Flag "off" zurückgibt, wenn es von someRandomUser@atlassian.com aufgerufen wird, und dass es "on" zurückgibt, wenn es von AtlassianTestUser@atlassian.com aufgerufen wird.

Protokollereignisse

Fazit

LaunchDarkly-Feature-Flags lassen sich problemlos in eine Anwendung integrieren, die über Bitbucket Pipelines bereitgestellt wird. Mit Feature-Flags können Entwickler die Ausführung des bereitgestellten Codes kontrollieren. Dadurch kann schneller auf fehlerhafte Deployments reagiert werden, wodurch die Auswirkungen auf die Benutzer reduziert werden. Nimm dir die Zeit, eine Bitbucket-Instanz und LaunchDarkly einzurichten und die Funktionen für dein Team zu testen.

Warren Marusiak
Warren Marusiak

Warren is a Canadian developer from Vancouver, BC with over 10 years of experience. He came to Atlassian from AWS in January of 2021.


Diesen Artikel teilen

Lesenswert

Füge diese Ressourcen deinen Lesezeichen hinzu, um mehr über DevOps-Teams und fortlaufende Updates zu DevOps bei Atlassian zu erfahren.

Abbildung: DevOps

DevOps-Community

Abbildung: DevOps

DevOps-Lernpfad

Abbildung: Karte

Kostenlos loslegen

Melde dich für unseren DevOps-Newsletter an

Thank you for signing up