Close

Utilisation des feature flags LaunchDarkly avec Bitbucket Pipelines

Portrait de Warren Marusiak
Warren Marusiak

Senior Technical Evangelist

Le déploiement d'un nouveau code dans un environnement de production est risqué. Des bugs peuvent entrer en production même après que le code a été testé au niveau unitaire, de l'intégration et du système dans des environnements de test et de staging. Traditionnellement, les développeurs ont deux possibilités quand un bug arrive en production et que les utilisateurs sont touchés. Ils peuvent annuler le code qui pose problème ou déployer une correction ; ces deux solutions prennent du temps. Désormais, les développeurs peuvent activer ou désactiver une fonctionnalité dans un environnement en cliquant sur un bouton qui intègre les changements de code associés dans un feature flag. L'impact d'un code rempli de bugs sur les utilisateurs peut être atténué immédiatement, et une correction peut être développée et déployée en toute sécurité. Cet article présente cette solution à l'aide de Bitbucket Pipelines et des feature flags LaunchDarkly dans l'application de démo ImageLabeller.

Une démo de feature flag ImageLabeller

ImageLabeller est une petite application qui utilise l'apprentissage machine pour étiqueter des images. Elle est déployée dans cinq environnements : Test, Staging, Production-US-West-2, Production-us-east-1 et Production-ca-central-1. Cet article explique comment utiliser les feature flags pour gérer les changements apportés au composant SubmitImage d'ImageLabeller. SubmitImage est une fonction AWS Lambda écrite en Go. Vous utiliserez LaunchDarkly pour gérer les feature flags, Bitbucket pour le contrôle de version et Bitbucket Pipelines pour les fonctionnalités de CI/CD.

Comment utiliser les feature flags LaunchDarkly avec Bitbucket Pipelines

Demandez à votre administrateur LaunchDarkly local de créer un projet et un environnement. Sur la capture d'écran ci-dessous, nous voyons un projet, PMMImageLabellerDemo, avec cinq environnements. Les environnements de test et de staging sont des environnements de préproduction. Notez la clé SDK pour chaque environnement. Plus tard, les clés SDK seront ajoutées en tant que variables de dépôt dans Bitbucket.

Dans cet exemple, les pipelines Bitbucket sont déployés dans ces environnements lorsque le code est commité dans une branche de fonctionnalité. Production-us-west-2, Production-us-east-1 et Production-ca-central-1 sont des environnements de production qui correspondent aux environnements AWS. Les pipelines Bitbucket sont déployés dans ces environnements lorsque le code est mergé dans la branche principale, à partir d'une branche de fonctionnalité, par pull request.

Capture d'écran de Bitbucket Pipelines

Dans LaunchDarkly, créez un feature flag pour le projet. Sélectionnez l'environnement de test et ajustez les paramètres des feature flags. Sur la capture d'écran ci-dessous, le feature flag est réglé pour renvoyer par défaut la valeur true (vrai) dans la région de test. Si un utilisateur spécifique, AtlassianTestUser@atlassian.com, en fait la demande, le feature flag renverra false (faux). De cette façon, l'utilisateur spécifique nommé (p. ex., les utilisateurs de test dans une suite de tests système) peut faire exécuter le code d'une certaine manière tandis que les utilisateurs normaux du même environnement obtiennent le code pour qu'il s'exécute différemment.

Ce comportement peut être ajusté en fonction de l'environnement. Les feature flags permettent à un développeur de déployer du nouveau code dans toutes les régions, tout en autorisant l'exécution du code uniquement dans des environnements spécifiques. Dans le cas de cette démo, le flag est défini sur false dans l'environnement de staging et dans les trois environnements de production. Le nouveau code ne s'exécutera que dans l'environnement de test.

Capture d'écran du ciblage des utilisateurs

Récupérez les clés SDK pour chaque environnement à partir de LaunchDarkly. Ensuite, accédez à Bitbucket et ajoutez des variables de dépôt à chaque dépôt qui utilisera ce flag. La capture d'écran ci-dessous montre que cinq variables de dépôt ont été ajoutées. ld_test_env contient la clé SDK de LaunchDarkly pour l'environnement de test. ld_staging_env contient la clé SDK de LaunchDarkly pour l'environnement de staging. Ces variables de dépôt sont des références ultérieures dans le fichier bitbucket-pipelines.yml pour le dépôt.

Clés SDK

Les valeurs des clés SDK peuvent être des références dans le fichier bitbucket-pipeline.yml du dépôt une fois que les clés SDK ont été ajoutées en tant que variables de dépôt. STACK_PARAMETERS est ajouté à l'étape de déploiement de production-ca-central-1 dans le snippet ci-dessous. STACK_PARAMETERS envoie la valeur de la clé SDK correspondante au fichier template.yml d'AWS CloudFormation en tant que paramètre.

- 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}"
    }]'

Ajoutez une section Parameters (Paramètres) avec LaunchDarklySDKKey de type String (Chaîne) dans la section Parameters (Paramètres) du fichier template.yml du dépôt. Ce paramètre reçoit la valeur de LaunchDarklySDKKey STACK_PARAMETER définie dans le fichier bitbucket-pipelines.yml.

Parameters:
  LaunchDarklySDKKey:
    Type: String

Mettez également à jour la ressource AWS Lambda pour la fonction SubmitImage dans le fichier template.yml. Ajoutez LaunchDarklySDKKey comme variable d'environnement.

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

La variable d'environnement LaunchDarklySDKKey sera visible dans la console AWS Lambda une fois les pipelines Bitbucket déployés dans l'environnement. La valeur de cette clé est propre à l'environnement. Par exemple, la variable d'environnement LaunchDarklySDKKey dans Test sera différente de celle dans Production-us-west-2.

Capture d'écran des configurations d'environnement

SubmitImage est une fonction AWS Lambda écrite en Go. Pour utiliser LaunchDarkly avec Go, importez les dépendances suivantes.

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

Ajoutez une fonction pour récupérer la valeur du feature flag dans LaunchDarkly au moment de l'exécution.

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
  }
}

Appelez la fonction avec une chaîne vide pour récupérer la valeur du flag par défaut, ou avec un e-mail utilisateur pour récupérer la valeur ciblée. La configuration ci-dessus devrait afficher la valeur true (vrai) pour l'utilisateur anonyme et la valeur false (faux) pour l'utilisateur AtlasianTestUser@atlassian.com.

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)

Accédez aux journaux AWS CloudWatch après avoir exécuté le code pour vérifier que les bonnes valeurs de flag sont extraites.

Capture d'écran des événements du journal
Copie des règles de la cible

Accédez à Admin settings (Paramètres administrateur), puis à API keys (Clés d'API) pour obtenir la liste des clés d'API pour chaque environnement. Ces clés d'API sont renvoyées à Split lors des appels d'API sous forme de code afin d'obtenir la bonne version d'un split. Ce guide utilise les clés côté serveur pour chaque environnement.

Paramètres administrateur

Accédez à votre dépôt Bitbucket, à Repository settings (Paramètres du dépôt), puis à Repository variables (Variables de dépôt), et ajoutez des variables pour chaque clé d'API.

Variables de dépôt dans les paramètres du dépôt

Modifiez le fichier bitbucket-pipelines.yml et ajoutez STACK_PARAMETERS à l'étape de déploiement d'AWS SAM. Cette opération s'effectue par environnement. Le snippet YAML ci-dessous montre l'étape de déploiement pour la région TEST qui se trouve dans AWS US-WEST-1. L'étape fait donc référence à la configuration de la variable du dépôt split_test_env ci-dessus. Utilisez la variable de dépôt appropriée pour chaque environnement.

- 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}"
    }]'

Modifiez le fichier template.yml AWS CloudFormation et ajoutez une section Parameters (Paramètres) faisant référence à la clé SDK de Split.

Parameters:
  SplitIOSDKKey:
    Type: String

Dans le fichier template.yml, ajoutez une section Environment (Environnement) à chaque ressource AWS Lambda qui doit accéder à Split. Ce guide montre

Environment:
  Variables:
    SplitIOSDKKey:
      Ref: SplitIOSDKKey

Importez les dépendances suivantes dans le fichier Go qui utilisera le SDK Split.

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

Cette fonction crée un client et récupère la valeur du feature flag pour l'élément « SubmitImageDemoSplit » créé dans l'interface utilisateur Split. Un seul paramètre est requis, le nom d'utilisateur.

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
}

Appelez la fonction avec une adresse e-mail. Dans ce cas, someRandomUser@atlassian.com récupérera la valeur par défaut du feature flag, puisqu'il ne fait pas partie d'une liste verte associée au feature flag. AtlassianTestUser@atlassian.com extraira la valeur du feature flag associée à la liste verte dont elle est membre.

Regardez les résultats dans les journaux AWS CloudWatch une fois le code exécuté. Notez que le feature flag se désactive lorsque someRandomUser@atlassian.com y accède, et qu'il s'active à nouveau lorsque AtlassianTestUser@atlassian.com y accède.

Événements du journal

Conclusion…

Les feature flags LaunchDarkly s'intègrent facilement dans une application déployée via Bitbucket Pipelines. Les feature flags permettent aux développeurs de contrôler l'exécution du code déployé. Cela peut permettre de répondre plus rapidement aux déploiements remplis de bugs, réduisant ainsi l'impact sur les utilisateurs. Prenez le temps de créer une instance de Bitbucket et LaunchDarkly, et de tester les capacités de votre équipe.

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.


Partager cet article

Lectures recommandées

Ajoutez ces ressources à vos favoris pour en savoir plus sur les types d'équipes DevOps, ou pour les mises à jour continues de DevOps chez Atlassian.

Illustration Devops

Communauté DevOps

Illustration Devops

Parcours de formation DevOps

Illustration d'une carte

Essayez la solution gratuitement

Inscrivez-vous à notre newsletter Devops

Thank you for signing up