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
본 글은 우 실습 가이드를 통해 실습한 내용을 정리하였습니다.
모든 이미지의 출처는 위 실습 가이드 입니다.
- Terrform
- Git
- GitOps repository SSH 인증 설정 (AWS Secret Manager -> "github-blue-print-ssh-key" 또는 workload_repo_secret 테라폼 변수로 변경 가능) : keygen을 통해 key를 만들고 github에 public key 등록 후 연동 테스트 필요
- AWS CLI
- Administrator 역할이 부여된 AWS 계정
- Amazon Route 53 Hosted Zone (hosted_zone_name 변수로 테라폼 코드에서 사용)
- 도메인 등록 (https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/domain-register.html)
> 실습 샘플 구성
- environment
. VPC
. Route53 sub domain hosted zone
. wildcard 인증서 (TLS 엔드포인트 용)
. SecreteManager 비밀번호 (ArgoCD UI 용)
- module/eks_cluster
. ArgoCD add-on
. 데모 워크로드
- eks-blue
. blue eks cluster
- eks-green
. green eks cluster
=> 2개의 EKS 클러스터가 동일한 VPC를 공유하고, 각 클러스터는 중앙 GitOps 리포지토리에서 ArgoCD 애드온을 사용하여 워크로드 설치
=> GitOps 리포지토리에서 애플리케이션을 배포하고 AWS Load Balancers Controller annotation을 사용하여, AWS 로드 밸런서를 통해 노출하며, 클러스터마다 1개의 로드 밸런서 생성
=> 두 클러스터에 ExternalDNS 애드온을 설정하여 동일한 Route 53 호스팅 영역을 공유하고, AWS Route 53의 가중치 레코드를 사용하여 두 EKS 클러스터 간에 카나리아 마이그레이션을 구성
> GitOps 구성
- Terraform 모듈
. eks : EKS 클러스터 생성
. eks_blueprints_teams : 팀별 네임스페이스, 권한(Quota, Role 등) 설정
. eks_blueprints_addons : AWS 리소스(예: IRSA 역할) 생성. 단, Helm 차트는 직접 배포하지 않음
. gitops-bridge-metadata : Terraform에서 생성한 리소스 정보를 메타데이터로 추출
. gitops_bridge_bootstrap : ArgoCD와의 연계를 위한 초기 부트스트랩
- GitHub 저장소
. eks-blueprints-add-ons : ArgoCD에서 사용할 ApplicationSet 정의
. eks-blueprints-workloads : 샘플 워크로드 저장소
> Terrafor aws eks blueprint
git clone https://github.com/aws-ia/terraform-aws-eks-blueprints.git
cd patterns/blue-green-upgrade/
1. 기본 설정
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
- hosted_zone_name : 본인의 hosted zone name으로 변경
- eks_admin_role_name : EKS 클러스터 관리자 권한을 가진 IAM Role 지정 (이번 실습에서 Admin 권한을 가지는 롤을 새로 만들고 적용)
- aws_region : 본인이 사용하는 region으로 변경
# You should update the below variables
aws_region = "ap-northeast-2"
environment_name = "eks-blueprint"
hosted_zone_name = "psalmist-study-aws.com" # 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"
2. environment 배포
❯ tree ../environment
../environment
├── README.md
├── main.tf
├── outputs.tf
├── terraform.tfstate
├── terraform.tfstate.backup
├── terraform.tfvars -> ../terraform.tfvars
├── variables.tf
└── versions.tf
cd environment
terraform init
terraform apply
- eks-blueprint VPC 1개 생성
- 6개(public 3개, private 3개) subnet 및 2개(public, private) 라우팅 테이블 생성
. pod는 private subnet에 배포
- NAT G/W (eks-blueprint-ap-northeast-2a)
- Internet G/W (eks-blueprint)
- public hosted zone 생성
- ACM 인증서 생성
- argocd admin 비밀번호 (secret manager secret 생성) - argocd 배포 후 admin 비밀번호 (k8s scret 값으로 들어감)
3. blue cluster 배포 (약 15분 소요)
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
}
- 1.30 EKS 클러스터 생성
- Amazon VPC CNI : v1.19.3-eksbuild.1
- kube-proxy: 1.30.9-eksbuild.3
- CoreDNS: v1.11.4-eksbuild.2
- team-burnham 네임스페이스에 배포된 워크로드를 통해 마이그레이션 자동화 확인
. reponse body에 실행 중인 클러스터 이름 표시
> blue cluster 확인
# kubeconfig update - 클러스터 생성한 사용자는 --role-arn 필요 없음
aws eks --region ${region} update-kubeconfig --name eks-blueprint-blue --role-arn ${arn of eks_admin_role_name}
#
kubectl cluster-info
kubectl get no
kubectl get deployment -n team-burnham -l app=burnham
kubectl get pods -n team-burnham -l app=burnham
kubectl logs -n team-burnham -l app=burnham
# cluster 이름 확인
URL=$(echo -n "https://" ; kubectl get ing -n team-burnham burnham-ingress -o json | jq ".spec.rules[0].host" -r)
curl -s $URL | grep CLUSTER_NAME | awk -F "<span>|</span>" '{print $4}'
eks-blueprint-blue
4. green cluster 배포 (약 15분 소요)
- 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" << green cluster 버전
<< 초기 가중치 100% (blue로만 인입) >>
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
}
- 1.30 EKS 클러스터 생성
- Amazon VPC CNI : v1.19.3-eksbuild.1
- kube-proxy: 1.30.9-eksbuild.3
- CoreDNS: v1.11.4-eksbuild.2
- team-burnham 네임스페이스에 배포된 워크로드를 통해 마이그레이션 자동화 확인
. reponse body에 실행 중인 클러스터 이름 표시
> green cluster 확인
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 = "green"
cluster_version = "1.31" << green cluster 버전
<< 초기 가중치 0% (blue로만 인입) >>
argocd_route53_weight = "0"
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 cluster 확인
# kubeconfig update - 클러스터 생성한 사용자는 --role-arn 필요 없음
aws eks --region ${region} update-kubeconfig --name eks-blueprint-green --role-arn ${arn of eks_admin_role_name}
#
kubectl cluster-info
kubectl get no
kubectl get deployment -n team-burnham -l app=burnham
kubectl get pods -n team-burnham -l app=burnham
kubectl logs -n team-burnham -l app=burnham
# cluster 이름 확인
URL=$(echo -n "https://" ; kubectl get ing -n team-burnham burnham-ingress -o json | jq ".spec.rules[0].host" -r)
curl -s $URL | grep CLUSTER_NAME | awk -F "<span>|</span>" '{print $4}'
eks-blueprint-green
- 1.31 EKS 클러스터 생성
- Amazon VPC CNI : v1.19.3-eksbuild.1
- kube-proxy: 1.31.3-eksbuild.2
- CoreDNS: v1.11.4-eksbuild.2
5. 카나리아 배포 실습
- 시나리오
. eks-blue: 100, eks-green: 0 => BLUE 100%
. eks-blue: 100, eks-green: 100 => BLUE 50% / GREEN 50%
. eks-blue: 0, eks-green: 100 => GREEN 100%
. 추후 스텝
- eks-blue 클러스터 삭제
- eks-blue 클러스터 업그레이드 후 트래픽 다시 돌림
- 롤백 대비용으로 eks-blue 유지
- Amazon Route 53 Hostes Zone 사용
. main.tf에서 exteranl_dns 설정 동일한 구성
enable_external_dns = true
external_dns_route53_zone_arns = [data.aws_route53_zone.sub.arn]
addons_metadata = merge(
...
external_dns_policy = "sync"
)
. sync 모드 사용 : ExternalDNS가 Ingress에 따라 DNS 레코드 생성 및 삭제 가능
- Ingress에 set-identifier, aws-weight 설정 사용
external-dns.alpha.kubernetes.io/set-identifier: {{ .Values.spec.clusterName }}
external-dns.alpha.kubernetes.io/aws-weight: '{{ .Values.spec.ingress.route53_weight }}'
. self-identifier : 해당 클러스터의 externalDns가 레코드 관리
. aws-weight : Helm values <- terraform이 주입 : 플랫폼 팀이 traffic 비율 조정 가능
> eks-blue: 100, eks-green: 0 => BLUE 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}'
> eks-blue: 100, eks-green: 100 => BLUE 50% / GREEN 50%
# eks-green/main.tf
cd eks-green
...
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 = "100" # We control with theses parameters how we send traffic to the workloads in the new cluster
...
# 적용
terraform apply
- 확인
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-blue: 0, eks-green: 100 => BLUE 50% / GREEN 100%
# blue-eks/main.tf
cd blue-eks
module "eks_cluster" {
source = "../modules/eks_cluster"
aws_region = var.aws_region
service_name = "blue"
cluster_version = "1.30"
argocd_route53_weight = "0"
route53_weight = "0"
ecsfrontend_route53_weight = "0"
terraform apply
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
- 모든 DNS TTL 갱신되면 트래픽은 전부 eks-green 클러스터로 이동함
> 추후 스텝
- eks-blue 클러스터 삭제
- eks-blue 클러스터 업그레이드 후 트래픽 다시 돌림
- 롤백 대비용으로 eks-blue 유지
> 자원 삭제
cd ../eks-blue
terraform destroy
cd ../eks-green
terraform destroy
cd ../environment
terraform destroy
11주차 - Amazon EKS, FSx, Inferentia를 활용한 생성형 AI 및 ML 환경 구축 (0) | 2025.04.19 |
---|---|
10주차 - k8s 시크릿 관리 (0) | 2025.04.12 |
8주차 - K8S CI/CD (0) | 2025.03.29 |
7주차 - EKS Mode/Nodes (0) | 2025.03.22 |
6주차 - EKS Security (0) | 2025.03.15 |