본문 바로가기
WIKI 기술 지식 베이스

블루/그린 배포

원문 보기 위키 갱신

블루/그린 배포 (Blue/Green Deployments)

이 가이드에서는 Flagger와 Kubernetes로 블루/그린(Blue/Green) 배포를 자동화하는 방법을 보여드립니다. 서비스 메시에 배포되지 않는 애플리케이션을 위해 Kubernetes L4 네트워킹으로 블루/그린 방식의 배포를 오케스트레이션하는 과정을 살펴볼게요.

출처: 문서

본문

이 가이드에서는 Flagger와 Kubernetes로 블루/그린 배포를 자동화하는 방법을 보여드립니다.

서비스 메시에 배포되지 않는 애플리케이션의 경우, Flagger는 Kubernetes L4 네트워킹으로 블루/그린 방식의 배포를 오케스트레이션할 수 있습니다. 서비스 메시를 사용할 때는 여기에 지정된 대로 블루/그린을 사용할 수 있습니다.

Flagger Blue/Green Stages

사전 요구사항 (Prerequisites)

Flagger는 Kubernetes 클러스터 v1.16 이상이 필요합니다.

Flagger와 Prometheus 애드온을 설치합니다:

helm repo add flagger https://flagger.app

helm upgrade -i flagger flagger/flagger \
--namespace flagger \
--set prometheus.install=true \
--set meshProvider=kubernetes

클러스터에 이미 실행 중인 Prometheus 인스턴스가 있다면 다음과 같이 Flagger를 ClusterIP 서비스로 지정할 수 있습니다:

helm upgrade -i flagger flagger/flagger \
--namespace flagger \
--set metricsServer=http://prometheus.monitoring:9090

선택적으로 Slack 알림을 활성화할 수 있습니다:

helm upgrade -i flagger flagger/flagger \
--reuse-values \
--namespace flagger \
--set slack.url=https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK \
--set slack.channel=general \
--set slack.user=flagger

부트스트랩 (Bootstrap)

Flagger는 Kubernetes deployment와 선택적으로 horizontal pod autoscaler(HPA)를 받아, 일련의 오브젝트(Kubernetes deployment와 ClusterIP services)를 생성합니다. 이 오브젝트들은 클러스터 내부에서 애플리케이션을 노출하고 카나리아 분석과 블루/그린 승격을 구동합니다.

테스트 네임스페이스를 만듭니다:

kubectl create ns test

deployment와 horizontal pod autoscaler를 만듭니다:

kubectl apply -k https://github.com/fluxcd/flagger//kustomize/podinfo?ref=main

분석 중 트래픽을 생성할 부하 테스트 서비스를 배포합니다:

helm upgrade -i flagger-loadtester flagger/loadtester \
--namespace=test

canary 커스텀 리소스를 만듭니다:

apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: podinfo
  namespace: test
spec:
  provider: kubernetes
  # deployment reference
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: podinfo
  # the maximum time in seconds for the canary deployment
  # to make progress before rollback (default 600s)
  progressDeadlineSeconds: 60
  # HPA reference (optional)
  autoscalerRef:
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    name: podinfo
  service:
    port: 9898
    portDiscovery: true
  analysis:
    # schedule interval (default 60s)
    interval: 30s
    # max number of failed checks before rollback
    threshold: 2
    # number of checks to run before rollback
    iterations: 10
    # Prometheus checks based on 
    # http_request_duration_seconds histogram
    metrics:
      - name: request-success-rate
        # minimum req success rate (non 5xx responses)
        # percentage (0-100)
        thresholdRange:
          min: 99
        interval: 1m
      - name: request-duration
        # maximum req duration P99
        # milliseconds
        thresholdRange:
          max: 500
        interval: 30s
    # acceptance/load testing hooks
    webhooks:
      - name: smoke-test
        type: pre-rollout
        url: http://flagger-loadtester.test/
        timeout: 15s
        metadata:
          type: bash
          cmd: "curl -sd 'anon' http://podinfo-canary.test:9898/token | grep token"
      - name: load-test
        url: http://flagger-loadtester.test/
        timeout: 5s
        metadata:
          type: cmd
          cmd: "hey -z 1m -q 10 -c 2 http://podinfo-canary.test:9898/"

위 구성은 5분 동안 분석을 실행합니다.

위 리소스를 podinfo-canary.yaml로 저장한 뒤 적용합니다:

kubectl apply -f ./podinfo-canary.yaml

몇 초 후 Flagger가 canary 오브젝트를 생성합니다:

# applied 
deployment.apps/podinfo
horizontalpodautoscaler.autoscaling/podinfo
canary.flagger.app/podinfo

# generated 
deployment.apps/podinfo-primary
horizontalpodautoscaler.autoscaling/podinfo-primary
service/podinfo
service/podinfo-canary
service/podinfo-primary

블루/그린 시나리오:

  • 부트스트랩 시 Flagger는 세 개의 ClusterIP 서비스(app-primary, app-canary, app)를 만듭니다

    그리고 블루 버전을 나타내는 app-primary라는 이름의 섀도우(shadow) 배포를 만듭니다

  • 새 버전이 감지되면 Flagger는 그린 버전을 스케일 업하고 합성 테스트를 실행합니다

    (테스트는 그린 버전에 도달하기 위해 app-canary ClusterIP 서비스를 대상으로 해야 합니다)

  • 합성 테스트가 통과하면 Flagger는 부하 테스트를 시작하고 커스텀 Prometheus 쿼리로 검증합니다

  • 부하 테스트 분석이 성공하면 Flagger는 새 버전을 app-primary로 승격하고 그린 버전을 스케일 다운합니다

자동 블루/그린 승격 (Automated Blue/Green promotion)

컨테이너 이미지를 업데이트해 배포를 트리거합니다:

kubectl -n test set image deployment/podinfo \
podinfod=ghcr.io/stefanprodan/podinfo:6.0.1

Flagger는 배포 리비전이 변경되었음을 감지하고 새 롤아웃을 시작합니다:

kubectl -n test describe canary/podinfo

Events:

New revision detected podinfo.test
Waiting for podinfo.test rollout to finish: 0 of 1 updated replicas are available
Pre-rollout check acceptance-test passed
Advance podinfo.test canary iteration 1/10
Advance podinfo.test canary iteration 2/10
Advance podinfo.test canary iteration 3/10
Advance podinfo.test canary iteration 4/10
Advance podinfo.test canary iteration 5/10
Advance podinfo.test canary iteration 6/10
Advance podinfo.test canary iteration 7/10
Advance podinfo.test canary iteration 8/10
Advance podinfo.test canary iteration 9/10
Advance podinfo.test canary iteration 10/10
Copying podinfo.test template spec to podinfo-primary.test
Waiting for podinfo-primary.test rollout to finish: 1 of 2 updated replicas are available
Promotion completed! Scaling down podinfo.test

참고 카나리아 분석 중에 배포에 새 변경 사항을 적용하면 Flagger가 분석을 다시 시작합니다.

모든 canary는 다음과 같이 모니터링할 수 있습니다:

watch kubectl get canaries --all-namespaces

NAMESPACE   NAME      STATUS        WEIGHT   LASTTRANSITIONTIME
test        podinfo   Progressing   100      2019-06-16T14:05:07Z
prod        frontend  Succeeded     0        2019-06-15T16:15:07Z
prod        backend   Failed        0        2019-06-14T17:05:07Z

자동 롤백 (Automated rollback)

분석 중에 HTTP 500 오류와 높은 지연 시간을 생성해 Flagger의 롤백을 테스트할 수 있습니다.

로드 테스터 파드에 exec로 들어갑니다:

kubectl -n test exec -it flagger-loadtester-xx-xx sh

HTTP 500 오류를 생성합니다:

watch curl http://podinfo-canary.test:9898/status/500

지연 시간을 생성합니다:

watch curl http://podinfo-canary.test:9898/delay/1

실패한 검사 횟수가 분석 임계값에 도달하면 그린 버전은 0으로 스케일되고 롤아웃은 실패로 표시됩니다.

kubectl -n test describe canary/podinfo

Status:
  Failed Checks:         2
  Phase:                 Failed
Events:
  Type     Reason  Age   From     Message
  ----     ------  ----  ----     -------
  Normal   Synced  3m    flagger  New revision detected podinfo.test
  Normal   Synced  3m    flagger  Advance podinfo.test canary iteration 1/10
  Normal   Synced  3m    flagger  Advance podinfo.test canary iteration 2/10
  Normal   Synced  3m    flagger  Advance podinfo.test canary iteration 3/10
  Normal   Synced  3m    flagger  Halt podinfo.test advancement success rate 69.17% < 99%
  Normal   Synced  2m    flagger  Halt podinfo.test advancement success rate 61.39% < 99%
  Warning  Synced  2m    flagger  Rolling back podinfo.test failed checks threshold reached 2
  Warning  Synced  1m    flagger  Canary failed! Scaling down podinfo.test

커스텀 메트릭 (Custom metrics)

분석은 Prometheus 쿼리로 확장할 수 있습니다. 데모 앱은 Prometheus로 계측되어 있으므로, HTTP 요청 지속 시간 히스토그램을 사용해 canary(그린 버전)를 검증하는 커스텀 검사를 만들 수 있습니다.

메트릭 템플릿을 만들고 클러스터에 적용합니다:

apiVersion: flagger.app/v1beta1
kind: MetricTemplate
metadata:
  name: not-found-percentage
  namespace: test
spec:
  provider:
    type: prometheus
    address: http://flagger-prometheus.flagger:9090
  query: |
    100 - sum(
        rate(
            http_request_duration_seconds_count{
              kubernetes_namespace="{{ namespace }}",
              kubernetes_pod_name=~"{{ target }}-[0-9a-zA-Z]+(-[0-9a-zA-Z]+)"
              status!="{{ interval }}"
            }[1m]
        )
    )
    /
    sum(
        rate(
            http_request_duration_seconds_count{
              kubernetes_namespace="{{ namespace }}",
              kubernetes_pod_name=~"{{ target }}-[0-9a-zA-Z]+(-[0-9a-zA-Z]+)"
            }[{{ interval }}]
        )
    ) * 100

카나리아 분석을 편집하고 다음 메트릭을 추가합니다:

  analysis:
    metrics:
      - name: "404s percentage"
        templateRef:
          name: not-found-percentage
        thresholdRange:
          max: 5
        interval: 1m

위 구성은 HTTP 404 req/sec 비율이 전체 트래픽의 5% 미만인지 확인해 canary(그린 버전)를 검증합니다. 404 비율이 5% 임계값에 도달하면 롤아웃은 롤백됩니다.

컨테이너 이미지를 업데이트해 배포를 트리거합니다:

kubectl -n test set image deployment/podinfo \
podinfod=ghcr.io/stefanprodan/podinfo:6.0.3

404를 생성합니다:

watch curl http://podinfo-canary.test:9898/status/400

Flagger 로그를 봅니다:

kubectl -n flagger logs deployment/flagger -f | jq .msg

New revision detected podinfo.test
Scaling up podinfo.test
Advance podinfo.test canary iteration 1/10
Halt podinfo.test advancement 404s percentage 6.20 > 5
Halt podinfo.test advancement 404s percentage 6.45 > 5
Rolling back podinfo.test failed checks threshold reached 2
Canary failed! Scaling down podinfo.test

알림이 구성되어 있다면 Flagger는 canary가 실패한 이유와 함께 알림을 보냅니다.

Helm으로 합성 테스트 (Conformance Testing with Helm)

Flagger에는 pre-rollout 웹훅으로 구성할 때 Helm 테스트를 실행할 수 있는 테스트 서비스가 함께 제공됩니다.

tiller 서비스 계정을 사용해 kube-system 네임스페이스에 Helm 테스트 러너를 배포합니다:

helm repo add flagger https://flagger.app

helm upgrade -i flagger-helmtester flagger/loadtester \
--namespace=kube-system \
--set serviceAccountName=tiller

배포되면 Helm 테스터 API는 http://flagger-helmtester.kube-system/에서 사용할 수 있습니다.

차트에 helm 테스트 pre-rollout 훅을 추가합니다:

  analysis:
    webhooks:
      - name: "conformance testing"
        type: pre-rollout
        url: http://flagger-helmtester.kube-system/
        timeout: 3m
        metadata:
          type: "helm"
          cmd: "test {{ .Release.Name }} --cleanup"

카나리아 분석이 시작되면 Flagger는 pre-rollout 웹훅을 호출합니다. helm 테스트가 실패하면 Flagger는 분석 임계값에 도달해 canary가 롤백될 때까지 재시도합니다.

분석 과정을 심층적으로 살펴보려면 사용 문서를 읽어보세요.

더 알아보기 (Learn more)