Search

Argo Rollouts를 이용한 Blue/Green 배포 (1)

Blue/Green 배포

Blue/Green 배포는 무중단 배포의 한 가지 방법입니다.  한 줄로 요약하자면, 두 개의 개별적이지만 동일한 환경을 만드는 배포 전략으로 볼 수 있습니다.
조금 더 자세히는, Blue를 구버전, Green을 새로운 버전으로 가정한다면, 운영 환경에 기존 버전인 Blue와 동일하게 새로운 Green 버전의 인스턴스를 구성하고, 테스트를 완료 후 라이브 트래픽을 로드밸런서를 통해 새로운 버전으로 전환하는 형태의 배포 방식입니다.
새로운 버전을 구버전과 동일한 운영 환경으로 인스턴스를 구성하기 때문에 실제 운영 환경에서 새로운 버전을 테스트 후 버전을 바꿀 수 있는 장점이 있고 트래픽을 다시 구버전으로 돌릴 수 있으므로 빠른 롤백이 가능합니다.
기본적으로 Blue/Green 배포를 위해서는 시스템 자원이 두 배로 필요로하기 때문에 비용등의 단점이 있을 수 있습니다.
쿠버네티스 운영환경을 사용 중이라면, 특별히 Argo CD를 사용하지 않더라도 Blue/Green 배포 전략을 사용할 수 있긴 합니다.
Deployment를 똑같이 2개를 만들되, 각각 Blue, Green으로 라벨링하고, 그 후에 Service에서 Selector를 원하는 시점에 Blue/Green으로 변경하여 트래픽을 전환하는 방법으로 가능합니다.
그러나 이 방법에는 수작업이 들어가기 때문에 실수의 위험성이 존재하기 마련입니다.
그러면, Argo CD로 실수 없이 Blue/Green 배포를 하는 법을 알아보겠습니다.

Argo CD로 Blue/Green 배포

먼저 Argo CD에 Argo Rollouts 라는 새로운 플러그인을 추가해야합니다.
Argo Rollouts

Argo Rollouts?

Argo Rollouts는 Blue/Green, Canary 등과 같은 Progressive Delivery 기능을 쿠버네티스에 제공하는 CRD 입니다.
그렇다면 왜 Argo Rollouts가 필요할까요?
기본적으로 쿠버네티스의 배포는 RollingUpdate 전략을 사용하며, Readiness probe등을 활용하여 배포의 안정성을 확보하게 됩니다.
그러나 롤링 업데이트 전략에는 아래와 같은 문제 사항들을 안고 있습니다.
롤아웃 속도에 대한 제어가 쉽지 않음
새로운 버전으로 트래픽 흐름을 제어할 수 없음
Readiness probe는 단순한 용도에만 유용함
업데이트를 확인하기 위해 외부 메트릭을 쿼리할 수 없음
업데이트 진행을 중단할 수 있지만, 업데이트를 자동으로 중단하고 롤백하는 등의 심화된 기능 부재
RollingUpdate는 쿠버네티스 환경에서 유용한 전략이지만, Application의 규모가 커지기 시작하면 그 이야기가 매우 달라지게 됩니다.
RollingUpdate는 1)blast radius(문제 발생시 그로 인한 영향 범위)에 대한 제어가 없고, 2)공격적으로 롤아웃할 수 있으며, 3)실패 시 자동 롤백을 제공하지 않기 때문에 쿠버네티스 환경의 업데이트에서는 너무 위험한 것으로 간주됩니다.
그렇다면, 이를 보완할 수 있다는 Argo Rollouts의 주요기능은 어떻게 될까요?
Blue/Green update strategy
Canary update strategy
트래픽 이동
자동 롤백 및 promotion
수동 판단
여러가지 인그레스 컨트롤러와 서비스 메시, 그리고 메트릭과 통합 가능

Architecture

Argo Rollouts의 전반적인 아키텍처는 아래를 참고하시면 될 것 같습니다.

Install Argo Rollouts

설치에는 2가지 방법이 있습니다. (https://argoproj.github.io/argo-rollouts/installation/)
기본 설치 방법
kubectl create namespace argo-rollouts kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
Bash
복사
특정 namespace의 권한 내에서 설치
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/namespace-install.yaml # 이 경우 Argo Rollouts CRD가 포함되어 있지 않으므로 별도로 설치해야한다. kubectl apply -k https://github.com/argoproj/argo-rollouts/manifests/crds\?ref\=stable
Bash
복사
kubectl에 plugin 설치 (Intel Mac 기준)
curl -LO https://github.com/argoproj/argo-rollouts/releases/latest/download/kubectl-argo-rollouts-darwin-amd64 chmod +x ./kubectl-argo-rollouts-darwin-amd64 sudo mv ./kubectl-argo-rollouts-darwin-amd64 /usr/local/bin/kubectl-argo-rollouts kubectl argo rollouts version >> kubectl-argo-rollouts: v1.4.0+e40c9fe BuildDate: 2023-01-09T20:26:12Z GitCommit: e40c9fe8a2f7fee9d8ee1c56b4c6c7b983fce135 GitTreeState: clean GoVersion: go1.19.4 Compiler: gc Platform: darwin/amd64
Bash
복사

Argo CD로 Blue/Green 배포 맛보기

Argo CD로 Blue/Green 배포를 하려면 위에서 설치한 Rollout Custom Resource를 사용하게 됩니다.
strategy: 하위에 배포 전략을 선택하며 여기서는 blueGreen을 명시
blueGreen
activeService: 현재 운영 중인 application에 연결될 서비스
previewService: 변경될 application에 연결될 서비스
active/preview 2개의 서비스를 명시하기 때문에 서비스를 2개 생성해주어야합니다. 이 테스트에서는 NodePort 30081 을 active로, NodePort 30082를 preview로 생성하겠습니다
또한 테스트에 사용된 Image는 Argo project에서 제공하는 데모용 이미지입니다.(https://github.com/argoproj/rollouts-demo)
간단한 프론트 페이지가 포함되어 있으며, 서비스를 통해 접속하면 이미지 태그에 맞는 색을 가진 정사각형 타일들을 볼 수 있습니다. 각 타일은 backend 호출시 이미지의 색상으로 응답하는 형태로 보시면 됩니다.
apiVersion: argoproj.io/v1alpha1 kind: Rollout metadata: name: rollout-bluegreen spec: replicas: 2 revisionHistoryLimit: 2 selector: matchLabels: app: rollout-bluegreen template: metadata: labels: app: rollout-bluegreen spec: containers: - name: rollouts-demo image: argoproj/rollouts-demo:blue imagePullPolicy: Always ports: - containerPort: 8080 strategy: blueGreen: activeService: rollout-bluegreen-active previewService: rollout-bluegreen-preview autoPromotionEnabled: false --- kind: Service apiVersion: v1 metadata: name: rollout-bluegreen-active spec: type: NodePort selector: app: rollout-bluegreen ports: - protocol: TCP port: 80 targetPort: 8080 nodePort: 30081 --- kind: Service apiVersion: v1 metadata: name: rollout-bluegreen-preview spec: type: NodePort selector: app: rollout-bluegreen ports: - protocol: TCP port: 80 targetPort: 8080 nodePort: 30082
YAML
복사
위 Rollout 리소스를 이제 배포한 뒤 아래와 같은 변화 과정을 테스트 해보겠습니다.
 초기 배포 상태로, 2개의 Blue 버전 Pod로 구성된 ReplicaSet이 생성되며 이는 Argo Rollouts Controller가 관리합니다. 아래 명령어를 사용하면, 현재 rollout의 상태를 볼 수 있다. stable, active 버전이 Blue이며 갯수 등의 정보를 확인할 수 있습니다. 현재는 30081, 30082 모두 접속해도 파란색 타일이 확인되며 active/preview 모두 blue 버전임을 알 수 있습니다.
kubectl argo rollouts get rollout <rollout-name> --watch
Bash
복사
아래 2개 서비스를 비교해보면, selector의 rollouts-pod-template-hash가 5ffd47b8d4 로 동일한 것을 알 수 있습니다.
또한 5ffd47b8d4 는 현재 배포된 버전의 replicaset 리소스 이름의 뒷부분과 일치한다. 2개의 서비스 모두 동일한 replicaset과 연결되고 있음을 알 수 있습니다.
stable/active service
apiVersion: v1 kind: Service metadata: annotations: argo-rollouts.argoproj.io/managed-by-rollouts: rollout-bluegreen creationTimestamp: '2023-02-28T05:19:36Z' labels: argocd.argoproj.io/instance: blue-green name: rollout-bluegreen-active namespace: default resourceVersion: '59528871' uid: 9385a439-7fd1-412d-afa2-df5f284e556b spec: clusterIP: 10.103.66.44 clusterIPs: - 10.103.66.44 externalTrafficPolicy: Cluster internalTrafficPolicy: Cluster ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - nodePort: 30081 port: 80 protocol: TCP targetPort: 8080 selector: app: rollout-bluegreen rollouts-pod-template-hash: 5ffd47b8d4 sessionAffinity: None type: NodePort status: loadBalancer: {}
YAML
복사
preview service
apiVersion: v1 kind: Service metadata: annotations: argo-rollouts.argoproj.io/managed-by-rollouts: rollout-bluegreen creationTimestamp: '2023-02-28T05:19:36Z' labels: argocd.argoproj.io/instance: blue-green name: rollout-bluegreen-preview namespace: default resourceVersion: '59528799' uid: a9053289-1051-46c2-8d2a-055052521ec9 spec: clusterIP: 10.96.197.36 clusterIPs: - 10.96.197.36 externalTrafficPolicy: Cluster internalTrafficPolicy: Cluster ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - nodePort: 30082 port: 80 protocol: TCP targetPort: 8080 selector: app: rollout-bluegreen rollouts-pod-template-hash: 5ffd47b8d4 sessionAffinity: None type: NodePort status: loadBalancer: {}
YAML
복사
Rollout의 이미지 버전을 Blue → Green 으로 변경하여 배포한 직후 상태입니다.
기존 버전은 그대로 유지 중이며, 새로운 ReplicaSet이 생기고 똑같이 2개의 Pod가 생성되는데 이미지의 버전은 Green인 것을 확인할 수 있고, Preview라고 명시된 것을 확인할 수 있습니다.
Green 버전 배포 후, 잠시 뒤부터 30082 서비스는 타일이 녹색으로 변경됩니다. 30082 서비스는 preview 서비스로 위에서 새로 생성된 Green 버전의 replicaset과 연결됩니다.
이미지 변경 전에 preview 서비스로 접속하면 새로운 버전에 대한 확인이 가능합니다.
이 때 서비스가 어떻게 분리되어 호출되는지 확인해보면 다음과 같습니다. preview 서비스 selector의 rollouts-pod-template-hash75695867f 으로 변경된 것을 확인할 수 있습니다.
stable/active service
apiVersion: v1 kind: Service metadata: annotations: argo-rollouts.argoproj.io/managed-by-rollouts: rollout-bluegreen creationTimestamp: '2023-02-28T05:19:36Z' labels: argocd.argoproj.io/instance: blue-green name: rollout-bluegreen-active namespace: default resourceVersion: '59528871' uid: 9385a439-7fd1-412d-afa2-df5f284e556b spec: clusterIP: 10.103.66.44 clusterIPs: - 10.103.66.44 externalTrafficPolicy: Cluster internalTrafficPolicy: Cluster ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - nodePort: 30081 port: 80 protocol: TCP targetPort: 8080 selector: app: rollout-bluegreen rollouts-pod-template-hash: 5ffd47b8d4 sessionAffinity: None type: NodePort status: loadBalancer: {}
YAML
복사
preview service
apiVersion: v1 kind: Service metadata: annotations: argo-rollouts.argoproj.io/managed-by-rollouts: rollout-bluegreen creationTimestamp: '2023-02-28T05:19:36Z' labels: argocd.argoproj.io/instance: blue-green name: rollout-bluegreen-preview namespace: default resourceVersion: '59531012' uid: a9053289-1051-46c2-8d2a-055052521ec9 spec: clusterIP: 10.96.197.36 clusterIPs: - 10.96.197.36 externalTrafficPolicy: Cluster internalTrafficPolicy: Cluster ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - nodePort: 30082 port: 80 protocol: TCP targetPort: 8080 selector: app: rollout-bluegreen rollouts-pod-template-hash: 75695867f sessionAffinity: None type: NodePort status: loadBalancer: {}
YAML
복사
Green 버전 테스트가 끝났다고 가정하고, Green 버전으로 옮기는 과정을 진행할 때 다음과 같은 명령어를 사용합니다.
kubectl argo rollouts promote <rollout-name>
Bash
복사
이 명령어를 사용하면, preview 였던 replicaset이 stable/active인 것으로 변경되고 기존 버전은 삭제 준비를 하게 됩니다. 아래 그림을 보면 revision 1의 INFO에 delay를 볼 수 있으며, 해당 시간 후 replicaset은 종료 프로세스로 들어갑니다.
기존 버전인 revision 1의 Pod Status가 Terminating으로 변경된 것을 확인할 수 있습니다.
기존 버전이 종료되어 30081 / 30082 서비스 모두 녹색으로 변한 것을 볼 수 있습니다.
기존 버전이 완전히 종료되고, 성공적으로 Green 버전으로 배포된 것을 확인할 수 있습니다.

마치며

기본적으로 쿠버네티스의 라벨과 selector를 사용해서 Blue/Green 배포를 수행할 수 있습니다. 그러나 어쨌든 손으로 수정하는 작업이 들어가고, Deployment를 2벌로 관리하는 점에서 불편하고 실수의 위험이 있습니다.
Argo CD의 Rollouts 플러그인을 사용하면 Blue/Green, Canary 등의 배포전략을 직관적이고 쉽게 적용할 수 있기 때문에 Argo CD를 사용 중이라면 한 번쯤 살펴보시면 좋을 것 같습니다.

참고

Argo CD
Argo CD Rollouts
Github