DevOps
EKS Blue/Green 배포 2부
Jensen여기어때
2023년 9월 25일
원문에서 보기 ↗안녕하세요. 여기어때컴퍼니 인프라개발팀에서 EKS(Elastic Kubernetes Service, AWS의 관리형 Kubernetes 서비스)를 담당하고 있는 젠슨 입니다. 1부에 이어서 이번에는 실제로 Blue/Green을 적용하는 방법에 대해서 알아보도록 하겠습니다.
앞서 설명 드린 것과 같이 EKS에서는 기본 배포전략으로 Blue/Green이 제공되지 않으며 ArgoCD를 통해 구성하는 것을 추천 드립니다. 1부에서도 안내해 드렸지만, 그 이유를 간단하게 설명 드리겠습니다. Blue/Green을 사용하기 위해서는 Version 1.0의 POD가 서비스를 제공하고 있을 때 내부에서 Version 2.0의 POD가 별도로 생성되어야 합니다. 이렇게 별도로 생성된 Version 2.0의 POD는 Version 1.0과 POD Name이 구분되어야 하며 POD가 정상적으로 Ready 1/1 상태가 되었는지 체크를 해야합니다. 모든 상태 체크가 완료되면 Version 1.0과 교체하는 작업이 이루어져야 합니다.
지금 설명해 드린 내용이 EKS에서 Blue/Green으로 배포가 되는 절차입니다. 만약 이러한 절차를 직접 구성해야 한다면 상당히 피곤할 것입니다. 다행히도 ArgoCD에서는 Rollouts 기능을 활용하여 이 모든 구성을 자동으로 수행할 수 있습니다. 그럼 이제부터 Rollouts의 설치부터 구성까지 알아보도록 하겠습니다.
1. ArgoCD Rollouts 설치
Rollouts 설치는 간단합니다. Rollouts가 동작할 별도의 Namespace를 생성 후 ArgoCD에서 제공하는 ArgoCD Rollouts 용 install yaml을 배포하기만 하면 됩니다.
# Namespace 생성
kubectl create namespace argo-rollouts
# Rollouts 다운로드
wget https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
# Rollouts 배포
kubectl apply -f install.yaml -n argo-rollouts
# 배포 확인
kubectl get pod -n argo-rollouts
NAME READY STATUS RESTARTS AGE
argo-rollouts-99554cf4-bt9vz 1/1 Running 0 30s
아래 링크에서 조금 더 자세한 내용을 확인하실 수 있습니다.
https://argoproj.github.io/argo-rollouts/
2. Sample Test
설치가 완료되면 정상적으로 동작하는지 확인해 볼 수 있습니다. 친절하게도 ArgoCD에서 Test를 위한 Image도 제공합니다.
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
#image: argoproj/rollouts-demo:green
imagePullPolicy: Always
ports:
- containerPort: 8080
strategy:
blueGreen:
#activeService는 현재 운영중인 Blue 서비스
activeService: rollout-bluegreen-active
#previewService는 새롭게 배포될 Green 서비스
previewService: rollout-bluegreen-preview
#autoPromotioEnabled 옵션은 Blue/Green 배포를 자동으로 진행할 것인지 여부. false 옵션을 사용해 수동으로 지정
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
---
kind: Service
apiVersion: v1
metadata:
name: rollout-bluegreen-preview
spec:
type: NodePort
selector:
app: rollout-bluegreen
ports:
- protocol: TCP
port: 80
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: default
name: rollouts-test-active-ingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/group.name: rollouts-test
alb.ingress.kubernetes.io/scheme: internal
alb.ingress.kubernetes.io/security-groups: <<<sg id>>>
alb.ingress.kubernetes.io/healthcheck-path: "/"
alb.ingress.kubernetes.io/certificate-arn: <<<acm arn>>>
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80,"HTTPS": 443}]'
alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
alb.ingress.kubernetes.io/backend-protocol: HTTP
alb.ingress.kubernetes.io/target-type: ip
spec:
rules:
- host: "rollouts-test-active.<<<domain name>>>"
http:
paths:
- backend:
service:
name: ssl-redirect
port:
name: use-annotation
path: /
pathType: Prefix
- backend:
service:
name: rollout-bluegreen-active
port:
number: 8080
path: /
pathType: Prefix
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: default
name: rollouts-test-preview-ingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/group.name: rollouts-test
alb.ingress.kubernetes.io/scheme: internal
alb.ingress.kubernetes.io/security-groups: <<<sg id>>>
alb.ingress.kubernetes.io/healthcheck-path: "/"
alb.ingress.kubernetes.io/certificate-arn: <<<acm arn>>>
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80,"HTTPS": 443}]'
alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
alb.ingress.kubernetes.io/backend-protocol: HTTP
alb.ingress.kubernetes.io/target-type: ip
spec:
rules:
- host: "rollouts-test-preview.<<<domain name>>>"
http:
paths:
- backend:
service:
name: ssl-redirect
port:
name: use-annotation
path: /
pathType: Prefix
- backend:
service:
name: rollout-bluegreen-preview
port:
number: 8080
path: /
pathType: Prefix
위와 같은 yaml 파일을 생성 후 ArgoCD에서 배포해 주면 다음과 유사한 형태로 배포가 진행될 것입니다. Ingress는 실제 운영시 1개만 필요하지만 preview 페이지를 확인하기 위하여 1개 더 배포 하였습니다.

Rollouts 배포
브라우저를 통해 rollouts-test-active.<<<domain name>>>과 같이 active ingress 페이지에 접속해 보면 다음과 같은 화면을 확인 할 수 있습니다.

Active Ingress Page
이번에는 rollouts-test-preview.<<<domain name>>>과 같이 preview ingress 페이지를 확인해 보도록 하겠습니다.

Preview Ingress Page
동일한 페이지가 출력되는 것을 확인 할 수 있을 것입니다. 아직 Blue Image 만 배포되어 있는 상태이기 때문에 active, preview 2개의 도메인이 같은 페이지를 출력하고 있습니다. 이제 Green Image 배포를 통해 정상적으로 배포가 진행되는지 확인해 보도록 하겠습니다. 아래와 같이 Image를 변경해 줍니다.
spec:
containers:
- name: rollouts-demo
# image: argoproj/rollouts-demo:blue
image: argoproj/rollouts-demo:green
imagePullPolicy: Always
ports:
- containerPort: 8080
ArgoCD에서 배포가 진행되면서 Application의 상태가 Healthy에서 Suspended로 변경 됩니다.

Green Image Deploy
Green Image의 배포가 완료된 상태이지만 아직 Ingress가 기존 Blue Image 의 서비스를 제공하고 있는 상태입니다. autoPromotionEnabled: false 옵션에 의해 신규 배포가 이루어졌어도 바로 서비스를 제공하지 않고 대기 상태에 있습니다. 이제 rollouts-test-preview.<<<domain name>>>에 접속하여 배포된 이미지가 정상적으로 출력되고 있는지 확인합니다.

변경된 Green Image로 페이지가 출력되는 것을 확인할 수 있습니다. 이제 해당 이미지가 정상적으로 출력되는 것을 확인 했기 때문에 실제 서비스를 교체하도록 하겠습니다. Rollout의 Promote-Full 메뉴를 선택하면 서비스가 변경되면서 Application 상태가 Suspended에서 Healthy로 변경될 것입니다.

서비스 변경
이제 마지막으로 방금 전까지 Blue Image를 출력하고 있던 rollouts-test-active.<<<domain name>>> 페이지에 접속해 보면 해당 이미지가 Green으로 변경된 것을 확인할 수 있습니다.

Blue -> Green
그리고 잠시 기다리면 Rollout에서 제공하던 POD가 4개에서 2개로 변경되면서 기존 리소스를 삭제하는 것을 확인할 수 있습니다.

POD Count : 2
Rollout을 배포한 yaml 파일의 내용을 보면 autoPromotionEnabled라는 옵션이 제공된다는 것을 확인할 수 있습니다. 지금까지 진행한 과정을 살펴보면 배포 후 ArgoCD에서 Promote-Full을 클릭해 줘야만 서비스가 전환되고 있습니다. 하지만 이 모든 과정을 Suspended 상태 없이 자동화로 진행하고 싶다면 이 옵션을 False에서 True로 변경해주면 됩니다.
3. HPA 적용
Blue/Green 배포가 정상적으로 동작하지만 HPA에 의한 Scale Out이 Rollout에서 지원되지 않는다면 실제 운영환경에서 사용이 불가능합니다. 다행히도 HPA에서 scaleTargetRef 값에Rollout을 지원합니다. 이 내용은 아래 링크에서 확인할 수 있습니다.
https://argoproj.github.io/argo-rollouts/features/hpa-support/
HPA를 적용하는 방법은 기존 Deployment를 적용할 때와 동일합니다. 실제로 이 옵션을 적용하여 Scale Out이 정상적으로 동작하는지 확인해 보겠습니다.
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: hpa-rollout-example
spec:
maxReplicas: 6
minReplicas: 2
scaleTargetRef:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
name: php-apache
targetCPUUtilizationPercentage: 60
배포하면 ArgoCD에 HPA가 생성되고 HPA의 MinReplicas 값에 따라 2개의 POD가 생성될 것입니다.

HPA 배포
이제 해당 POD에 부하를 주어서 CPU 사용률을 높이면 아래와 같이 POD가 정상적으로 늘어나는 것을 확인할 수 있습니다.

POD Scale Out
부하를 없애고 잠시 기다려보면 POD가 다시 2개로 줄어드는 것까지 확인하실 수 있을 것입니다. 이렇게 간단한 설치와 설정만으로 EKS에서 수동으로 복잡하게 구성해야하는 Blue/Green 배포 방식을 사용할 수 있습니다.
이외 Canary 배포 전략도 ArgoCD에서 친절하게 지원해주고 있습니다. 아래 링크를 확인하시고 위에서 제가 제공해 드린 내용을 천천히 읽어보신다면 비록 제가 이 내용에 대한 가이드를 별도로 제공해드리지 않더라도 누구든 어렵지 않게 이용하실 수 있을 것입니다. 이 글을 보시는 모든 분들이 각 상황에 최적인 배포전략을 선택하셔서 손쉽게 구성하시길 바라겠습니다.
https://argoproj.github.io/argo-rollouts/features/canary/
감사합니다.