안녕하세요?
AEWS 9주차 과제로 EKS Blue/Green Migration 실습을 진행하겠습니다.
Blue/Green Upgrade - Amazon EKS Blueprints for Terraform
내용은 이 문서를 참고 하였습니다.
EKS의 업그레이드와 Blue/Green Migration에 대하여
쿠버네티스은 계속 업데이트되고, 예전 버젼은 지원을 하지 않게 되며 강제로 업그레이드를 시켜버리니 언젠가는 EKS의 버젼을 업그레이드해야 하는 순간이 옵니다.
이때 어떤 방식이 가장 안전할지에 대해서 생각해 볼 필요가 있습니다.
특히 프로덕션 환경에서 애플리케이션을 안전하게 배포하려면, 안정성과 롤백 가능성을 보장할 수 있는 전략이 필요합니다.
블루-그린 배포는 기존의 버전(블루)과 새로운 버전(그린)을 동시에 존재하게 한 뒤, 트래픽을 스위칭하여 배포하는 전략입니다.
이 접근 방식은 다음과 같은 특징이 있습니다:
- 배포 중 장애 발생 시 쉽게 롤백 가능
- 무중단 배포 실현
그러면 블루 그린 배포가 왜 필요할까요?
전통적인 롤링 업데이트(Rolling Update)는 점진적으로 Pod를 교체하기 때문에, 문제가 생기면 일부 사용자에게 오류가 발생할 수 있습니다.
반면 블루-그린 방식은 기존 블루 환경은 그대로 둔 채, 그린 환경을 배포하고 테스트한 뒤 한 번에 트래픽을 전환하기 때문에 다음과 같은 장점이 있습니다:
- 배포 중 문제 발생 시, 블루로 즉시 전환 가능
- 고가용성(HA) 환경에서 안정적 전환
- 실시간 검증 환경 제공
프로젝트 실습
아키텍쳐

위와 같은 구성이 됩니다.
같은 VPC내에 EKS Blue, Green을 생성해서 옮기는 구조가 될 것입니다.
코드 준비
git clone https://github.com/aws-ia/terraform-aws-eks-blueprints.git
cd terraform-aws-eks-blueprints
cd patterns/blue-green-upgrade/
terraform.tfvars.example를 terraform.tfvars에 복사하여 각 환경, eks-blue 및 eks-green 폴더에 심볼릭 링크하고 필요에 따라 region, hosted_zone_name, eks_admin_role_name을 변경합니다.
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
terrafrom.tfvars 파일을 살펴보면 아래와 같이,
region, environment_name, hosted_zone_name, eks_admin_role_name을 변경해주어야 합니다.
# You should update the below variables
aws_region = "eu-west-1"
environment_name = "eks-blueprint"
hosted_zone_name = "eks.example.org" # your Existing Hosted Zone
eks_admin_role_name = "Admin" # Additional role admin in the cluster (usually the role I use in the AWS console)
#gitops_addons_org = "git@github.com:aws-samples"
#gitops_addons_repo = "eks-blueprints-add-ons"
#gitops_addons_path = "argocd/bootstrap/control-plane/addons"
#gitops_addons_basepath = "argocd/"
# EKS Blueprint Workloads ArgoCD App of App repository
gitops_workloads_org = "git@github.com:aws-samples"
gitops_workloads_repo = "eks-blueprints-workloads"
gitops_workloads_revision = "main"
gitops_workloads_path = "envs/dev"
#Secret manager secret for github ssk jey
aws_secret_manager_git_private_ssh_key_name = "github-blueprint-ssh-key"
시크릿 매니저를 추가해줍니다.
로컬에 있는 나의 public key를 가지고 만들 수 있습니다.
aws secretsmanager create-secret \
--name github-blueprint-ssh-key \
--secret-string "$(cat ~/.ssh/id_ed25519.pub)"
{
"ARN": "arn:aws:secretsmanager:ap-northeast-2:441758121212:secret:github-blueprint-ssh-key-bYcvSM",
"Name": "github-blueprint-ssh-key",
"VersionId": "057c0b26-9177-408d-b53d-53c6d772df81"
}

물론 이 키는 GitHub에 등록이 되어있어야 합니다.

배포
cd environment
terraform init
terraform apply


클러스터 생성
cd eks-blue
terraform init
terraform apply
main.tf
rovider "aws" {
region = var.aws_region
}
provider "kubernetes" {
host = module.eks_cluster.eks_cluster_endpoint
cluster_ca_certificate = base64decode(module.eks_cluster.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
args = ["eks", "get-token", "--cluster-name", module.eks_cluster.eks_cluster_id]
}
}
provider "helm" {
kubernetes {
host = module.eks_cluster.eks_cluster_endpoint
cluster_ca_certificate = base64decode(module.eks_cluster.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
args = ["eks", "get-token", "--cluster-name", module.eks_cluster.eks_cluster_id]
}
}
}
module "eks_cluster" {
source = "../modules/eks_cluster"
aws_region = var.aws_region
service_name = "blue"
cluster_version = "1.30" << blue cluster 버전
argocd_route53_weight = "100"
route53_weight = "100" << 초기 가중치 100% (blue로만 인입)
ecsfrontend_route53_weight = "100"
environment_name = var.environment_name
hosted_zone_name = var.hosted_zone_name
eks_admin_role_name = var.eks_admin_role_name
# aws_secret_manager_git_private_ssh_key_name = var.aws_secret_manager_git_private_ssh_key_name
argocd_secret_manager_name_suffix = var.argocd_secret_manager_name_suffix
ingress_type = var.ingress_type
gitops_addons_org = var.gitops_addons_org
gitops_addons_repo = var.gitops_addons_repo
gitops_addons_basepath = var.gitops_addons_basepath
gitops_addons_path = var.gitops_addons_path
gitops_addons_revision = var.gitops_addons_revision
gitops_workloads_org = var.gitops_workloads_org
gitops_workloads_repo = var.gitops_workloads_repo
gitops_workloads_revision = var.gitops_workloads_revision
gitops_workloads_path = var.gitops_workloads_path
}
그린 클러스터 생성
cd eks-green
terraform init
terraform apply
클러스터가 생성되었습니다.

배포
클러스터는 각 클러스터에 동기화된 기존 ArgoCD Github 저장소로 구성됩니다.

마이그레이션 자동화를 시연하기 위해 워크로드 리포지토리에서 배포된 애플리케이션 중 하나인 팀-번햄 네임스페이스의 번햄 워크로드를 예로 살펴보겠습니다.
실행 중인 클러스터의 이름을 본문에서 응답할 수 있는 간단한 go 애플리케이션을 설정했습니다. 이를 통해 워크로드의 현재 마이그레이션을 쉽게 확인할 수 있습니다.
k get deployment -n team-burnham -l app=burnham
NAME READY UP-TO-DATE AVAILABLE AGE
burnham 3/3 3 3 30m
nginx 1/1 1 1 30m
k get pods -n team-burnham -l app=burnham
NAME READY STATUS RESTARTS AGE
burnham-9sk5e2tlks-l23ch 1/1 Running 0 30m
burnham-9sk5e2tlks-kltp5 1/1 Running 0 30m
burnham-9sk5e2tlks-5tfa1 1/1 Running 0 30m
Blue -> Green Migration
처음에는 번햄 트래픽의 100%가 eks-blue 클러스터로 설정되며, 이는 route53_weight = "100"이라는 매개변수를 사용하여 eks-blue/main.tf 및 eks-green/main.tf 파일에서 제어됩니다. 동일한 파라미터가 eks-green 클러스터에서는 0으로 설정됩니다.

아래가 100으로 되어 있어서 이런식으로 동작하게 됩니다.
cat eks-blue/main.tf
provider "aws" {
region = var.aws_region
}
provider "kubernetes" {
host = module.eks_cluster.eks_cluster_endpoint
cluster_ca_certificate = base64decode(module.eks_cluster.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
args = ["eks", "get-token", "--cluster-name", module.eks_cluster.eks_cluster_id]
}
}
provider "helm" {
kubernetes {
host = module.eks_cluster.eks_cluster_endpoint
cluster_ca_certificate = base64decode(module.eks_cluster.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
args = ["eks", "get-token", "--cluster-name", module.eks_cluster.eks_cluster_id]
}
}
}
module "eks_cluster" {
source = "../modules/eks_cluster"
aws_region = var.aws_region
service_name = "blue"
cluster_version = "1.30"
argocd_route53_weight = "100"
route53_weight = "100"
ecsfrontend_route53_weight = "100"
environment_name = var.environment_name
hosted_zone_name = var.hosted_zone_name
eks_admin_role_name = var.eks_admin_role_name
aws_secret_manager_git_private_ssh_key_name = var.aws_secret_manager_git_private_ssh_key_name
argocd_secret_manager_name_suffix = var.argocd_secret_manager_name_suffix
ingress_type = var.ingress_type
gitops_addons_org = var.gitops_addons_org
gitops_addons_repo = var.gitops_addons_repo
gitops_addons_basepath = var.gitops_addons_basepath
gitops_addons_path = var.gitops_addons_path
gitops_addons_revision = var.gitops_addons_revision
gitops_workloads_org = var.gitops_workloads_org
gitops_workloads_repo = var.gitops_workloads_repo
gitops_workloads_revision = var.gitops_workloads_revision
gitops_workloads_path = var.gitops_workloads_path
}
DNS 레코드 가중치가 블루 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

green에는 반대로 0인걸 볼 수 있습니다.
cat eks-green/main.tf
provider "aws" {
region = var.aws_region
}
provider "kubernetes" {
host = module.eks_cluster.eks_cluster_endpoint
cluster_ca_certificate = base64decode(module.eks_cluster.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
args = ["eks", "get-token", "--cluster-name", module.eks_cluster.eks_cluster_id]
}
}
provider "helm" {
kubernetes {
host = module.eks_cluster.eks_cluster_endpoint
cluster_ca_certificate = base64decode(module.eks_cluster.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
args = ["eks", "get-token", "--cluster-name", module.eks_cluster.eks_cluster_id]
}
}
}
module "eks_cluster" {
source = "../modules/eks_cluster"
aws_region = var.aws_region
service_name = "green"
cluster_version = "1.31" # Here, we deploy the cluster with the N+1 Kubernetes Version
argocd_route53_weight = "0" # We control with theses parameters how we send traffic to the workloads in the new cluster
route53_weight = "0"
ecsfrontend_route53_weight = "0"
environment_name = var.environment_name
hosted_zone_name = var.hosted_zone_name
eks_admin_role_name = var.eks_admin_role_name
aws_secret_manager_git_private_ssh_key_name = var.aws_secret_manager_git_private_ssh_key_name
argocd_secret_manager_name_suffix = var.argocd_secret_manager_name_suffix
ingress_type = var.ingress_type
gitops_addons_org = var.gitops_addons_org
gitops_addons_repo = var.gitops_addons_repo
gitops_addons_basepath = var.gitops_addons_basepath
gitops_addons_path = var.gitops_addons_path
gitops_addons_revision = var.gitops_addons_revision
gitops_workloads_org = var.gitops_workloads_org
gitops_workloads_repo = var.gitops_workloads_repo
gitops_workloads_revision = var.gitops_workloads_revision
gitops_workloads_path = var.gitops_workloads_path
}
만약에 green의 DNS 레코드 가중치를 100으로 하면 아래와 같은 결과가 나오는 것을 볼 수 있습니다.

'Kubernetes' 카테고리의 다른 글
Vault로 K8S Secret 관리하기 (0) | 2025.04.10 |
---|---|
Kubernetes Scheduling과 Scheduling plugins 파보기 (0) | 2025.03.20 |
Karpenter + Keda로 특정 시간에 Autoscaling 걸기 (0) | 2025.03.16 |
External Secret으로 AWS Secrets Manager와 EKS Secret 동기화하기 (0) | 2025.03.15 |
Datadog Agent로 Traefik pod의 로그를 Datadog으로 전송하기 (0) | 2025.02.26 |