Close

Bitbucket Pipelines에서 Launch Darkly 기능 플래그 사용

Warren Marusiak 얼굴 사진
Warren Marusiak

선임 기술 에반젤리스트

프로덕션 환경에 새 코드를 배포하는 것은 위험합니다. 코드가 단위 테스트, 통합 테스트, 테스트 및 스테이징 환경에서의 시스템 테스트를 거친 후에도 프로덕션에서 버그가 발생할 수 있습니다. 기존에는 프로덕션에서 버그가 발생하고 사용자가 영향을 받으면 개발자가 두 가지 선택을 할 수 있었습니다. 버그가 있는 코드를 롤백하거나 수정을 배포할 수 있었으며 두 해결책 모두 시간이 걸렸습니다. 이제는 개발자가 관련 코드 변경을 기능 플래그에 래핑하여 버튼을 한 번만 클릭하면 환경에서 기능을 활성화 또는 비활성화할 수 있습니다. 버그가 발생한 코드가 사용자에게 미치는 영향을 즉시 완화할 수 있으며 수정을 개발하고 안전하게 적용할 수 있습니다. 이 문서는 Bitbucket Pipelines 및 ImageLabeller 데모 애플리케이션의 Launch Darkly 기능 플래그를 사용하여 이것을 보여줍니다.

ImageLabeller 기능 플래그 데모

ImageLabeller는 머신러닝을 사용하여 이미지에 레이블을 지정하는 작은 애플리케이션입니다. ImageLabeller는 테스트, 스테이징, Production-us-west-2, Production-us-east-1, Production-ca-central-1이라는 다섯 가지 환경에 배포되었습니다. 이 문서에서는 기능 플래그를 사용하여 ImageLabeller의 SubmitImage 컴포넌트에 대한 변경 사항을 관리하는 방법을 보여줍니다. SubmitImage는 Go로 작성된 AWS Lambda입니다. 기능 플래그 관리에 Launch Darkly를, 소스 제어에 Bitbucket을, CI/CD 기능 관리에 Bitbucket Pipelines를 사용하게 됩니다.

Bitbucket Pipelines에서 Launch Darkly 기능 플래그를 사용하는 방법

로컬 Launch Darkly 관리자가 프로젝트 및 환경을 만들도록 합니다. 아래 스크린샷에는 다섯 가지 환경으로 구성된 PMMImageLabellerDemo라는 프로젝트가 있습니다. 테스트 및 스테이징은 프로덕션 전 환경입니다. 각 환경의 SDK 키를 기록해 두세요. 나중에 SDK 키가 Bitbucket에 리포지토리 변수로 추가될 것입니다.

이 예에서 Bitbucket Pipelines는 코드가 기능 브랜치에 커밋될 때 해당 환경에 배포됩니다. Production-us-west-2, Production-us-east-1, Production-ca-central-1은 AWS 환경에 해당하는 프로덕션 환경입니다. Bitbucket Pipelines는 코드가 기능 브랜치에서 풀리퀘스트를 통해 메인 라인에 병합될 때 해당 환경에 배포됩니다.

Bitbucket Pipelines 스크린샷

Launch Darkly에서 프로젝트의 기능 플래그를 만듭니다. 테스트 환경을 선택하고 기능 플래그 설정을 조정합니다. 아래 스크린샷에서 테스트 리전에서는 기능 플래그가 기본적으로 true를 반환하도록 설정되어 있습니다. [email protected]이라는 특정 사용자가 요청을 하면 기능 플래그가 false를 반환합니다. 이런 방식으로 시스템 테스트 스위트의 테스트 사용자와 같은 특정 기명 사용자는 코드를 어떤 방법으로 실행할 수 있고 같은 환경의 일반 사용자는 코드를 다른 방법으로 실행할 수 있습니다.

이 동작은 환경별로 조정될 수 있습니다. 기능 플래그를 사용하면 개발자가 모든 리전에 새 코드를 배포할 수 있고 코드는 특정 환경에서만 실행되도록 허용합니다. 이 데모의 경우 스테이징과 세 가지 프로덕션 환경 모두에서 플래그가 false를 반환하도록 설정되어 있습니다. 새 코드는 테스트 환경에서만 실행됩니다.

사용자 타겟팅 스크린샷

Launch Darkly에서 각 환경용 SDK 키를 가져가세요. 그런 다음 Bitbucket으로 이동하여 이 플래그를 사용할 각 리포지토리에 리포지토리 변수를 추가합니다. 아래 스크린샷은 리포지토리 변수 다섯 개가 추가된 것을 보여줍니다. ld_test_env에는 테스트 환경을 위한 Launch Darkly SDK 키가 들어 있습니다. ld_staging_env에는 스테이징 환경을 위한 Launch Darkly SDK 키가 들어 있습니다. 리포지토리 변수는 나중에 bitbucket-pipelines.yml 파일에서 리포지토리에 대한 참조로 사용됩니다.

SDK 키

SDK 키가 리포지토리 변수로 추가된 후에 리포지토리의 bitbucket-pipeline.yml 파일에서 SDK 키 값을 참조할 수 있습니다. STACK_PARAMETERS가 아래 스니펫에서 production-ca-central-1의 배포 단계에 추가됩니다. STACK_PARAMETERS는 해당하는 SDK 키 값을 AWS CloudFormation 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}"
    }]'

리포지토리의 template.yml 파일의 매개 변수 섹션에 문자열 유형의 LaunchDarklySDKKey를 사용하여 매개 변수 섹션을 추가합니다. 이 매개 변수는 bitbucket-pipelines.yml 파일에 설정된 LaunchDarklySDKKey STACK_PARAMETER의 값을 받습니다.

Parameters:
  LaunchDarklySDKKey:
    Type: String

template.yml 파일에 있는 SubmitImage 함수의 AWS Lambda 리소스도 업데이트합니다. LaunchDarklySDKKey를 환경 변수로 추가합니다.

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

LaunchDarklySDKKey 환경 변수는 Bitbucket Pipelines가 환경에 배포되고 나면 AWS Lambda 콘솔에 보일 것입니다. 이 키의 값은 환경에 고유합니다. 예를 들어 테스트의 LaunchDarklySDKKey 환경 변수는 Production-us-west-2의 환경 변수와 다릅니다.

환경 구성 스크린샷

SubmitImage는 Go로 작성된 AWS Lambda입니다. Go와 함께 Launch Darkly를 사용하려면 다음 종속성을 가져와야 합니다.

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

런타임에 Launch Darkly에서 기능 플래그 값을 가져오는 함수를 추가합니다.

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

기본 플래그 값을 가져오려면 빈 문자열로 함수를 호출하고 대상 값을 가져오려면 사용자 이메일로 함수를 호출합니다. 위에 표시된 설정은 익명 사용자에 대해 true, [email protected] 사용자애 대해 false를 가져와야 합니다.

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

  flagVal, flagErr  = getLaunchDarklyFlags("[email protected]")
  if flagErr != nil {
    return "", flagErr
  }
  fmt.Println("DEMO flagVal for [email protected]: ", flagVal)

코드를 실행한 후 AWS CloudWatch 로그로 이동하여 올바른 플래그 값을 가져오는지 확인합니다.

이벤트 로그 스크린샷
대상 규칙 복사 중

관리자 설정으로 이동한 후 API 키로 이동하여 각 환경의 API 키 목록을 받습니다. API 키는 올바른 버전의 Split을 가져오기 위해 코드에서 API 호출 중에 Split으로 다시 전송됩니다. 이 가이드에서는 각 환경에 서버 측 키를 사용합니다.

관리자 설정

Bitbucket 리포지토리로 이동한 다음 리포지토리 설정, 리포지토리 변수로 이동하여 각 API 키에 변수를 추가합니다.

리포지토리 설정의 리포지토리 변수

bitbucket-pipelines.yml 파일을 편집하고 AWS SAM 배포 단계에 STACK_PARAMETERS를 추가합니다. 이 작업은 환경별로 수행됩니다. 아래의 YAML 스니펫은 AWS US-WEST-1 테스트 리전의 배포 단계를 보여줍니다. 따라서 이 단계는 위의 split_test_env 리포지토리 변수 설정을 참조합니다. 각 환경에 적합한 리포지토리 변수를 사용하세요.

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

AWS CloudFormation template.yml 파일을 편집하고 Split SDK 키를 참조하는 매개 변수 섹션을 추가합니다.

Parameters:
  SplitIOSDKKey:
    Type: String

template.yml 파일에서 Split에 액세스하는 데 필요한 각 AWS Lambda 리소스에 환경 섹션을 추가합니다. 이 가이드는 다음을 보여줍니다

Environment:
  Variables:
    SplitIOSDKKey:
      Ref: SplitIOSDKKey

Split SDK를 사용할 Go 파일에 다음 종속성을 가져옵니다.

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

이 함수는 클라이언트를 만들고 Split UI에서 만들어진 “SubmitImageDemoSplit”의 기능 플래그 값을 검색합니다. 사용자 이름이라는 단일 매개 변수가 있어야 합니다.

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
}

이메일 주소로 함수를 호출합니다. 이 경우 [email protected]은 기능 플래그와 연결된 허용 목록의 구성원이 아니므로 기능 플래그의 기본값을 가져옵니다. [email protected]은 자신이 속한 허용 목록에 연결된 기능 플래그의 값을 가져옵니다.

코드가 실행된 후에 AWS CloudWatch 로그의 출력을 살펴보세요. [email protected]이 액세스할 때 기능 플래그가 비활성화되고 [email protected]이 액세스할 때 기능 플래그가 다시 활성화되는 것을 살펴보세요.

이벤트 로그

결론...

Launch Darkly 기능 플래그는 Bitbucket Pipelines를 통해 배포된 애플리케이션에 쉽게 통합됩니다. 개발자는 기능 플래그를 사용하여 배포된 코드의 실행을 제어할 수 있습니다. 이렇게 하면 버그가 있는 배포에 더 빠르게 대응하고 사용자에게 미치는 영향을 줄일 수 있습니다. 시간을 내어 Bitbucket 및 Launch Darkly 인스턴스를 시작하고 팀의 역량을 테스트해 보세요.

Warren Marusiak
Warren Marusiak

개발자 출신인 Warren은 2021년 기술 에반젤리스트로 Atlassian에 합류했습니다. 메인프레임에서 실행되는 COBOL 통신 소프트웨어부터 AWS의 최신 클라우드 인프라에 이르기까지 모든 분야에서 활약했습니다. 기술에 대한 관심이 지대하며 머신러닝 분야를 연구한 경력이 있습니다. 기술 에반젤리스트로서 Warren은 데모, 글쓰기 및 동영상을 통해 Atlassian 제품 및 파트너 통합 기능에 대한 인지도를 높이고 있습니다. 또한 Developer’s Edge 동영상 시리즈도 큐레이션합니다. 여가 시간에는 브라질 주짓수를 열정적으로 연습합니다.


이 문서 공유

여러분께 도움을 드릴 자료를 추천합니다.

이러한 리소스에 책갈피를 지정하여 DevOps 팀의 유형에 대해 알아보거나 Atlassian에서 DevOps에 대한 지속적인 업데이트를 확인하세요.

DevOps 일러스트레이션

DevOps 커뮤니티

DevOps 일러스트레이션

DevOps 학습 경로

맵 일러스트레이션

무료로 사용해보기

DevOps 뉴스레터 신청

Thank you for signing up

OSZAR »