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가 필요할까요?
기본적으로 쿠버네티스의 배포는 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
•
기본 설치 방법
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로 생성하겠습니다
간단한 프론트 페이지가 포함되어 있으며, 서비스를 통해 접속하면 이미지 태그에 맞는 색을 가진 정사각형 타일들을 볼 수 있습니다. 각 타일은 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 리소스를 이제 배포한 뒤 아래와 같은 변화 과정을 테스트 해보겠습니다.
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
복사
기존 버전은 그대로 유지 중이며, 새로운 ReplicaSet이 생기고 똑같이 2개의 Pod가 생성되는데 이미지의 버전은 Green인 것을 확인할 수 있고, Preview라고 명시된 것을 확인할 수 있습니다.
이미지 변경 전에 preview 서비스로 접속하면 새로운 버전에 대한 확인이 가능합니다.
이 때 서비스가 어떻게 분리되어 호출되는지 확인해보면 다음과 같습니다. preview 서비스 selector의 rollouts-pod-template-hash가 75695867f 으로 변경된 것을 확인할 수 있습니다.
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
복사
kubectl argo rollouts promote <rollout-name>
Bash
복사
이 명령어를 사용하면, preview 였던 replicaset이 stable/active인 것으로 변경되고 기존 버전은 삭제 준비를 하게 됩니다. 아래 그림을 보면 revision 1의 INFO에 delay를 볼 수 있으며, 해당 시간 후 replicaset은 종료 프로세스로 들어갑니다.
기존 버전이 종료되어 30081 / 30082 서비스 모두 녹색으로 변한 것을 볼 수 있습니다.
마치며
기본적으로 쿠버네티스의 라벨과 selector를 사용해서 Blue/Green 배포를 수행할 수 있습니다. 그러나 어쨌든 손으로 수정하는 작업이 들어가고, Deployment를 2벌로 관리하는 점에서 불편하고 실수의 위험이 있습니다.
Argo CD의 Rollouts 플러그인을 사용하면 Blue/Green, Canary 등의 배포전략을 직관적이고 쉽게 적용할 수 있기 때문에 Argo CD를 사용 중이라면 한 번쯤 살펴보시면 좋을 것 같습니다.
참고
Argo CD
Argo CD Rollouts
Github