Close

Como usar sinalizadores de funcionalidade do Launch Darkly com o Bitbucket Pipelines

Foto de rosto de Warren Marusiak
Warren Marusiak

Evangelista tecnológico sênior

Implementar um novo código em um ambiente de produção é arriscado. Os bugs podem entrar na produção mesmo após o código ser testado por unidade, testado na integração e testado pelo sistema em ambientes de teste e staging. Em geral, os desenvolvedores têm duas opções quando um bug chega à produção e os usuários são afetados. Eles podem fazer rollback do código do bug ou executar um avanço de correção; ambas as soluções levam tempo. Agora, os desenvolvedores podem ativar ou desativar uma funcionalidade em um ambiente com o clique de um botão, agrupando as alterações de código relacionadas em um sinalizador de funcionalidade. O impacto do código com bug nos usuários pode ser mitigado de imediato e uma correção pode ser desenvolvida e implementada com segurança. Este artigo demonstra isso usando o Bitbucket Pipelines e os sinalizadores de funcionalidade do Launch Darkly no aplicativo de demonstração ImageLabeller.

Uma demonstração do sinalizador de funcionalidade do ImageLabeller

O ImageLabeller é um pequeno aplicativo que usa aprendizado de máquina para rotular imagens. O ImageLabeller é implementado em cinco ambientes: teste, staging, Production-us-west-2, Production-us-east-1 e Production-ca-central-1. Este artigo demonstra como usar sinalizadores de funcionalidade para gerenciar alterações no componente SubmitImage do ImageLabeller. O SubmitImage é um AWS Lambda escrito em Go. Você vai usar o Launch Darkly para gerenciar sinalizadores de funcionalidade, o Bitbucket para fazer controle de origem e o Bitbucket Pipelines para a funcionalidade de IC/CD (integração/implementação contínuas).

Como usar sinalizadores de funcionalidade do Launch Darkly com Bitbucket Pipelines

Faça com que seu administrador local do Launch Darkly crie um projeto e ambiente. Na captura de tela abaixo há um projeto, PMMImageLabellerDemo, com cinco ambientes. Teste e Staging são ambientes de pré-produção. Anote a chave do SDK para cada ambiente. Depois, as chaves do SDK vão ser adicionadas como variáveis de repositório no Bitbucket.

Neste exemplo, o Bitbucket Pipelines faz a implementação nesses ambientes quando é feito o commit do código em uma ramificação de recursos. Production-us-west-2, Production-us-east-1 e Production-ca-central-1 são ambientes de produção que correspondem aos ambientes da AWS. O Bitbucket Pipelines faz a implementação nesses ambientes quando o código é mesclado à linha principal, a partir de uma ramificação de funcionalidades, por meio da solicitação pull.

Captura de tela do Bitbucket Pipelines

No Launch Darkly, crie um sinalizador de funcionalidade para o projeto. Selecione o ambiente de teste e ajuste as configurações do sinalizador de funcionalidade. Na captura de tela abaixo, o sinalizador de funcionalidade está configurado para retornar verdadeiro por padrão na região de teste. Se um usuário específico, AtlassianTestUser@atlassian.com, estiver fazendo a solicitação, o sinalizador de funcionalidade vai retornar falso. Dessa forma, o usuário específico nomeado, como usuários de teste em um pacote de teste do sistema, pode fazer com que o código seja executado de uma maneira, enquanto usuários normais no mesmo ambiente fazem com que o código seja executado de maneira diferente.

Esse comportamento pode ser ajustado por ambiente. Os sinalizadores de funcionalidade permitem que um desenvolvedor implemente um novo código em todas as regiões, permitindo que o código seja executado apenas em ambientes específicos. No caso dessa demonstração, o sinalizador está configurado para retornar falso no Staging e em todos os três ambientes de produção. O novo código só vai ser executado no ambiente de teste.

Captura de tela de segmentação de usuários

Pegue as chaves do SDK para cada ambiente do Launch Darkly. Em seguida, acesse o Bitbucket e adicione variáveis de repositório a cada repositório que vai usar esse sinalizador. A captura de tela abaixo mostra que cinco variáveis de repositório foram adicionadas. ld_test_env contém a chave do SDK do Launch Darkly para o ambiente de teste. ld_staging_env contém a chave do SDK do Launch Darkly para o ambiente de Staging. Essas variáveis de repositório são referências posteriores no arquivo bitbucket-pipelines.yml do repositório.

Chaves do SDK

Os valores das chaves do SDK podem ser referências no arquivo bitbucket-pipeline.yml do repositório depois que as chaves do SDK forem adicionadas como variáveis do repositório. STACK_PARAMETERS é adicionado à etapa de implementação do production-ca-central-1 no trecho abaixo. STACK_PARAMETERS envia o valor da chave SDK correspondente para o arquivo template.yml do AWS CloudFormation como um parâmetro.

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

Adicione uma seção Parâmetros com LaunchDarklySDKKey do tipo String à seção Parâmetros do arquivo template.yml do repositório. Esse parâmetro recebe o valor do LaunchDarklySDKKey STACK_PARAMETER definido no arquivo bitbucket-pipelines.yml.

Parameters:
  LaunchDarklySDKKey:
    Type: String

Atualize também o recurso do AWS Lambda para a função SubmitImage no arquivo template.yml. Adicione LaunchDarklySDKKey como uma variável de 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

A variável de ambiente LaunchDarklySDKKey vai ficar visível no console do AWS Lambda após a implementação dos pipelines do Bitbucket no ambiente. O valor dessa chave é exclusivo para o ambiente. Por exemplo, a variável de ambiente LaunchDarklySDKKey em Teste vai ser diferente da variável Production-us-west-2.

Captura de tela de configurações do ambiente

O SubmitImage é um AWS Lambda escrito em Go. Para usar o Launch Darkly com Go, importe as seguintes dependências.

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

Adicione uma função para recuperar o valor do sinalizador de funcionalidade do Launch Darkly no tempo de execução.

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

Chame a função com uma string vazia para obter o valor padrão do sinalizador ou com um e-mail do usuário para obter o valor que quer. A configuração mostrada acima deve ser verdadeira para o usuário anônimo e falsa para o usuário 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)

Acesse os logs do AWS CloudWatch depois de executar o código para verificar se os valores corretos do sinalizador foram extraídos.

Captura de tela de eventos de registro
Como copiar as regras de destino

Acesse Configurações do administrador e, em seguida, chaves de API para obter uma lista das chaves de API para cada ambiente. Essas chaves de API são enviadas de volta para divisão durante chamadas de API em código para obter a versão correta de uma divisão. Este guia usa as chaves do lado do Server para cada ambiente.

Configurações do administrador

Vá para o repositório do Bitbucket, depois para Configurações do repositório, depois para Variáveis do repositório e adicione variáveis para cada chave de API.

Variáveis do repositório nas configurações do repositório

Edite o arquivo bitbucket-pipelines.yml e adicione STACK_PARAMETERS à etapa de implementação do AWS SAM. Isso é feito por ambiente. O trecho YAML abaixo mostra a etapa de implementação para a região TEST que está no AWS US-WEST-1. Portanto, a etapa faz referência à configuração da variável de repositório split_test_env acima. Use a variável de repositório apropriada para cada 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}"
    }]'

Edite o arquivo template.yml do AWS CloudFormation e adicione uma seção de parâmetros fazendo referência à chave Split SDK.

Parameters:
  SplitIOSDKKey:
    Type: String

No arquivo template.yml, adicione uma seção Ambiente a cada recurso do AWS Lambda que precisa acessar o Split. Este guia demonstra

Environment:
  Variables:
    SplitIOSDKKey:
      Ref: SplitIOSDKKey

Importe as seguintes dependências para o arquivo Go que vai usar o SDK Split.

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

Essa função cria um cliente e recupera o valor do sinalizador de funcionalidade para o “SubmitImageDemoSplit” criado na interface do usuário do Split. É necessário um único parâmetro: nome de usuário.

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
}

Chame a função com um endereço de e-mail. Nesse caso, someRandomUser@atlassian.com vai extrair o valor padrão do sinalizador de funcionalidade, pois ele não é membro de uma lista de permissões associada ao sinalizador de funcionalidade. AtlassianTestUser@atlassian.com vai extrair o valor do sinalizador de funcionalidade associado à lista de permissões da qual é membro.

Veja a saída nos logs do AWS CloudWatch após a execução do código. Observe que o sinalizador de funcionalidade retorna desativado quando é acessado por someRandomUser@atlassian.com, e o sinalizador de funcionalidade retorna ativado quando acessado por AtlassianTestUser@atlassian.com.

Eventos de registro

Conclusão…

Os sinalizadores de funcionalidade do Launch Darkly se integram fácil a um aplicativo implementado por meio do Bitbucket Pipelines. Os sinalizadores de funcionalidade permitem que os desenvolvedores controlem a execução do código implementado. Isso pode agilizar a resposta a implementações com bugs, reduzindo os impactos sobre os usuários. Reserve um tempo para criar uma instância do Bitbucket e do Launch Darkly e testar os recursos para sua equipe.

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.


Compartilhe este artigo

Leitura recomendada

Marque esses recursos para aprender sobre os tipos de equipes de DevOps ou para obter atualizações contínuas sobre DevOps na Atlassian.

Ilustração do DevOps

Comunidade de DevOps

Ilustração do DevOps

Caminho de aprendizagem de DevOps

Ilustração do mapa

Comece gratuitamente

Inscreva-se para receber a newsletter de DevOps

Thank you for signing up