← 전체 기록으로

EKS 노드를 줄이기 전에 Pod의 Requests부터 살펴봤다

그루핀에서 DevOps Engineer로 근무하며 진행했던 작업 중 하나는 EKS 리소스 최적화였습니다.

당시에는 서비스가 새로 배포될 때마다 워커 노드가 과도하게 늘어나는 문제가 있었습니다. 노드 자동 확장에는 Karpenter를 사용하고 있었지만, 실제 컨테이너의 자원 사용량을 확인해 보니 배포 시 설정한 리소스 할당량과 차이가 있었습니다.

이 작업을 통해 알게 된 것은, 노드의 실제 사용률이 낮다고 해서 새로운 Pod를 배치할 공간이 충분한 것은 아니라는 점입니다.

실제 사용량과 스케줄러가 보는 자원은 다르다

처음에는 노드의 CPU와 메모리 사용량에 시선이 갔습니다. 하지만 Kubernetes의 스케줄러는 실시간 사용량만 보고 Pod를 배치하지 않습니다.

핵심 기준 중 하나는 컨테이너에 설정한 Requests입니다.

예를 들어 CPU를 실제로 적게 사용하는 컨테이너라도 requests.cpu가 크게 설정되어 있다면, 스케줄러는 그 요청량을 기준으로 배치 가능 여부를 판단합니다. 노드의 사용률 그래프에 여유가 보이더라도, 이미 배치된 Pod들의 Requests 합계 때문에 새 Pod를 배치하지 못할 수 있습니다.

이 경우 새 Pod는 배치할 공간을 기다리게 되고, 노드 자동 확장 시스템은 추가 노드가 필요하다고 판단할 수 있습니다.

즉, 확인해야 할 것은 두 가지였습니다.

  • 애플리케이션이 실제로 얼마나 사용하고 있는가
  • 배포 설정에서는 얼마나 필요하다고 선언하고 있는가

Requests와 스케줄링의 관계는 Kubernetes 공식 문서에서도 설명합니다.

Requests와 Limits를 같은 의미로 보면 안 된다

리소스 설정을 검토할 때는 Requests와 Limits도 구분해야 합니다.

설정주요 역할검토할 부분
Requests스케줄링 시 필요한 자원량의 기준실제 필요량보다 과도하게 설정되어 있는가
CPU Limits컨테이너가 사용할 수 있는 CPU 상한제한으로 인해 CPU throttling이 발생하는가
Memory Limits컨테이너의 메모리 사용 상한부족한 제한으로 OOM 종료가 발생하는가

노드가 불필요하게 늘어나는 문제에서 먼저 살펴볼 대상은 Requests였습니다. 그렇다고 Limits를 무조건 낮추는 방식으로 접근할 수는 없었습니다.

특히 메모리는 제한을 너무 낮게 잡으면 애플리케이션이 종료될 수 있습니다. 노드 수를 줄이는 것과 서비스에 필요한 자원을 부족하게 주는 것은 구분해야 했습니다.

CPU 제한과 메모리 제한의 동작 역시 Kubernetes 공식 문서를 기준으로 확인했습니다.

컨테이너별로 실제 사용량과 설정값을 비교했다

실제 작업에서는 Pod의 컨테이너 목록을 정리하고, 실사용량과 할당량을 비교했습니다. 기존 입사 회고에 적었던 것처럼 이 정보를 표로 정리하면서 차이가 큰 서비스를 확인했습니다.

클러스터 전체의 평균만 보면 어느 워크로드가 자원을 과도하게 요청하는지 찾기 어렵습니다. 컨테이너 단위로 내려가서 봐야 조정할 대상을 구분할 수 있었습니다.

이 과정에서 중요한 점은 모든 서비스에 같은 값을 적용하는 것이 아니었습니다. 서비스마다 필요한 자원이 다르므로, 사용량과 설정값 사이의 차이를 기준으로 조정 대상을 찾고 리소스 설정을 튜닝해 롤아웃했습니다.

이런 작업을 보통 Rightsizing이라고 부릅니다. 제게는 단순히 설정값을 줄이는 작업이라기보다, 애플리케이션이 필요로 하는 자원과 배포 설정 사이의 간격을 좁히는 작업에 가까웠습니다.

자동 확장이 잘 동작해도 비효율은 남을 수 있다

이번 경험에서 인상적이었던 부분은 자동 확장 도구가 있다고 해서 자원이 자동으로 효율화되는 것은 아니라는 점이었습니다.

Karpenter가 추가 노드를 준비하더라도, 워크로드가 필요 이상으로 큰 자원을 요청하고 있다면 그 요청을 충족하기 위해 노드가 늘어날 수 있습니다.

그래서 노드가 많아졌을 때 자동 확장 설정만 살펴보기보다, 그 앞단의 질문으로 돌아갈 필요가 있었습니다.

우리가 배포하는 Pod는 자신에게 필요한 자원을 적절하게 요청하고 있는가?

자동화는 선언한 요구사항을 처리하는 역할을 합니다. 그 요구사항이 적절한지는 운영자가 계속 확인해야 했습니다.

비용 절감은 리소스 설정을 이해하는 데서 시작됐다

그루핀에서는 EKS Pod의 리소스 할당량을 최적화하면서 워커 노드 수와 클라우드 비용을 줄일 수 있었습니다.

다만 노드 수가 줄었다는 사실을 그대로 비용 절감률로 표현할 수는 없습니다. 실제 비용은 노드의 인스턴스 유형과 실행 시간 등에도 영향을 받기 때문입니다.

이 글에서 남기고 싶은 결과는 특정 비율보다 불필요한 자원 요청을 줄여 추가 노드가 필요해지는 상황을 완화했다는 점입니다.

다음에는 무엇을 더 확인할까?

비슷한 최적화를 다시 진행한다면, 평상시 사용량뿐 아니라 다음 상황도 함께 확인하려고 합니다.

  • 애플리케이션 시작 시 필요한 자원
  • 트래픽이 증가하는 시간대의 사용량
  • 배포 중 기존 Pod와 새 Pod가 함께 실행될 때의 여유
  • CPU throttling, OOM 종료, 응답 시간 변화

평균 사용량이 낮다는 이유만으로 값을 줄이면, 평소에는 보이지 않던 문제가 배포나 트래픽 증가 시점에 나타날 수 있기 때문입니다.

리소스 최적화는 한 번 값을 정하고 끝내는 작업보다, 서비스가 달라질 때마다 다시 확인하는 운영 과정에 가깝다고 생각합니다.

마치며

이번 작업을 하면서 클라우드 비용과 Kubernetes 리소스 설정이 생각보다 가까이 연결되어 있다는 것을 배웠습니다.

노드 사용률만 보면 여유 있어 보였던 환경도, Pod의 Requests를 함께 확인하니 다른 모습으로 보였습니다. 노드를 얼마나 늘릴지 고민하기 전에, 각 워크로드가 얼마나 필요하다고 선언하고 있는지부터 살펴볼 필요가 있었습니다.

비용 최적화는 무조건 자원을 줄이는 일이 아니라, 서비스에 필요한 자원을 더 정확하게 이해하는 일이었습니다.