kubernetes-node-size 선택하기
https://learnk8s.io/kubernetes-node-size
쿠버네티스를 사용하는 입장에서 아래 기법을 적용중이긴하나 다시 한번 읽어보니 재밌어서 남김.
쿠버네티스 클러스터를 구성할 때 중요한 질문 중 하나는 "어떤 유형의 워커 노드를 사용하고, 몇 개나 필요한가?"입니다. 즉, 더 적은 수의 대형 노드를 사용할지 아니면 더 많은 수의 소형 노드를 사용할지에 대한 선택이 필요합니다.

클러스터 용량
쿠버네티스 클러스터는 개별 노드들을 하나의 큰 "슈퍼 노드"로 추상화합니다. 이 슈퍼 노드의 총 컴퓨팅 용량(CPU와 메모리)은 모든 구성 노드 용량의 합계입니다. 예를 들어, 총 8 CPU 코어와 32GB RAM이 필요한 클러스터를 구성할 때:
- 4개의 작은 노드(각 2 CPU, 8GB)
- 2개의 큰 노드(각 4 CPU, 16GB)
를 사용할 수 있습니다.
쿠버네티스 워커 노드의 예약 리소스
각 워커 노드는 kubelet(쿠버네티스 에이전트)을 실행하는 컴퓨팅 유닛입니다. kubelet, SystemD, 운영 체제는 모두 리소스를 필요로 하기 때문에 워커 노드의 모든 리소스가 파드 실행에 사용 가능한 것은 아닙니다.

일반적으로 CPU와 메모리 리소스는 다음과 같이 할당됩니다:
CPU 예약:
- 첫 번째 코어의 6%
- 다음 코어의 1%(최대 2코어까지)
- 다음 두 코어의 0.5%(최대 4코어까지)
- 4코어 이상의 코어는 각 0.25%
메모리 예약:
- 1GB 미만 머신의 경우 255 MiB
- 첫 4GB 메모리의 25%
- 다음 4GB 메모리의 20%(최대 8GB까지)
- 다음 8GB 메모리의 10%(최대 16GB까지)
- 다음 112GB 메모리의 6%(최대 128GB까지)
- 128GB 이상 메모리의 2%
또한 eviction threshold(보통 100MB)가 있어, 노드가 이 임계값을 초과하면 kubelet이 메모리 부족으로 파드를 제거하기 시작합니다.
예를 들어, 8GB 메모리와 2 vCPU 인스턴스의 경우:
- kubelet과 운영 체제에 70m vCPU와 1.8GB 메모리
- eviction threshold에 100MB
- 파드에 사용 가능한 리소스는 6.1GB 메모리와 1930 millicores

이는 전체 메모리의 약 75%만 워크로드 실행에 사용됨을 의미합니다. 게다가 Kube-proxy, Fluentd, NodeLocal DNSCache 같은 DaemonSet도 노드 크기에 관계없이 리소스를 소비합니다.

시나리오 분석: 단일 노드 vs 분산 배포
현대적인 마이크로서비스 아키텍처에서 흔히 볼 수 있는 상황을 가정해 보겠습니다. 각각 0.3 vCPU와 2GB 메모리를 요청하는 애플리케이션의 7개 Replicaset을 배포해야 한다고 상상해 보세요. 이 워크로드를 어떻게 배치하는 것이 최적일까요?
첫 번째 접근법은 모든 Replicaset을 단일 워커 노드에 집중시키는 것입니다. 이는 관리 복잡성을 줄이고 노드 간 통신 오버헤드를 최소화할 수 있습니다. 반면, 두 번째 접근법은 각 Replicaset을 별도의 노드에 분산시키는 전략입니다. 이는 고가용성과 장애 격리 측면에서 이점을 제공합니다.
단순 계산상으로는 7개 Replicaset에 필요한 총 리소스는 2.1 vCPU(7 × 0.3 vCPU)와 14GB 메모리(7 × 2GB)입니다.
7 x 300m = 2.1 vCPU
7 x 2GB = 14GB
그렇다면 4 vCPU와 16GB 메모리를 갖춘 인스턴스가 이 워크로드를 수용할 수 있을까요? 이 질문에 답하기 위해서는 kubelet의 리소스 예약 메커니즘을 자세히 이해해야 합니다.
kubelet의 리소스 예약 공식 해부
쿠버네티스 시스템에서 kubelet은 노드 안정성을 보장하기 위해 CPU와 메모리의 일부를 예약합니다. 이 예약 공식은 생각보다 복잡합니다.
CPU 예약의 경우:
- 첫 번째 코어의 6%: 60m
- 두 번째 코어의 1%: 10m
- 나머지 코어의 0.5%: 10m(2코어 × 0.5%)
- 총 예약 CPU: 80밀리코어
6% of the first core = 60m +
1% of the second core = 10m +
0.5% of the remaining cores = 10m
---------------------------------
total = 80m
이렇게 계산하면, 4 vCPU 인스턴스에서 실제 파드가 사용할 수 있는 CPU는 3.92 vCPU(4000밀리코어 - 80밀리코어)입니다. 이는 2.1 vCPU를 요구하는 우리 워크로드에 충분한 여유가 있습니다.
하지만 메모리 예약은 더 복잡한 패턴을 따릅니다:
- 첫 4GB 메모리의 25%: 1GiB
- 다음 4GB 메모리의 20%: 0.8GiB
- 다음 8GB 메모리의 10%: 0.8GiB
- 총 예약 메모리: 2.6GiB
25% of the first 4GB of memory = 1GB
20% of the following 4GB of memory = 0.8GB
10% of the following 8GB of memory = 0.8GB
--------------------------------------
total = 2.8GB -> 2.6GiB
여기에 쿠버네티스의 안정적인 운영을 위한 축출 임계값(eviction threshold)으로 100MB를 추가로 고려해야 합니다. 결과적으로 16GB 메모리 인스턴스에서 파드가 실제로 사용할 수 있는 메모리는 약 13.1GB(16GB - 2.8GB - 0.1GB)에 불과합니다.

리소스 부족의 현실과 해결책
이제 우리는 중요한 문제에 직면합니다. 7개 Replicaset이 요구하는 14GB 메모리에 비해, 사용 가능한 13.1GB는 부족합니다. 이는 단순히 '4 vCPU, 16GB 메모리 인스턴스면 충분하겠지'라는 직관적인 판단이 얼마나 위험할 수 있는지 보여줍니다.
이 상황에서 클라우드 환경이라면 다음 단계의 인스턴스 유형, 즉 4 vCPU와 32GB 메모리를 갖춘 인스턴스로 업그레이드해야 합니다. 이는 비용 증가를 의미하지만, 워크로드의 안정적인 운영을 위해서는 불가피한 선택입니다.

미세 조정의 예술: 단일 복제본 최적화
반면, 두 번째 시나리오에서는 각 노드에 단일 Replicaset만 배포하는 전략을 고려합니다. 이 경우 우리는 0.3 vCPU와 2GB 메모리를 요청하는 단일 Replicaset을 수용할 수 있는 가장 작은 크기의 VM 인스턴스를 찾아야 합니다.
이 접근법은 고가용성 측면에서 이점이 있지만, 각 노드마다 kubelet이 리소스를 예약하기 때문에 전체적인 리소스 효율성은 떨어질 수 있습니다. 작은 인스턴스에서는 예약되는 리소스의 비율이 상대적으로 더 높기 때문입니다.
예를 들어, 2 vCPU와 4GB 메모리를 갖춘 작은 인스턴스에서는 CPU의 약 4%(70밀리코어)와 메모리의 약 25%(1GB)가 예약됩니다. 이는 대형 VM 인스턴스에 비해 상대적으로 높은 비율입니다.
실무자를 위한 최적화 전략
이러한 분석을 바탕으로, 쿠버네티스 환경에서 리소스를 최적화하기 위한 몇 가지 실용적인 전략을 제시할 수 있습니다:
- 노드 크기의 전략적 선택: 작은 노드 여러 개보다 큰 노드 몇 개를 사용하면 큐블릿 예약으로 인한 오버헤드를 줄일 수 있습니다. 그러나 이는 장애 격리와 고가용성 측면에서 트레이드오프가 있습니다.
- 리소스 requests / limits 정확한 설정: 애플리케이션의 실제 리소스 사용량을 모니터링하고, 이를 바탕으로 리소스 requests / limits 을 정확하게 설정하세요. 과도한 requests / limits 설정은 리소스 낭비로 이어집니다.
- 노드 풀 다양화: 다양한 워크로드 특성에 맞춰 여러 유형의 노드 풀을 구성하는 것이 효율적일 수 있습니다. 메모리 전용 워크로드와 CPU 전용 워크로드 각각에 맞는 노드 풀을 적절히 분리하세요.
- Autoscaling 활용: 클라우드 환경에서는 클러스터 autoscaler와 수평적 파드 autoscaler를 활용하여 수요 변화에 동적으로 대응할 수 있습니다.
결론: 균형 잡힌 접근의 중요성
쿠버네티스 환경에서 리소스 관리는 단순한 산술 계산 이상의 복잡성을 가집니다. kubelet의 리소스 예약 메커니즘을 이해하고, 이를 클러스터 설계에 반영하는 것은 비용 효율성과 시스템 안정성 사이의 균형을 찾는 데 필수적입니다.
최적의 리소스 할당 전략은 워크로드 특성, 가용성 요구사항, 비용 제약 등 다양한 요소를 종합적으로 고려해야 합니다. 단순히 리소스 요청의 합계만으로 인스턴스 크기를 결정하는 것은 위험할 수 있으며, kubelet의 예약 메커니즘을 항상 염두에 두어야 합니다.
클라우드 네이티브 시대에 쿠버네티스 리소스 관리의 숨겨진 복잡성을 이해하는 것은 더 이상 선택이 아닌 필수입니다. 이러한 지식을 바탕으로 더 효율적이고 안정적인 클러스터를 설계하고 운영할 수 있을 것입니다.
'엔지니어' 카테고리의 다른 글
대량 트래픽과 분산 처리: 신화와 현실 (0) | 2025.04.10 |
---|---|
AI의 새로운 연결 시대: Agent2Agent(A2A)와 Model Context Protocol(MCP)의 상호 보완적 역할 (0) | 2025.04.10 |
끊임없는 선택과 책임, 소프트웨어 엔지니어의 삶 (0) | 2025.04.09 |
효율적인 IT 운영을 위한 9가지 통합 아키텍처 (0) | 2025.04.08 |
디지털 세계의 주소체계: URI, URL, URN의 (0) | 2025.04.07 |