Close

Używanie flag funkcji Launch Darkly w Bitbucket Pipelines

Warren Marusiak — zdjęcie portretowe
Warren Marusiak

Starszy propagator techniczny

Wdrażanie nowego kodu w środowisku produkcyjnym bywa ryzykowne. Błędy mogą trafić do środowiska produkcyjnego pomimo wykonania testów jednostkowych, integracyjnych oraz systemowych kodu w środowiskach testowych i przejściowych. Dotychczas gdy błąd trafił do środowiska produkcyjnego, a użytkownicy zostali poszkodowani, programiści mieli dwa wyjścia. Mogli wycofać błędny kod lub wdrożyć poprawkę, a każde z tych rozwiązań wymagało czasu. Teraz programiści mogą włączać i wyłączać funkcję w środowisku jednym kliknięciem, oznaczając odpowiednie zmiany w kodzie jako flagi funkcji. Pozwala to błyskawicznie wyeliminować wpływ błędnego kodu na użytkowników, dając czas na opracowanie poprawki i bezpieczne ponowne wdrożenie. W tym artykule przedstawiono ten proces z wykorzystaniem Bitbucket Pipelines oraz flag funkcji Launch Darkly w aplikacji demonstracyjnej ImageLabeller.

Demonstracja flag funkcji w aplikacji ImageLabeller

ImageLabeller jest niewielką aplikacją, która wykorzystuje uczenie maszynowe do oznaczania obrazów etykietami. Aplikacja ImageLabeller jest wdrażana w pięciu środowiskach: testowym Test, przejściowym Staging oraz trzech produkcyjnych — Production-us-west-2, Production-us-east-1 i Production-ca-central-1. W tym artykule przedstawiono, jak wykorzystać flagi funkcji do zarządzania zmianami w komponencie SubmitImage aplikacji ImageLabeller. SubmitImage jest funkcją AWS Lambda napisaną w Go. Do zarządzania flagami funkcji zastosujesz aplikację Launch Darkly, do kontroli kodu źródłowego — rozwiązanie Bitbucket, a do obsługi funkcji CI/CD — Bitbucket Pipelines.

Używanie flag funkcji Launch Darkly w Bitbucket Pipelines

Poproś lokalnego administratora Launch Darkly o utworzenie projektu i środowiska. Na poniższym zrzucie ekranu widać projekt PMMImageLabellerDemo z pięcioma środowiskami. Środowisko testowe Test i przejściowe Staging są środowiskami przedprodukcyjnymi. Zanotuj klucz zestawu SDK dla każdego środowiska. Później klucze zestawów SDK zostaną dodane jako zmienne repozytorium w Bitbucket.

W tym przykładzie po zatwierdzeniu kodu do gałęzi funkcji Bitbucket Pipelines dokonuje wdrożenia do tych środowisk. Środowiska produkcyjne Production-us-west-2, Production-us-east-1 i Production-ca-central-1 odpowiadają środowiskom AWS. Bitbucket Pipelines dokonuje wdrożenia w tych środowiskach po scaleniu kodu z gałęzią mainline z poziomu gałęzi funkcji za pośrednictwem pull requestu.

Zrzut ekranu Bitbucket Pipelines

W Launch Darkly utwórz flagę funkcji dla projektu. Wybierz środowisko testowe i dostosuj ustawienia flag funkcji. Na poniższym zrzucie ekranu flaga funkcji została ustawiona tak, aby domyślnie w regionie Test zwracała wartość true. Jeśli konkretny użytkownik, czyli AtlassianTestUser@atlassian.com prześle wniosek, dla flagi funkcji zostanie przywrócona wartość false. W ten sposób konkretny nazwany użytkownik, taki jak użytkownicy testowi w pakiecie testów systemowych, może pobrać kod do wykonania w jeden sposób, podczas gdy zwykli użytkownicy w tym samym środowisku będą mogli pobrać kod do wykonania w inny sposób.

Taki sposób działania można dostosować do każdego środowiska z osobna. Flagi funkcji umożliwiają programistom wdrożenie nowego kodu we wszystkich regionach, ale ograniczenie możliwości jego wykonywania tylko do konkretnych środowisk. W przypadku tej demonstracji wartość flagi jest ustawiona, aby zwracać wartość false w środowisku przejściowym Staging oraz we wszystkich trzech środowiskach produkcyjnych. Nowy kod zostanie wykonany tylko w środowisku testowym.

Zrzut ekranu określania kierowania do określonych odbiorców

Pobierz z Launch Darkly klucze zestawu SDK dla każdego środowiska. Następnie przejdź do Bitbucket i dodaj zmienne repozytorium do każdego repozytorium, które będzie używać tej flagi. Na poniższym zrzucie ekranu widać, że dodano pięć zmiennych repozytorium. ld_test_env zawiera klucz zestawu SDK Launch Darkly dla środowiska testowego. ld_staging_env zawiera klucz zestawu SDK Launch Darkly dla środowiska przejściowego. Następnie w pliku bitbucket-pipelines.yml te zmienne będą używane jako odniesienia do repozytorium.

Klucze zestawu SDK

Wartości kluczy zestawu SDK mogą być odniesieniami w pliku bitbucket-pipelines.yml repozytorium po dodaniu kluczy zestawu SDK jako zmiennych repozytorium. W poniższym fragmencie kodu zmienna STACK_PARAMETERS została dodana do kroku wdrożenia dla środowiska produkcyjnego production-ca-central-1. Zmienna STACK_PARAMETERS wysyła wartość odpowiedniego klucza zestawu SDK do pliku template.yml usługi AWS CloudFormation jako parametr.

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

Dodaj sekcję Parameters z kluczem LaunchDarklySDKKey typu String do sekcji Parameters pliku template.yml repozytorium. Ten parametr przyjmie wartość zmiennej STACK_PARAMETER parametru LaunchDarklySDKKey ustawioną w pliku bitbucket-pipelines.yml.

Parameters:
  LaunchDarklySDKKey:
    Type: String

Zaktualizuj również zasób AWS Lambda dla funkcji SubmitImage w pliku template.yml. Dodaj LaunchDarklySDKKey jako zmienną środowiskową.

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

Zmienna środowiskowa LaunchDarklySDKKey będzie widoczna w konsoli AWS Lambda po dokonaniu przez Bitbucket Pipelines wdrożenia w środowisku. Ta wartość tego klucza jest unikatowa dla środowiska. Przykładowo zmienna środowiskowa LaunchDarklySDKKey w środowisku Test będzie inna niż w środowisku Production-us-west-2.

Zrzut ekranu konfiguracji środowisk

SubmitImage jest funkcją AWS Lambda napisaną w Go. Aby używać Launch Darkly z Go, zaimportuj poniższe zależności.

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

Dodaj funkcję, aby pobrać wartość flagi funkcji z Launch Darkly w czasie wykonywania.

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

Wywołaj funkcję z pustym ciągiem, aby poprać domyślną flagę funkcji lub z adresem e-mail użytkownika aby pobrać wartość dla określonych odbiorców. Powyższa konfiguracja powinna pobrać wartość true dla użytkownika anonimowego i wartość false dla użytkownika 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)

Po uruchomieniu kodu przejdź do dzienników AWS CloudWatch, aby sprawdzić, czy są ściągane prawidłowe wartości flagi.

Zrzut ekranu zdarzeń w dzienniku
Kopiowanie reguł kierowania

Przejdź do sekcji Admin settings (Ustawienia administratora), a następnie do obszaru API keys (Klucze API), aby uzyskać listę kluczy API do każdego środowiska. W trakcie wywołań interfejsu API w kodzie klucze te są wysyłane z powrotem do podziału w celu pobrania jego poprawnej wersji. W tym przewodniku w przypadku każdego środowiska wykorzystano klucze po stronie serwera Server-side.

Ustawienia administratora

Przejdź do repozytorium Bitbucket, a następnie wybierz kolejno Repository settings (Ustawienia repozytorium) i Repository variables (Zmienne repozytorium), aby dodać zmienne dla każdego klucza API.

Zmienne repozytorium w ustawieniach repozytorium

Edytuj plik bitbucket-pipelines.yml i dodaj zmienną STACK_PARAMETERS do kroku wdrożenia AWS SAM. Tę operację trzeba wykonać dla każdego środowiska. Poniższy fragment kodu YAML przedstawia krok wdrożenia dla środowiska TEST znajdującego się w regionie AWS US-WEST-1. W związku z tym krok ten odnosi się do skonfigurowanej wyżej zmiennej repozytorium split_test_env. Dla każdego środowiska należy użyć odpowiedniej zmiennej repozytorium.

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

Edytuj plik template.yml AWS CloudFormation i dodaj sekcję Parameters odwołującą się do klucza zestawu SDK aplikacji Split.

Parameters:
  SplitIOSDKKey:
    Type: String

W pliku template.yml dodaj sekcję Environment do każdego zasobu AWS Lambda, który musi uzyskać dostęp do aplikacji Split. W tym przewodniku pokazano

Environment:
  Variables:
    SplitIOSDKKey:
      Ref: SplitIOSDKKey

Zaimportuj poniższe zależności do pliku Go, który będzie używał zestawu SDK aplikacji Split.

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

Ta funkcja tworzy klienta i pobiera wartość flagi funkcji dla elementu „SubmitImageDemoSplit” utworzonego w interfejsie użytkownika aplikacji Split. Przyjmuje jeden parametr „username” — nazwę użytkownika.

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
}

Wywołaj funkcję, używając adresu e-mail. W tym przypadku someRandomUser@atlassian.com spowoduje pobranie wartości domyślnej flagi funkcji, ponieważ ten adres nie należy do listy dozwolonych powiązanej z flagą funkcji. Adres AtlassianTestUser@atlassian.com spowoduje pobranie wartości flagi funkcji powiązanej z listą dozwolonych, do której należy.

Po wykonaniu kodu przejrzyj wyniki w dziennikach usługi AWS CloudWatch. Zwróć uwagę, że flaga funkcji zostaje ponownie wyłączona przy próbie uzyskania dostępu z adresu someRandomUser@atlassian.com i ponownie włączona, gdy dostęp ma miejsce z adresu AtlassianTestUser@atlassian.com.

Zdarzenia w dzienniku

Wnioski…

Flagi funkcji Launch Darkly można z łatwością zintegrować z aplikacją wdrażaną za pośrednictwem Bitbucket Pipelines. Flagi funkcji umożliwiają programistom kontrolowanie wykonywania wdrażanego kodu. Pozwala to przyspieszyć reagowanie na błędne wdrożenia, ograniczając ich wpływ na użytkowników. Poświęć chwilę na uruchomienie instancji Bitbucket i Launch Darkly oraz przetestowanie możliwości dla Twojego zespołu.

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.


Udostępnij ten artykuł

Zalecane lektury

Dodaj te zasoby do zakładek, aby dowiedzieć się więcej na temat rodzajów zespołów DevOps lub otrzymywać aktualności na temat metodyki DevOps w Atlassian.

Ilustracja DevOps

Społeczność DevOps

Ilustracja DevOps

Ścieżka szkoleniowa DevOps

Ilustracja przedstawiająca mapę

Zacznij korzystać za darmo

Zapisz się do newslettera DevOps

Thank you for signing up