Cloudnet AEWS 9주차 스터디를 진행하며 정리한 글입니다.
이번 포스팅에서는 EKS 업그레이드 방식 중 하나인 Blue/Green 마이그레이션 방법에 대해 알아보겠습니다.
EKS 클러스터 업그레이드 방법
EKS 클러스터를 사용하면서 신규 Kubernetes 버전에 따라 클러스터를 최신으로 업데이트할 수 있는 방법은 다양합니다.
1. In-place 업그레이드
- 기존 클러스터 및 노드 그룹을 그대로 두고 Kubernetes 버전만 올리는 방식
- 컨트롤 플레인 → 워커 노드 → 애플리케이션 순서로 점진 업그레이드
- 장점: 인프라 변경 최소화
- 단점: 다운타임 발생 가능, 롤백 어려움
2. Blue/Green 업그레이드
- 새로운 클러스터(혹은 노드 그룹)를 생성한 후, 기존 환경과 병렬로 유지하면서 점진적으로 트래픽을 이동
- 업그레이드가 완료되면 기존 클러스터 제거
- 장점: 무중단 배포, 롤백 용이
- 단점: 비용 증가 (일시적으로 리소스 중복), IaC 기반 자동화 필요
3. Canary 업그레이드
- 일부 노드 또는 애플리케이션에만 새로운 버전을 적용해 문제가 없으면 전체에 확장
- kubeadm이나 eksctl, Argo Rollouts, 또는 Karpenter를 사용
Blue/Green Migration 실습
위에 소개한 다양한 방식 중, 다음 워크샵을 참고하여 Terraform 기반 Blue/Green 방식을 실습해보겠습니다.
https://aws-ia.github.io/terraform-aws-eks-blueprints/patterns/blue-green-upgrade/
Blue/Green Upgrade - Amazon EKS Blueprints for Terraform
Blue/Green Migration This directory provides a solution based on EKS Blueprint for Terraform that shows how to leverage blue/green or canary application workload migration between EKS clusters, using Amazon Route 53 weighted routing feature. The workloads
aws-ia.github.io
실습 구조
다음과 같이 Blue 클러스터를 생성 후 Route53에서 Blue 클러스터 도메인에 가중치 100을 주어 운영하다가, Green 클러스터를 사전에 생성한 후 Route53에서 가중치를 변경하여 클러스터 마이그레이션을 진행할 예정입니다.

실습은 다음 Repository 디렉터리에서 진행할 예정입니다.
.
├── README.md
├── bootstrap
├── eks-blue # Blue 클러스터
├── eks-green # Green 클러스터
├── environment # 공통 인프라 관리, 공유할 VPC와 Route53 서브도메인 호스팅 영역 등등
├── modules # 클러스터 정의하는 로컬 모듈
├── static
├── tear-down-applications.sh
├── tear-down.sh
└── terraform.tfvars.example
준비사항
AWS CLI, kubectl, Terraform 설치되어있는지 확인합니다.
❯ terraform -v
Terraform v1.5.6
on darwin_arm64
Your version of Terraform is out of date! The latest version
is 1.11.3. You can update by downloading from https://www.terraform.io/downloads.html
❯ git --version
git version 2.41.0
❯ aws --version
aws-cli/2.24.0 Python/3.12.6 Darwin/22.5.0 exe/x86_64
진행하는 실습에서, DNS 레코드를 만들어서 Ingress가 도메인으로 접근 가능하게 만들어야하기 때문에 Route53에 도메인을 예제 디렉터리 내부 terraform.tfvars.example 파일에 등록합니다.
GitOps 방식으로 진행하기 때문에 SSH access가 필요하여 Github의 SSH키를 생성하고, 이 SSH 키 값을 AWS Secret Manager에 저장합니다.
❯ ssh-keygen -t ed25519 -C "~~~@gmail.com"
❯ aws secretsmanager create-secret \
--name github-blueprint-ssh-key \
--secret-string "$(cat ~/.ssh/id_ed25519)"

실습 진행
이제 본격적으로 블루 클러스터를 생성하고, 그린 클러스터로 전환하는 실습을 진행해보겠습니다.
1. 기본 환경 설정
terraform.tfvars에 환경에 공통으로 사용하는 변수가 입력됩니다. 이 파일만 수정해도 3곳의 파일에 모두 반영될 수 있도록 심볼릭 링크로 연결합니다.
cp terraform.tfvars.example terraform.tfvars
ln -s ../terraform.tfvars environment/terraform.tfvars
ln -s ../terraform.tfvars eks-blue/terraform.tfvars
ln -s ../terraform.tfvars eks-green/terraform.tfvars
그 후 environment 디렉터리에서 실습에 사용할 인프라를 생성합니다.
(ex, VPC, 서브도메인 Route53 Hosted Zone, TLS 인증서, Secret Manager 리소스, 기타 Blue/Green 클러스터에서 공유할 리소스들 생성)
cd environment
terraform init
terraform apply
...
Apply complete! Resources: 31 added, 0 changed, 0 destroyed.
Outputs:
aws_acm_certificate_status = "PENDING_VALIDATION"
aws_route53_zone = "eks-blueprint.hellouz818.com"
vpc_id = "vpc-01abc189fc70102da"
2. 기존 클러스터(Blue) 배포
Blue 클러스터를 생성합니다. 이 때 Blue 클러스터 외에도 ArgoCD 및 Addon들이 설치됩니다.
cd eks-blue
terraform init
terraform apply
eks_blueprints_platform_teams_configure_kubectl = "aws eks --region ap-northeast-2 update-kubeconfig --name eks-blueprint-blue --role-arn arn:aws:iam::941377114730:role/team-platform-20250405083934793300000001"
eks_cluster_id = "eks-blueprint-blue"
gitops_metadata = <sensitive>
이 때 아래와 같은 에러가 발생했는데, 내가 사용하는 User이름이 admin이었지만, 실제 admin이라는 Role은 없어서, admin이라는 Role을 생성하고 임시로, AdministratorAccess 권한을 부여한 뒤 생성하였습니다.
Error: reading IAM Role (admin): couldn't find resource
│
│ with module.eks_cluster.data.aws_iam_role.eks_admin_role_name[0],
│ on ../modules/eks_cluster/main.tf line 256, in data "aws_iam_role" "eks_admin_role_name":
│ 256: data "aws_iam_role" "eks_admin_role_name" {
3. 새로운 클러스터(Green) 생성 (업그레이드된 버전)
Green 클러스터를 생성합니다. Blue 클러스터와 Kubernetes 버전이 다르며, 이 후 트래픽이 옮겨갈 클러스터입니다.
cd eks-green
terraform init
terraform apply
eks_blueprints_platform_teams_configure_kubectl = "aws eks --region ap-northeast-2 update-kubeconfig --name eks-blueprint-green --role-arn arn:aws:iam::941377114730:role/team-platform-20250405090853470400000002"
eks_cluster_id = "eks-blueprint-green"
gitops_metadata = <sensitive>
4. 애플리케이션 배포 및 테스트
team-burnham 네임스페이스에 배포된 어플리케이션이 현재는 Blue 클러스터에 배포 되어있는데, Green 클러스터를 만든 뒤 Green 클러스터로 전환하여 실제 어떤 클러스터로 요청이 가는지 확인할 수 있습니다.
(예제 어플리케이션은 현재 어떤 클러스터로 요청이 갔는지 디버깅하는 어플리케이션입니다.)

현재 ArgoCD가 자동으로 연결된 Github 레포지토리는 2개로, 각 클러스터는 GitOps 방식으로 이 두 repo에 리소스를 받아와서 생성합니다.
- EKS Blueprints Addon repo (Add-on)
- Workload repo (실제 어플리케이션)
ArgoCD 접근하기 위한 Key 값을 확인합니다.
❯ aws secretsmanager get-secret-value \
--secret-id argocd-admin-secret.eks-blueprint \
--query SecretString \
--output text
# 다만, ArgoCD 접근 시 Application이 없어서 에러 메세지를 확인했더니 다음 에러 메세지 출력
Failed to load target state: failed to generate manifest for source 1 of 1: rpc error: code = Unknown desc = ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain
# SSH 인증을 시도했지만 github에 키가 등록되지 않은 상황
❯ ssh -T git@github.com
The authenticity of host 'github.com (20.200.245.247)' can't be established.
ED25519 key fingerprint is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'github.com' (ED25519) to the list of known hosts.
git@github.com: Permission denied (publickey).
# Github에 key 등록 후 terraform apply로 재배포 하여 정상 동작
cat ~/.ssh/id_ed25519.pub <- 값을 https://github.com/settings/keys 에 추가
클러스터에 접속하여 배포된 리소스의 상태를 확인합니다.
❯ aws eks --region ap-northeast-2 update-kubeconfig --name eks-blueprint-blue --role-arn arn:aws:iam::123456789:role/YourAdminRole
❯ kubectl get deployment -n team-burnham -l app=burnham
NAME READY UP-TO-DATE AVAILABLE AGE
burnham 3/3 3 3 4m21s
nginx 1/1 1 1 4m21s
❯ kubectl logs -n team-burnham -l app=burnham
2025/04/05 10:00:16 {url: / }, cluster: eks-blueprint-blue }
2025/04/05 10:00:24 {url: / }, cluster: eks-blueprint-blue }
2025/04/05 10:00:29 {url: / }, cluster: eks-blueprint-blue }
2025/04/05 10:00:31 {url: / }, cluster: eks-blueprint-blue }
2025/04/05 10:00:39 {url: / }, cluster: eks-blueprint-blue }
2025/04/05 10:00:44 {url: / }, cluster: eks-blueprint-blue }
2025/04/05 10:00:46 {url: / }, cluster: eks-blueprint-blue }
5. 트래픽 전환
이제 트래픽을 Blue → Green 클러스터로 점진적으로 전환하겠습니다.
전환 시 Route53의 Weighted Record + ExternalDNS + Helm + Terraform을 통해 진행합니다.
ExternalDNS 설정을 확인해보겠습니다.
ExternalDNS란?
- Kubernetes 리소스를 보고, Route53과 같은 외부 DNS 서비스에 자동으로 도메인 레코드 등록해주는 컨트롤러
- 동일한 Route53 Hosted Zone을 공유하여 각 클러스터가 생성하는 ALB 도메인을 Route53에 자동 등록 가능
enable_external_dns = true
external_dns_route53_zone_arns = [data.aws_route53_zone.sub.arn]
addons_metadata = merge(
...
external_dns_policy = "sync" # sync 모드는 리소스 삭제 시 Route53의 레코드도 삭제
external_dns_txt_owner_id = var.cluster_name # 클러스터마다 다르게 설정되어 충돌 없이 동작 가능
)
Ingress 설정을 확인해보면 클러스터 이름과 Route53에서의 트래픽 가중치가 설정 되어있습니다.
annotations:
external-dns.alpha.kubernetes.io/set-identifier: eks-blueprint-blue
external-dns.alpha.kubernetes.io/aws-weight: "100"
이제 가중치를 변경하여 Blue 클러스터에서 Green 클러스터로 전환하도록 하겠습니다.
현재는 blue 클러스터 100 / green 클러스터 0으로 설정되어 있고, 모든 요청이 Blue 클러스터로만 이동하고, 응답에 eks-blueprint-blue라고 남습니다.

# eks-blue/main.tf
route53_weight = "100"
# eks-green/main.tf
route53_weight = "0"
# 결과
URL=$(echo -n "https://" ; kubectl get ing -n team-burnham burnham-ingress -o json | jq ".spec.rules[0].host" -r)
repeat 10 curl -s $URL | grep CLUSTER_NAME | awk -F "<span>|</span>" '{print $4}' && sleep 60
eks-blueprint-blue
eks-blueprint-blue
eks-blueprint-blue
eks-blueprint-blue
eks-blueprint-blue
eks-blueprint-blue
eks-blueprint-blue
eks-blueprint-blue
eks-blueprint-blue
eks-blueprint-blue
blue 클러스터 50 / green 클러스터 50으로 설정 시 모든 요청이 50퍼센트의 확률로 응답에 eks-blueprint-blue, eks-라고 남습니다.

# eks-blue/main.tf
route53_weight = "50"
# eks-green/main.tf
route53_weight = "50"
# 결과
URL=$(echo -n "https://" ; kubectl get ing -n team-burnham burnham-ingress -o json | jq ".spec.rules[0].host" -r)
repeat 10 curl -s $URL | grep CLUSTER_NAME | awk -F "<span>|</span>" '{print $4}' && sleep 60
eks-blueprint-green
eks-blueprint-green
eks-blueprint-blue
eks-blueprint-blue
eks-blueprint-green
eks-blueprint-green
eks-blueprint-green
eks-blueprint-green
eks-blueprint-blue
eks-blueprint-blue
blue 클러스터 0 / green 클러스터 100으로 설정 시 모든 요청이 Green 클러스터로만 이동하고, 응답에 eks-blueprint-green라고 남습니다.

# eks-blue/main.tf
route53_weight = "0"
# eks-green/main.tf
route53_weight = "100"
# 결과
❯ URL=$(echo -n "https://" ; kubectl get ing -n team-burnham burnham-ingress -o json | jq ".spec.rules[0].host" -r)
repeat 10 curl -s $URL | grep CLUSTER_NAME | awk -F "<span>|</span>" '{print $4}' && sleep 60
eks-blueprint-green
eks-blueprint-green
eks-blueprint-green
eks-blueprint-green
eks-blueprint-green
eks-blueprint-green
eks-blueprint-green
eks-blueprint-green
eks-blueprint-green
eks-blueprint-green
6. 기존 클러스터 종료
./tear-down.sh
이번 실습을 통해 도메인 기반 Blue/Green 실습을 진행해보았습니다.
'스터디 > AEWS' 카테고리의 다른 글
| [AEWS] 10주차 Vault CI/CD 구성하기 (2) | 2025.04.13 |
|---|---|
| [AEWS] 10주차 Vault 이해하기 (2) | 2025.04.13 |
| [AEWS] 8주차 Argo Rollout 이해하기 (0) | 2025.03.30 |
| [AEWS] 8주차 Jenkins를 통한 CI/CD 구성하기 (0) | 2025.03.30 |
| [AEWS] 7주차 AWS EKS Auto Mode (0) | 2025.03.29 |