본문 바로가기

Backend/AWS

AWS Elastic Beanstalk에서 쿠버네티스로 전환하기

AWS ElasticBeanstalk 기반에서 쿠버네티스 환경(AWS EKS)으로 마이그레이션 한 히스토리를 소개하겠습니다!
크게 문제상황 / 도입 과정 / 성과로 정리했습니다.
 


 


[문제 상황]


처음 서비스는 B2C API 서버, 어드민, 인증서버만으로  구성되었습니다. 이는 ElasticBeanstalk으로도 충분히 운영할 수 있는 규모입니다. 하지만 회사 서비스와 비즈니스가 고도화되면서 많은 기능이 추가되었습니다. B2B 서비스, CRM 연동 서비스, AI 추천 서비스 등등 다양하게 추가되었습니다. 이렇게 점점 많은 애플리케이션이 추가되면서, 이를 ElasticBeanstalk로 관리하는데에 어려움을 겪고 있었습니다. 
 

1. 서비스 확장에 따른 관리 복잡도 증가

초기에는 애플리케이션 수가 적어 Elastic Beanstalk로도 충분히 운영할 수 있었습니다. 그러나 비즈니스가 고도화되면서 다양한 기능이 추가되어 관리해야 할 서비스의 수가 급격히 증가했습니다. 각 서비스마다 별도의 Elastic Beanstalk 환경을 구축해야 했고 결과적으로, 각 애플리케이션의 설정과 유지보수에 많은 리소스가 소모되었으며, 새로운 애플리케이션을 구축하는 데 큰 장애물이 되었습니다.
 

2. 비용 효율성 문제

Elastic Beanstalk 환경에서는 각 서비스마다 필히 인스턴스를 유지/생성해야 합니다. 이는 고정 비용을 증가시키는 주요 요인이며 리소스 활용의 비효율성을 초래합니다.
스팟 인스턴스는 비용을 절감할 수 있는 좋은 방법이지만, Elastic Beanstalk에서는 이를 효과적으로 활용하기 어려웠습니다.
컨테이너 기반의 환경에서는 스팟 인스턴스가 종료되더라도 다른 노드로 빠르게 이동할 수 있지만, EB에서는 이러한 유연한 리소스 관리가 어려웠습니다. 결과적으로, 더 저렴하고 효율적으로 운영할 방법이 필요하다는 확신이 들었습니다.
 

3. DevOps 성숙도 향상의 필요성

많은 서비스들이 식별되면서, 더 모던한 마이크로서비스 아키텍처가 필요해졌습니다. 현 인프라 구조는 이런 요구사항을 충족시키기 어려웠습니다. 개발 방향성과 인프라 간의 괴리가 점점 커져가며, 더 이상 기존의 방식으로는 빠르게 변화하는 비즈니스 요구를 충족시킬 수 없다는 것을 깨달았습니다. 이러한 문제는 쿠버네티스 생태계로 눈을 돌리게 된 결정적 계기가 되었습니다. 쿠버네티스는 이를 충족시킬 수 있는 강력한 인프라를 제공하며 개발팀은 더 나은 품질의 소프트웨어를 더 빠르게 제공할 수 있게 되었습니다.
이러한 전환은 단순한 기술적 변화가 아니라, 개발팀의 생산성과 비즈니스 목표 달성을 위한 필수적인 전략적 선택이었습니다.
 


[도입 과정]

Step 1. 쿠버네티스 클러스터 환경 구축

쿠버네티스와 필요로하는 기능을 도입하기 위해, 아래 서비스를 이용하였습니다.

  • AWS EKS (Elastic Kubernetes Service): 관리형 클러스터를 구축하여, 쿠버네티스 클러스터 관리의 복잡성을 줄이고 안정성을 높였습니다.
  • Karpenter: 노드 스케일링을 자동화하여, 리소스 사용량에 따라 노드를 동적으로 추가하거나 제거할 수 있게 했습니다. 스팟 인스턴스를 함께 사용하여 비용 효율성을 크게 증대시킬 수 있었습니다.
  • ArgoCD: GitOps를 실현하여, 코드 변경 사항을 자동으로 배포하고, 배포 상태를 실시간으로 모니터링할 수 있었습니다. 이는 배포의 일관성을 높일 수 있습니다.
  • Grafana: 클러스터와 애플리케이션의 상태를 모니터링합니다.

 

Step 2. 외부 트래픽과 무관한 서비스를 선택하여 테스트하기

클러스터 환경이 성공적으로 구축된 후, 테스트용으로 파드를 배포했습니다. 이 과정에서 중요한 전략은 외부 요청을 직접적으로 받지 않는 서비스를 선택하는 것이었습니다. 이러한 서비스는 외부 트래픽에 직접적인 영향을 받지 않기 때문에, 초기 테스트에 적합했습니다. 저희는 주문/회원 관련 이벤트를 수신하여 CRM에 반영하는 메시지 컨슈머 애플리케이션으로 테스트를 진행하였습니다. 해당 파드가 제거된다고 해도, 이미 동일한 서비스는 EB환경에서 배포가 되었기 때문에 서비스에 영향을 주지 않습니다. 이 과정에서 Karpenter의 노드 스케일링, Gitops의 흐름, 모니터링을 테스트 할 수 있습니다. 
 
만약 팀이 k8s 경험이 부족하다면, 메시지 컨슈머와 같은 비동기처리가 가능한 애플리케이션을 선택하여 경험해보는 것을 추천합니다. 이러한 애플리케이션은 핵심 비즈니스에 직접적인 영향을 주지 않으므로, 초기 테스트에 적합하며, 클러스터 환경에 대한 이해도를 높이는 데 큰 도움이 됩니다
 
 

Step 3. 개발환경을 쿠버네티스로 전환하기

클러스터의 주요 서비스들이 정상적으로 동작하는 것을 확인하고나서, 개발환경부터 쿠버네티스로 전환했습니다.
개발 환경에서는 운영과는 다르게, 대부분의 파드를 스팟 인스턴스에 배치할 수 있습니다. 그래서 비용을 크게 절감 하게 되었습니다.
 

 No PlanSaving Plan
(절감형 플랜)
Reserved Instance
(예약 인스턴스)
Spot Instance
(스팟 인스턴스)
시간당 가격 (t3a.medium)0.0376 USD0.02710.0240.0107
가격 비율3.62.72.41

 
스팟 인스턴스는 예약 인스턴스에 비해 절반 이상 저렴하여, 비용 절감에 매우 유리합니다. 그러나 스팟 인스턴스는 AWS가 언제든지 자원을 회수할 수 있다는 단점이 있습니다. 개발 서버는 운영 환경에 비해 가용성의 중요성이 상대적으로 낮기 때문에, 이러한 특성을 최대한 활용하여 비용을 절감하는 것이 중요합니다.
개발 환경에서도 가용성이 필요한 서비스가 존재합니다. 이러한 서비스는 on-demand 인스턴스에 배치하여 안정성을 확보하고, 나머지 서비스는 스팟 인스턴스에 배치하여 비용을 절감했습니다.
 
가격에 대해 좀 더 이야기 해보자면, EB환경에서는 일반적으로 하나의 인스턴스에 하나의 애플리케이션이 배치됩니다. 이는 각 인스턴스의 유휴 자원을 다른 애플리케이션과 공유할 수 없다는 단점이 있습니다. 쿠버네티스를 통해 여러 어플리케이션이 서로 같은 인스턴스에서 실행될 수 있습니다. 이로 인해 유휴 자원에 파드를 배치하여 자원의 활용도를 극대화할 수 있게 됩니다. 같은 인스턴스에서 실행하지만, 애플리케이션 사이의 격리도 보장합니다.
 

Step 4. 운영 환경에서 동작하는 애플리케이션의 특징 분석하기

운영환경에서 도입하기 위해서 애플리케이션의 특징을 분석하는 것이 중요합니다. 저는 이를 두 가지 주요 측면으로 나누어 보았습니다.
 
첫 번째는 가용성의 허용 범위입니다. 가용성을 분석하는 이유는 최대한 스팟 인스턴스에 파드를 배치하여 비용을 절감하기 위함입니다. 스팟 인스턴스는 비용 효율적이지만, AWS가 언제든지 자원을 회수할 수 있기 때문에 가용성이 중요한 애플리케이션은 온디맨드 인스턴스에 배치해야 합니다.
 
두 번째는 애플리케이션의 최대 트랜잭션 시간입니다. 스케줄러가 실행되거나 외부 API를 호출할 때 긴 시간이 소요될 수 있습니다. 예를 들어, 스케줄러가 10분 이상 실행되고 완벽히 실행되어야 한다면, 해당 파드는 종료 시 10분의 시간을 보장받아야 합니다. AWS는 스팟 인스턴스가 회수되기 2분 전에 알림을 주기 때문에, 2분 내에 현재 트랜잭션을 graceful shutdown할 수 있는지 판단해야 합니다. 이는 가용성과도 밀접한 관련이 있습니다.
 
저는 이 두 가지 기준에 따라 세 가지 배치 방식을 선택했습니다.
 

1. 파드를 스팟 인스턴스에 배치하기

가용성이 중요하지 않거나, graceful shutdown이 1분 내로 가능한 애플리케이션들입니다. 스케줄러가 10분이상 소요되고 실패하여도 상관없다면 스팟 이용해도 좋습니다.
어드민과 같은 경우, 대부분 100% 가용성을 필요로 하지 않기 때문에 최대한 스팟 인스턴스에 배치하여 비용을 절감합니다.
위에서 테스트로 사용한 메시지 컨슈머도 마찬가지입니다. 해당 애플리케이션은 잠시 중지되어도 큰 문제가 발생하지 않습니다.
배송 완료 스케줄러 애플리케이션은 매 1시간마다 호출되고 10분 이상 소요되지만, 멱등성을 보장하고 완벽한 가용성이 필요하지 않기 때문에 스팟 인스턴스로 이동시켰습니다.
또 다른 애플리케이션은 30초 이내로 파드가 실행되고 모두 빠르게 트랜젝션이 완료되어 스팟에 배치했습니다.
 

2. 파드를 온디맨드 인스턴스에 배치하기

고객용 API 서버나 인증 서버 등 가용성이 매우 중요한 애플리케이션은 해당 디플로이먼트의 모든 파드를 온디맨드 인스턴스에 배치했습니다. 만약 파드 수가 적다면 더더욱 온디맨드에 배치하는 걸 고려해야합니다.
 

3. spot : on-demand = 1 : 1 배치하기

해당 전략은 디플로이먼트의 파드를 스팟와 온디맨드에 1:1로 배치하는 것입니다. 1번과 2번 경우의 중간에 위치한 애플리케이션입니다. 완벽한 가용성까지는 아니지만, 적절히 스팟에 분배할 여력이 되는 애플리케이션일 때 이용합니다. 비용절감과 가용성의 균형을 맞출 수 있습니다.
처음 쿠버네티스를 도입한다면, 모두 온디맨드에 배치하여 운영 경험을 쌓고 추후 1:1전략을 이용할 수 있습니다.
 
 

Step 5. DNS 가중치기반으로 카나리아 배포하기

애플리케이션을 파드에 배치하였다면, 실제 트래픽을 받아볼 차례입니다. 위에서 언급한 비동기 메시지 컨슈머는 큰 문제가 되지 않습니다. 문제는 HTTP 응답과 같이 동기로 응답을 줘야하는 상황에서, 트래픽을 EB에서 EKS 파드로 전환해야하는 것입니다.
AWS Route53을 이용해서 모든 애플리케이션의 도메인을 관리하고 있기 때문에, 편리하게 가중치 기반으로 카나리아 배포를 진행할 수 있습니다. 고객용 API, 인증서버는 가중치 기반으로 전환을 진행하였습니다.
 
https://docs.aws.amazon.com/ko_kr/Route53/latest/DeveloperGuide/routing-policy-weighted.html

가중치 기반 라우팅 - Amazon Route 53

이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.

docs.aws.amazon.com

 
 

Step 6. 사내 공유용 핸드북 작성

EB에서 EKS로 트래픽이 전환되면서 진정한 운영이 시작되었습니다. 운영 과정에서 다양한 문제가 발생할 수 있으며, 이러한 문제를 신속하게 발견하고 해결할 수 있어야 합니다. 이를 위해 클러스터 구축 시의 히스토리와 아키텍처를 팀 내에서 공유하는 것이 필수적입니다.
또한, 쿠버네티스에 익숙하지 않은 팀원을 위해 각 메니페스트를 정의하는 방법을 소개하는 것도 중요합니다. 이를 통해 팀원들이 쿠버 환경에서의 작업에 더 쉽게 적응할 수 있도록 도울 수 있습니다.
이러한 필요를 충족시키기 위해, 사내 공유용 핸드북을 작성하는 것을 추천합니다. 핸드북의 목적은 발생할 수 있는 문제나 궁금한 사항에 대해 팀원들이 쉽게 해결책을 찾을 수 있도록 돕는 것입니다. 핸드북에는 다음과 같은 내용을 작성했습니다.

  • 문제 해결 절차
  • 메니페스트 작성 가이드
  • 모니터링 방법

빠르게 핸드북의 내용을 찾는 게 중요하기 때문에, 하나의 문서에서 관리하는 것을 추천합니다.


[도입 후 성과]

1. 운영 효율성과 생산성 증가

이전에는 새로운 애플리케이션을 배포하기 위해 ElasticBeanstalk환경을 추가해야 했습니다. 이제는 쿠버네티스 메니페스트 정의만으로 빠르게 클러스터에 애플리케이션을 배포할 수 있습니다. 실험적인 프로젝트나 신규 기능을 빠르게 올릴 수 있습니다. 작은 서비스들이 많은 마이크로 서비스를 구축할 수 있는 초석을 마련했습니다.
또한 ArgoCD 기반으로 Gitops도 구축이 되어있어서, 코드 기반으로 빠르게 파드의 스펙이나 설정을 변경할 수 있고. 변경 히스토리도 관리할 수 있어 추적이 용이해졌습니다.
이제는 작은 서비스를 올리기 위해서 EB를 추가하거나, 하나의 거대한 의존성 덩어리 애플리케이션에 기능을 억지로 붙일 필요가 없어졌습니다. 작은 단위의 서비스를 독립적으로 쉽게 배포할 수 있어서, 서버 구조는 더욱 명확해졌습니다.
 

2. 비용 절감 효과

스팟 인스턴스를 적극적으로 활용하면서 40% 이상 비용 절감을 달성했습니다. 
애플리케이션의 특성을 잘 분석하고 Karpenter의 빠른 인스턴스 배치 덕분에 안정성은 유지하면서 가격은 절감하게 되었습니다.
 


[추가적인 내용 공유]

EKS환경에서 쿠버네티스를 도입하며 중요했던 내용/문서를 공유합니다.
 

1. Pod Readiness Gate

가용성이 굉장히 중요한 파드는 Pod Readiness Gate를 이용하는 것을 추천합니다.
AWS도 이를 제안하고 있습니다. [Utilize Pod readiness gates] 참고하시면 됩니다.
꼭 읽어보시길 추천합니다.
https://docs.aws.amazon.com/eks/latest/best-practices/load-balancing.html

Load Balancing - Amazon EKS

Load Balancing Load Balancers receive incoming traffic and distribute it across targets of the intended application hosted in an EKS Cluster. This improves the resilience of the application. When deployed in an EKS Cluster the AWS Load Balancer controller

docs.aws.amazon.com

https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/deploy/pod_readiness_gate/

Pod Readiness Gate - AWS Load Balancer Controller

Pod readiness gate AWS Load Balancer controller supports »Pod readiness gates« to indicate that pod is registered to the ALB/NLB and healthy to receive traffic. The controller automatically injects the necessary readiness gate configuration to the pod sp

kubernetes-sigs.github.io

 

2. MCP를 통해 클러스터 접근하기

쿠버네티스 클러스터와 LLM을 MCP를 통해서 연결할 수 있습니다. 자연어를 LLM에게 전달하면, 적절한 kubectl 명령을 통해 클러스터를 제어할 수 있습니다.
아직 쿠버네티스가 익숙하지 않은 팀원들이 편리하게 사용할 수 있습니다.
다만 적절한 권한 관리가 필수적입니다. 모든 권한을 가져서 실행하게 된다면 위험할 수 있습니다.
 
https://awslabs.github.io/mcp/servers/eks-mcp-server

Amazon EKS MCP Server | AWS MCP Servers

{`

awslabs.github.io

 
 
 

3. 리전 별 스팟 인스턴스 종료 빈도

스팟 인스턴스는 리전/인스턴스 타입마다 회수되는 빈도가 모두 다릅니다.
현재 운영중인 리전과 필요로 하는 인스턴스 타입으로 회수 빈도를 확인해보실 수 있습니다
 
https://aws.amazon.com/ko/ec2/spot/instance-advisor/

Amazon EC2 스팟 인스턴스: 컴퓨팅 사용 최적화

Amazon EC2 스팟 인스턴스를 통해 고객은 남은 EC2 용량을 활용하여 온디맨드 요금에 비해 최대 90%까지 비용을 절감할 수 있습니다. 스팟 인스턴스는 여러 인스턴스 유형에서 유연하게 실행할 수 있

aws.amazon.com

 
 

4. KEDA

쿠버네티스는 CPU, Memory 리소스 사용량을 기반으로 스케일링을 지원합니다.
다만, 실제 운영환경에서는 다른 지표를 통한 스케일링이 필요할 수 있습니다. (SQS의 사이즈, MySQL의 쿼리 결과 값 등등)
이때, KEDA를 이용해서 다양한 조건으로 스케일링이 가능합니다.
 
https://keda.sh/

KEDA

Application autoscaling made simple

keda.sh