Close

Utilizzo dei flag delle funzioni LaunchDarkly con Bitbucket Pipelines

Primo piano di Warren Marusiak
Warren Marusiak

Senior Technical Evangelist

La distribuzione di nuovo codice in un ambiente di produzione è rischiosa. I bug possono entrare in produzione anche dopo che il codice, l'integrazione e il sistema sono stati testati in ambienti di test e staging. In passato gli sviluppatori avevano a disposizione due possibilità una volta che un bug entrava nell'ambiente di produzione e si verificavano conseguenze per gli utenti. Potevano eseguire il rollback del codice difettoso o apportare una correzione successiva, ma entrambe le soluzioni richiedevano tempo. Ora gli sviluppatori possono attivare o disattivare una funzione in un ambiente con un semplice clic racchiudendo le relative modifiche al codice in un flag delle funzioni. In questo modo l'impatto del codice difettoso sugli utenti si riduce immediatamente ed è possibile sviluppare una correzione da implementare in sicurezza successivamente. Questo articolo lo dimostra utilizzando Bitbucket Pipelines e i flag delle funzioni LaunchDarkly nell'applicazione demo ImageLabeller.

Una demo del flag delle funzioni di ImageLabeller

ImageLabeller è una piccola applicazione che utilizza l'apprendimento automatico per etichettare le immagini. ImageLabeller è distribuito in cinque ambienti: test, staging, Production-us-west-2, Production-us-east-1 e Production-ca-central-1. Questo articolo dimostra come utilizzare i flag delle funzioni per gestire le modifiche al componente SubmitImage di ImageLabeller. SubmitImage è un AWS Lambda scritto in Go. Utilizzerai LaunchDarkly per gestire i flag delle funzioni, Bitbucket per il controllo del codice sorgente e Bitbucket Pipelines per la funzionalità CI/CD.

Come utilizzare i flag delle funzioni LaunchDarkly con Bitbucket Pipelines

Chiedi al tuo amministratore LaunchDarkly locale di creare un progetto e un ambiente. Nello screenshot qui sotto c'è un progetto, PMMImageLabellerDemo, con cinque ambienti. Gli ambienti di test e staging sono di preproduzione. Prendi nota della chiave SDK per ogni ambiente. Successivamente, le chiavi SDK saranno aggiunte come variabili del repository in Bitbucket.

Nell'esempio visualizzato, Bitbucket Pipelines è distribuito in questi ambienti quando il codice viene trasferito in un branch di funzioni. Production-us-west-2, Production-us-east-1 e Production-ca-central-1 sono ambienti di produzione che corrispondono agli ambienti AWS. La distribuzione di Bitbucket Pipelines in questi ambienti avviene quando si effettua il merge del codice alla mainline, da un branch di funzioni, tramite una pull request.

Screenshot di Bitbucket Pipelines

In LaunchDarkly, crea un flag delle funzioni per il progetto. Seleziona l'ambiente di test e regola le impostazioni del flag delle funzioni. Nello screenshot riportato sotto, il flag delle funzioni è impostato per restituire true come valore predefinito nella regione Test. Se la richiesta è effettuata da un utente specifico, ad esempio AtlassianTestUser@atlassian.com, il flag delle funzioni restituisce false. Ciò significa che un utente denominato specifico, ad esempio un utente di test in una suite di test di sistema, può far eseguire il codice in un determinato modo mentre gli utenti normali nello stesso ambiente fanno eseguire il codice in un modo diverso.

Questo comportamento può essere modificato in base all'ambiente. I flag delle funzioni permettono a uno sviluppatore di distribuire nuovo codice in tutte le regioni, consentendo al tempo stesso l'esecuzione del codice solo in ambienti specifici. in questa demo, il flag è impostato per restituire false nell'ambiente di staging e in tutti e tre gli ambienti di produzione. Il nuovo codice verrà eseguito solo nell'ambiente di test.

Screenshot del targeting degli utenti

Utilizzando le chiavi SDK di LaunchDarkly per ogni ambiente, vai su Bitbucket e aggiungi le variabili del repository a ogni repository che utilizzerà questo flag. Lo screenshot seguente mostra che sono state aggiunte cinque variabili del repository. ld_test_env contiene la chiave SDK di LaunchDarkly per l'ambiente di test. ld_staging_env contiene la chiave SDK di LaunchDarkly per l'ambiente di staging. Queste variabili del repository sono riferimenti successivi nel file bitbucket-pipelines.yml per il repository.

Chiavi SDK

I valori delle chiavi SDK possono essere riferimenti nel file bitbucket-pipeline.yml del repository dopo l'aggiunta delle chiavi SDK come variabili del repository. STACK_PARAMETERS viene aggiunto alla fase di distribuzione di production-ca-central-1 nello snippet seguente. STACK_PARAMETERS invia il valore della chiave SDK corrispondente al file template.yml di AWS CloudFormation come parametro.

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

Aggiungi una sezione Parameters con LaunchDarkLysdkKey di tipo String alla sezione Parameters del file template.yml del repository. Questo parametro riceve il valore del LaunchDarkLysdkKey STACK_PARAMETER impostato nel file bitbucket-pipelines.yml.

Parameters:
  LaunchDarklySDKKey:
    Type: String

Inoltre, aggiorna la risorsa AWS Lambda per la funzione SubmitImage nel file template.yml. Aggiungi LaunchDarklySDKKey come variabile di ambiente.

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 variabile di ambiente LaunchDarklySDKKey sarà visibile nella console AWS Lambda dopo la distribuzione di Bitbucket Pipelines nell'ambiente. Il valore di questa chiave è univoco per l'ambiente. Ad esempio, la variabile di ambiente LaunchDarklySDKKey in Test sarà diversa da quella in Production-us-west-2.

Screenshot delle configurazioni dell'ambiente

SubmitImage è un AWS Lambda scritto in Go. Per utilizzare LaunchDarkly con Go, importa le dipendenze seguenti.

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

Aggiungi una funzione per recuperare il valore del flag delle funzioni da LaunchDarkly in fase di esecuzione.

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

Chiama la funzione con una stringa vuota per ottenere il valore di flag predefinito o con un'e-mail dell'utente per ottenere il valore di destinazione. La configurazione mostrata sopra dovrebbe restituire true per l'utente anonimo e false per l'utente UtenteTestAtlasian@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)

Vai ai log di AWS CloudWatch dopo aver eseguito il codice per verificare che vengano estratti i valori di flag corretti.

Screenshot degli eventi del log
Copia delle regole di targeting

Da Admin settings (Impostazioni amministratore), vai alla sezione API keys (Chiavi API) per ottenere un elenco delle chiavi API per ogni ambiente. Le chiavi API vengono sottoposte a split durante le chiamate API in codice per ottenere la versione corretta di uno split. Questa guida utilizza le chiavi server-side per ogni ambiente.

Impostazioni dell'amministratore

Vai al repository Bitbucket, quindi a Repository settings (Impostazioni repository) e a Repository variables (Variabili repository), e aggiungi le variabili per ogni chiave API.

Variabili del repository nelle impostazioni del repository

Modifica il file bitbucket-pipelines.yml e aggiungi STACK_PARAMETERS al passaggio di distribuzione di AWS SAM. Questa operazione viene eseguita in base all'ambiente. Lo snippet YAML riportato di seguito mostra il passaggio di distribuzione per la regione TEST che si trova in AWS US-WEST-1. Pertanto, il passaggio fa riferimento alla variabile di repository split_test_env configurata sopra. Utilizza la variabile di repository appropriata per ogni ambiente.

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

Modifica il file template.yml di AWS CloudFormation e aggiungi una sezione Parameters (Parametri) che fa riferimento alla chiave SDK Split.

Parameters:
  SplitIOSDKKey:
    Type: String

Nel file template.yml aggiungi una sezione Environment (Ambiente) a ogni risorsa AWS Lambda necessaria per l'accesso a Split. Questa guida dimostra

Environment:
  Variables:
    SplitIOSDKKey:
      Ref: SplitIOSDKKey

Importa le seguenti dipendenze nel file Go che utilizzerà l'SDK di Split.

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

Questa funzione crea un client e recupera il valore del flag delle funzioni per "SubmitImageDemoSplit" creato nell'interfaccia utente di Split. È necessario un solo parametro, che è 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
}

Chiama la funzione con un indirizzo e-mail. In questo caso, someRandomUser@atlassian.com estrarrà il valore predefinito del flag delle funzioni poiché non fa parte di un elenco consentito associato al flag delle funzioni. AtlassianTestUser@atlassian.com estrarrà il valore del flag delle funzioni associato all'elenco di elementi consentiti di cui è membro.

Guarda l'output nei log AWS CloudWatch dopo l'esecuzione del codice. Noterai che il flag delle funzioni si disattiva quando vi si accede da someRandomUser@atlassian.com e si riattiva quando vi si accede da AtlassianTestUser@atlassian.com.

Eventi del log

In conclusione...

I flag delle funzioni di LauchDarkly si integrano facilmente in un'applicazione distribuita tramite Bitbucket Pipelines. Consentono agli sviluppatori di controllare l'esecuzione del codice distribuito, velocizzando in questo modo la risposta alle distribuzioni con bug e riducendo l'impatto sugli utenti. Prenditi il tempo necessario per creare un'istanza di Bitbucket, e di LaunchDarkly, e di testare le funzionalità per il tuo team.

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.


Condividi l'articolo

Letture consigliate

Aggiungi ai preferiti queste risorse per ricevere informazioni sui tipi di team DevOps e aggiornamenti continui su DevOps in Atlassian.

Illustrazione su Devops

Community DevOps

Illustrazione su Devops

Percorso di apprendimento DevOps

Illustrazione di una mappa

Inizia gratis

Iscriviti alla nostra newsletter DevOps

Thank you for signing up