AWS 기술 블로그

Blue/Green, Canary 방법을 활용한 stateless 워크로드의 Amazon EKS 클러스터 마이그레이션 전략

본 게시물은 AWS Container Blog에 게시된 ‘Blue/Green or Canary Amazon EKS clusters migration for stateless ArgoCD workloads by Sebastien Allamand’을 한국어 번역 및 편집하였습니다.

개요

조직에서는 마이크로서비스와 같은 최신 애플리케이션 개발 방식을 사용하여 혁신, 성능, 보안 및 안정성을 향상시킵니다. 하지만 레거시 배포 시스템을 사용하는 상황에서는 각 배포에 대한 제어와 보안을 유지하면서 빠른 배포 속도를 함께 유지하기 어렵습니다. 따라서 고객들은 애플리케이션 워크로드를 관리하기 위해서 Amazon Elastic Container Services(Amazon ECS) 또는 Amazon Elastic Kubernetes Service(Amazon EKS)와 같은 컨테이너 오케스트레이션 시스템을 사용하는 경우가 많습니다. 또한 지속적 전달(Continuous Delivery)은 고객이 애플리케이션과 인프라를 배포하고 위험 및 비용을 줄이면서 제품의 품질 및 시장 출시 시간을 개선하기 위한 모범 사례를 정의하는데 도움을 줄 수 있는 인기있는 원칙입니다. AWS 컨테이너 서비스들을 통해 실행되는 애플리케이션은 AWS 로드 밸런서를 통해 노출될 수 있고 Amazon Route 53을 사용하여 도메인 이름을 관리할 수 있습니다.

Amazon EKS를 사용한 Kubernetes 업그레이드 전략

Amazon EKS는 호환성 테스트를 거친 Kubernetes, etcd, 네트워킹 및 스토리지 플러그인의 바이너리와 컨테이너를 포함한 AWS의 Kubernetes 오픈 소스 배포판인 Amazon EKS Distro을 사용합니다. Kubernetes 릴리스는 1년에 약 3번 진행되는데 Amazon EKS는 언제든지 최소 네 가지 버전의 프로덕션용 Kubernetes 버전을 제공하며 최대 14개월 동안 Kubernetes 유지 관리 지원을 연장하는 등 최선을 다해 지원하고 있습니다. 따라서 Kubernetes 버전을 업그레이드하기 위해서 연간 계획이 필요합니다. 여러 버전을 한 번에 업그레이드하거나 검증된 Amazon EKS의 새 Kubernetes 버전으로 클러스터를 정기적으로 업그레이드해야 합니다.

Kubernetes 기능이 발전함에 따라 애플리케이션 프로그래밍 인터페이스(API)도 이러한 변화를 지원하도록 발전해야 합니다. 보통 새로운 API는 이전 버전과의 호환성과 안정성을 보장해야 하는 규칙이 일반적이지만, *이전 API가 지원되지 않는 경우라면 새 API 버전 및 형식을 사용해야 합니다.

(*역자 주: 보통 이전 API 호환성이 보장되지 않는 경우 또는 Deprecated된 API가 완전히 삭제된 경우 등을 Breaking Change라고 부르며, Major나 Minor 버전이 올라가는 경우 Breaking Change가 있는지 Release Notes를 꼼꼼하게 살펴봐야 합니다.)

업그레이드를 계획할 때는 다양한 요인이 업그레이드 프로세스에 영향을 미칠 수 있으므로 프로덕션 환경을 사용하기 전에 마이그레이션 테스트를 수행해야 합니다. 테스트 대상에는 클러스터 노드의 Amazon Machine Image(AMI), 클러스터에 배포된 애드온(예: kube-proxy, CodeDNS 및 AWS VPC CNI) 또는 고객이 Kubernetes 기능 확장을 위해 설치하여 추가 업그레이드가 필요할 수 있는 컨트롤러 또는 드라이버가 포함됩니다. 관련해서 특정 Kubernetes 버전에서 작동하지 않는 API를 식별하는 데 도움이 되는 Kubent와 같은 도구가 있습니다. 또한 새로 출시된 버전의 변경 사항에 대한 Amazon EKS 클러스터 Kubernetes 버전 업데이트 사용 설명서를 읽어 보는 것이 좋습니다. 경우에 따라서 새로 출시된 버전에 맞게 워크로드의 업데이트가 필요할 수도 있습니다.

In-place 롤링 업그레이드

Kubernetes 릴리즈의 각 버전을 개별적으로 업그레이드하기 위해서는 1년에 2~3회 정도 업그레이드 계획을 세우는 것이 일반적인 빈도입니다.

Amazon EKS로 전환하여 얻을 수 있는 주요 이점 중 하나는 AWS가 해당 업그레이드를 실행할 수 있는 API를 공개하여 Kubernetes 컨트롤 플레인의 업그레이드를 처리한다는 것입니다. Amazon EKS 관리형 기능(관리형 노드 그룹, AWS Fargate, Amazon EKS 관리형 애드온 등)을 많이 사용할수록 업그레이드 프로세스는 더욱 간소화됩니다. 관리형 노드 그룹의 Kubernetes 업그레이드는 롤링 방식으로 자동화되어 Amazon EKS에서 한 번에 업그레이드 할 수 있는 노드 수를 제어할 수 있습니다. 이 업그레이드 프로세스는 모든 Pod Disruption Budget(PDB) 설정을 준수하기 때문에 워크로드를 보호하기 위해서 클러스터에 해당 기능을 설정하는 것을 권장합니다. 업그레이드 시간은 이전 노드에서 제거해야 하는 포드(Pod) 수, 준수해야 하는 PDB, 클러스터의 노드 수, 업그레이드 병렬 처리 설정에 따라 달라집니다. Amazon EKS의 관리형 애드온을 업그레이드 하는 것도 Amazon EKS 콘솔과 Infrastructure as Code(IaC)에서 버전을 선택하여 간단하게 업데이트할 수 있고 마찬가지로 Amazon EKS에서 관리합니다. 관련하여 이 게시물을 통해 In-place 롤링 업그레이드 프로세스를 통해 Amazon EKS 애드온의 사용자 지정 구성을 보존할 수 있음을 확인할 수 있습니다.

Blue/Green or Canary 업그레이드

대부분의 경우 내장된 롤링 업데이트 솔루션을 사용하면 클러스터를 간단하게 업그레이드할 수 있습니다. 하지만 클러스터를 새로 만들고 기존 클러스터에서 새로운 클러스터로 워크로드를 마이그레이션 하는 것이 더 좋은 방법일 때가 있습니다. 예를 들면 Kubernetes 버전이 여러 개 뒤처져 있는 경우이거나 롤링 업데이트를 위한 사전 테스트에서 문제를 감지한 경우입니다. 이런 경우에는 TheFork 고객의 Kubernetes 클러스터 업그레이드 전략을 설명한 이전 게시물의 내용처럼 In-place 업그레이드 또는 Blue/Green 업그레이드를 혼합하여 진행할 수 있습니다. TheFork 고객은 모든 AWS 인프라를 Kubernetes가 아닌 Terraform에서 관리하는 Terraform 우선 접근 방식입니다. 이 방식은 한 클러스터에서 다른 클러스터로 이전할 때 리소스가 동일하게 유지되므로 Amazon EKS 클러스터의 Blue/Green 마이그레이션 프로세스를 간소화합니다.

이 방법을 사용할 때 로드 밸런서를 생성하기 위해서 IaC를 정의합니다. 로드 밸런서는 Amazon EKS 클러스터와 클러스터마다 하나씩 있는 두 대상 그룹 모두에 대해 동일하게 유지됩니다. 그런 다음 AWS Load Balancer ControllerTargetGroupBinding 사용자 지정 리소스 정의(CRD)를 사용하여 방금 생성한 기존 대상 그룹에 서비스를 동적으로 연결할 수 있습니다. 로드 밸런서의 리스너 규칙에서 각 대상 그룹으로 보낼 요청의 가중치를 설정하여 클러스터 간 요청 마이그레이션을 제어합니다. 이 솔루션의 장점은 클라이언트 장치의 도메인 네임 서버(DNS)의 TTL(Time to Live) 또는 캐싱에 의존하지 않는다는 것입니다.

하지만 고객의 애플리케이션을 개발하는 다양한 팀에서 수백 개의 서비스를 노출하기 시작하면 이러한 패턴을 확장하기가 어려워질 수 있습니다. 그 이유는 모든 애플리케이션 팀들이 플랫폼 팀에 애플리케이션이 노출할 로드 밸런서와 대상 그룹을 미리 생성하도록 요청해야 하기  때문입니다. 따라서 많은 고객들은 애플리케이션 팀에 더 많은 자율성을 부여하고 AWS Load Balancer Controller와 External DNS를 사용하여 Kubernetes의 서비스(Service) 또는 인그레스(Ingress) 오브젝트에 어노테이션(Annotation)을 추가하여 필요에 따라 리소스를 구성할 수 있도록 합니다.

분명한 것은 IaC 또는 Kubernetes를 사용하여 로드 밸런서를 만드는 각각의 경우가 클러스터 업그레이드를 하기 위한 세부적인 구현이 다르다는 것입니다. 따라서 어떤 경우든 Kubernetes 업그레이드를 반복적으로 테스트하는 것이 필수적이라는 점을 명심하십시오.

솔루션 개요

본 게시물에서는 플랫폼 팀이 Amazon EKS Blue 클러스터에서 Green 클러스터로의 워크로드 마이그레이션을 자동화할 수 있는 한 가지 가능한 구현 방법을 중점적으로 설명합니다.

이 솔루션을 참고하면서 따라할 수 있는 Terraform IaC 코드는 여기 git 리포지토리에 있습니다.

Blue&Green Weighed traffic routing with Route 53

Amazon EKS Blueprint for Terraform 오픈 소스 프로젝트를 사용하여 동일한 VPC를 사용하고, 애플리케이션을 노출하기 위해 AWS Load Balancer Controller와 External-DNS 애드온을 사용하는 두 개의 클러스터 (eks-blue 및 eks-green)를 생성합니다. Amazon EKS Blueprint는 클러스터를 생성하고 애드온을 설치하며 (Team)을 구성합니다.

여기서 두 가지 유형의 팀을 고려합니다. 플랫폼 팀은 인프라 자동화 코드를 담당하고 Amazon EKS 클러스터를 관리(관리 권한이 있음)합니다. 애플리케이션 팀은 워크로드의 빌드 및 배포를 담당하며 Kubernetes 네임스페이스와 연결(네임스페이스 읽기 전용 권한이 있음)됩니다.

애플리케이션 팀은 ArgoCD 애드온과 함께 GitOps 방식을 사용하여 워크로드를 클러스터에 배포합니다. 이때 ArgoCD Applications Kubernetes 오브젝트를 참조한 Helm 차트가 포함된 기존 “App of Apps” 구성 git 리포지토리를 사용합니다. Amazon EKS 클러스터가 생성되면 ArgoCD는 Git 리포지토리와 연결하여 클러스터를 조정합니다. 즉, Git에 정의된 워크로드를 Amazon EKS 클러스터에 배포합니다.

Amazon EKS Blueprint와 함께 Amazon EKS 애드온을 배포하는 방법은 두 가지가 있습니다. 두 가지 방법 모두 Terraform은 애드온 서비스 계정에 필요한 AWS Identity and Access Management (AWS IAM) 역할과 같은 필요한 리소스를 생성합니다. 하지만 애플리케이션의 Helm 차트는 Terraform 또는 ArgoCD 중 하나를 통해 배포할 수 있습니다. 플랫폼 팀은 ArgoCD에서 애드온 (예: metrics 서버, AWS Load Balancer Controller, external DNS, Karpenter 및 kubecost) 을 배포하는 데 사용하는 애드온 “App of App” Git 리포지토리를 이미 구성했습니다. 다음과 같이 애드온을 활성화하겠습니다.

enable_aws_load_balancer_controller = true
enable_external_dns = true
enable_karpenter = true
... 

ArogoCD EKS Add-on

우리의 목표는 애플리케이션 팀에게 Git 리포지토리를 통해 애플리케이션을 구축 및 배포할 수 있는 자율적인 방법을 제공하고, 플랫폼 팀에는 애플리케이션이 액세스할 수 있는 Amazon EKS 클러스터를 관리할 수 있는 방법을 제공하는 것입니다. 두 팀 모두 독립적으로 작업할 수 있는 파라미터에 합의하여 인지하고 있어야 합니다. 본 게시물에서는 Amazon Route53의 가중치 라우팅 기능을 사용하여 이를 수행할 수 있는 한 가지 방법을 제시합니다.

솔루션은 로컬 eks_cluster 테라폼 모듈을 사용하는eks-blueeks-green 두 클러스터에 대해 공유된 VPC와Amazon Route53 호스팅 영역을 생성하는 core-infra 스택으로 구성됩니다.

GitOps 워크로드 리포지토리의 두 클러스터에 동일한 애플리케이션을 배포하도록 Amazon EKS Blueprint를 구성했습니다.

일부 애플리케이션은 로드 밸런서 컨트롤러를 트리거하는 Kubernetes인그레스 오브젝트를 정의해서 애플리케이션을 위한 로드 밸런서를 생성합니다. 또한 전송 계층 보안(TLS, Transport Layer Security) 엔드포인트를 AWS Certificate Manager 서비스의 와일드 카드 인증서와 연결합니다. ExternalDNS 애드온은 공유된 core-infra 호스팅 영역에서 레코드를 생성하도록 구성됩니다.

values.yaml 파일을 사용한 Terraform에서 워크로드 애플리케이션을 구성하므로 각 클러스터에 서로 다른 파라미터 값(예: DNS 레코드의 가중치)을 적용하여 각 클러스터에 얼마나 많은 요청을 보낼 것인지 정의하여 두 클러스터 간 Canary 워크로드 마이그레이션을 제어할 수 있습니다. 본 게시물에서는 Blue/Green 또는 Canary 전략을 함께 사용하여 두 클러스터 간에 stateless 워크로드를 원활하게 마이그레이션하는 방법을 보여줍니다. 이 아키텍처의 또 다른 사용 사례는 고객의 고가용성 또는 짧은 지연 시간 액세스를 위해 워크로드를 서로 다른 Amazon EKS 클러스터, VPC 또는 리전으로 분리하는 것입니다.

테스트 해보기

시작하기

이 솔루션을 테스트하려면 Amazon EKS Blueprint 예제로 이동하여 단계별 지침을 따르면 됩니다. 게시물의 나머지 부분에서는 해당 리포지토리에 사용된 구성을 보여 줍니다. 또한 테스트의 사전 구성 요소를 제대로 준비했는지 확인한 다음 QuickStart 세부 정보를 따릅니다.

테스트 애플리케이션 살펴보기

마이그레이션 자동화를 시연하기 위해 워크로드 리포지토리에서 배포된 애플리케이션 중 하나인 team-burnham 네임스페이스에 배포된 Burnham 워크로드 예제를 살펴보겠습니다. 이 간단한 애플리케이션은 실행 중인 클러스터의 이름을 응답하도록 개발 되었기 때문에 워크로드의 현재 마이그레이션 상태를 쉽게 확인할 수 있습니다.

<head>
  <title>Hello EKS Blueprint</title>
</head>
<div class="info">
  <h>Hello EKS Blueprint Version 1.4</h>
  <p><span>Server&nbsp;address:</span> <span>10.0.2.201:34120</span></p>
  <p><span>Server&nbsp;name:</span> <span>burnham-9d686dc7b-dw45m</span></p>
  <p class="smaller"><span>Date:</span> <span>2022.10.13 07:27:28</span></p>
  <p class="smaller"><span>URI:</span> <span>/</span></p>
  <p class="smaller"><span>HOST:</span> <span>burnham.eks-blueprint.mon-domain.com</span></p>
  <p class="smaller"><span>CLUSTER_NAME:</span> <span>eks-blue</span></p>
</div>

애플리케이션은 ArgoCD integration설정을 사용하여 워크로드 리포지토리의 매니페스트 파일을 참조해 배포됩니다.

두 Amazon EKS 클러스터 모두 동일한 Amazon Route 53 호스팅 영역을 사용하도록 구성했습니다. 이는 main.tf에서 ExternalDNS 애드온 설정을 구성하여 수행됩니다.

  enable_external_dns = true
 
  external_dns_helm_config = {
    txtOwnerId         = local.name
    zoneIdFilter       = data.aws_route53_zone.sub.zone_id
    policy             = "sync"
    awszoneType        = "public"
    zonesCacheDuration = "1h"
    logLevel           = "debug"
  }

컨트롤러가 서비스 또는 인그레스 오브젝트 생성에 따라 DNS 레코드를 생성하고 제거할 수 있도록 ExternalDNS의 동기화 모드를 사용합니다. 또한 각 컨트롤러가 적절한 OwnerID에 연결된 레코드에 대해서만 레코드를 생성, 업데이트 또는 삭제할 수 있도록 txtOwnerID를 클러스터 이름으로 구성합니다. 각 클러스터에는 서로 다른 ID(eks-blue, eks-green)를 가지며 이러한 ID는 아래와 같은 형태로 전용 TXT 레코드로 전파됩니다.

"heritage=external-dns,external-dns/owner=eks-blue,external-dns/resource=ingress/team-burnham/burnham-ingress"

여기서 owner는 eks-blue클러스터의 외부 DNS 컨트롤러이며, team-burnham 네임스페이스의 burnham-ingress라는 Kubernetes 인그레스 리소스에 해당합니다.

가중치 레코드와 함께 이 기능을 사용하면 각 클러스터에 정의된 인그레스 리소스의 가중치를 변경하여 Blue/Green 또는 Canary 마이그레이션을 수행할 수 있습니다.

애플리케이션의 레코드 가중치 설정하기

플랫폼 팀에서 ExternalDNS 애드온을 구성했으므로 이제 애플리케이션 팀은 인그레스 또는 서비스 오브젝트에 특정 어노테이션을 정의할 수 있습니다. 다음은 예제 리포지토리의 인그레스 구성 예시 입니다.

external-dns.alpha.kubernetes.io/aws-weight: '{{ .Values.spec.ingress.route53_weight }}'
external-dns.alpha.kubernetes.io/set-identifier: '{{ .Values.spec.clusterName }}'

두 개의 external-dns 어노테이션을 사용하여 레코드 생성 방법을 구성합니다. set-identifier 어노테이션은 레코드를 연결할 클러스터 이름이 설정되고 aws-weight 어노테이션은 레코드 가중치 값을 설정하는데 사용됩니다. 각 클러스터를 생성하거나 업데이트할 때 Terraform 코드를 통해 어노테이션의 설정 값이 주입되므로 플랫폼 팀은 Amazon EKS 클러스터 간에 워크로드를 마이그레이션하는 방법과 시기를 제어할 수 있습니다.

테라폼으로 마이그레이션 자동화하기

만약에 현재 워크로드가 Kubernetes 1.23 버전의 eks-blue 클러스터에서만 실행된다고 가정하고 eks-blue 클러스터 설정은 다음 예시를 사용합니다.

eks-blue:

cluster_version            = "1.23"
  argocd_route53_weight       = "100"
  route53_weight              = "100"
  ecsfrontend_route53_weight  = "100"

그리고 새로운 eks-green 클러스터는 Kubernetes 버전 1.24에서 생성한다고 가정하겠습니다. 우리는 eks-green 리포지토리를 구성하여 이를 수행합니다. 이 때 green 리포지토리의 레코드 가중치를 0으로 설정하여 terraform이 제대로 적용되는지 확인합니다.

eks-green:

cluster_version           = "1.24"
  argocd_route53_weight      = "0"
  route53_weight             = "0"
  ecsfrontend_route53_weight = "0"

그러면 다음과 같은 구성이 됩니다.

Route 53 Weighed record to Blue

새롭게 생성한 클러스터는 로드 밸런서와 함께 생성되었지만 아직 가중치가 0으로 설정되어 있기 때문에 DNS 응답에는 포함되지 않습니다.

만약 로드 밸런서를 직접 호출하여 애플리케이션이 올바르게 응답하는지 확인 하고자 한다면 다음과 같이 호스트 헤더를 추가하여 테스트할 수 있습니다.

$ curl -k -H 'Host: burnham.eks-blueprint.my-example.com' \   https://$(kubectl get ing -n team-burnham burnham-ingress  -o json | \   jq ".status.loadBalancer.ingress[0].hostname" -r)

위 명령어를 참고하여 정상적으로 호출했다면 eks-green 클러스터에서 응답을 받아야 합니다. 만약 404 오류가 발생했다면 호스트 헤더를 올바른 값으로 업데이트했는지 확인합니다.

<head>
  <title>Hello EKS Blueprint</title>
</head>
<div class="info">
  <h>Hello EKS Blueprint Version 1.4</h>
  <p><span>Server&nbsp;address:</span> <span>10.0.1.167:3724</span></p>
  <p><span>Server&nbsp;name:</span> <span>burnham-6bf95f8fbf-dr2lg</span></p>
  <p class="smaller"><span>Date:</span> <span>2022.11.08 14:34:20</span></p>
  <p class="smaller"><span>URI:</span> <span>/</span></p>
  <p class="smaller"><span>HOST:</span> <span>burnham.eks-blueprint.my-example.com</span></p>
  <p class="smaller"><span>CLUSTER_NAME:</span> <span>eks-green</span></p>
</div>

지금까지 모두 정상적으로 동작했다면 eks-blue 및 eks-green 클러스터에서 burnham 워크로드에 대한 가중치 파라미터 값을 점진적으로 변경하고 Terraform에 변경 사항을 적용하여 Canary 마이그레이션을 시작할 수 있습니다. API 요청이 eks-green 클러스터의 요청으로 100%가 될 때까지 마이그레이션되는 것을 확인합니다.

TTL의 기본 값이 60초로 설정된 DNS를 사용하지만, 마이그레이션이 완전히 적용되려면 모든 HTTP 클라이언트나 프록시의 DNS 캐시가 업데이트할 때까지 기다려야 한다는 점에 주의합니다.

지금까지 워크로드를 eks-blue 클러스터에서 사용 가능한 최신 EKS 버전의 새로운 eks-green 클러스터로 성공적으로 마이그레이션했습니다. 만약 일부 워크로드를 롤백해야 하는 경우를 위해서 eks-blue 클러스터를 유지할 수도 있습니다. 이후에 eks-blue 클러스터가 더 이상 필요 없어진다면 클러스터를 제거하여 관련 리소스를 확보합니다.

Route 53 weighed record to green

리소스 정리하기

이 솔루션에 대한 테스트를 마치면 계정에서 관련된 리소스를 삭제할 수 있습니다. 자세한 지침은 이 섹션을 참조하십시오.

먼저 eks-blue와 eks-green디렉토리로 이동하여 tear down 스크립트를 실행합니다.

../tear-down.sh

완료되면 core-Infra 디렉토리로 이동하여 아래 명령어를 실행합니다.

terraform apply -destroy -auto-approve

결론

본 게시물에서는 클러스터 업그레이드를 위한 다양한 전략을 시연하고 Amazon Route53 가중치  레코드, Terraform 구성 및 ArgoCD를 사용하여 한 클러스터에서 다른 클러스터로 stateless 워크로드를 자동으로 마이그레이션하는 솔루션을 제공했고 이 솔루션의 장점을 살펴봤습니다. 또한 DNS TTL의 한계와 Kubernetes 서비스와의 동적 매핑을 위한 Load Balancer Controller의 TargetGroupBinding 기능으로 로드 밸런서 및 대상 그룹을 생성하기 위해 IaC를 사용한 방법에 대해서도 살펴봤습니다. 다음 게시물에서는 stateful 워크로드의 Amazon EKS 클러스터 마이그레이션을 위한 내용을 다루겠습니다.

Suggested tags:  Amazon EKSArgoCDblue-greenblueprintCanaryCluster Management

Jungseob Shin

Jungseob Shin

신정섭 Solutions Architect는 다양한 분야의 Backend 서버 개발 경험을 바탕으로 Startup 고객이 비즈니스 목표를 달성하도록 AWS 서비스의 효율적인 사용을 위한 아키텍처 설계 가이드와 기술을 지원하는 역할을 수행하고 있습니다. 컨테이너와 서버리스 기술에 관심이 많습니다.