본문 바로가기
1. K8s Core & Architecture/1.1. 컨트롤 플레인 (Control Plane) 심층 분석

컨트롤 플레인 구성 요소의 리소스 할당(CPU/Memory) 최적화 전략

by K8s Architect 2026. 3. 17.

컨트롤 플레인 구성 요소의 리소스 할당(CPU/Memory) 최적화 전략

쿠버네티스 클러스터의 안정성은 전적으로 컨트롤 플레인(Control Plane)의 건강 상태에 달려 있습니다. 클러스터 규모가 확장되고 배포되는 워크로드의 변동성(Churn rate)이 커질수록, 컨트롤 플레인을 구성하는 핵심 컴포넌트(kube-apiserver, etcd, kube-controller-manager, kube-scheduler)들은 극심한 리소스 압박을 받게 됩니다. 리소스가 부족할 경우 API 응답 지연, 파드 스케줄링 실패, 심지어 클러스터 전체의 붕괴(Cascading Failure)로 이어질 수 있습니다. 본 가이드에서는 각 컨트롤 플레인 컴포넌트의 아키텍처적 특성을 분석하고, 이에 맞춘 최적의 CPU 및 메모리 할당 전략을 제시합니다.

1. 컨트롤 플레인 리소스 관리의 대원칙: Guaranteed QoS와 PriorityClass

모든 컨트롤 플레인 컴포넌트는 워커 노드의 일반적인 파드들과 격리되어야 하며, 운영체제나 Kubelet의 OOM(Out Of Memory) Killer로부터 최우선적으로 보호받아야 합니다.

  • Guaranteed QoS 클래스 적용: Kube-apiserver, etcd 등의 파드 매니페스트(일반적으로 Static Pod 형태)를 작성할 때, CPU와 Memory의 requests 값과 limits 값을 반드시 동일하게 설정해야 합니다. 리소스 요구량과 제한량이 일치할 때 해당 파드는 Guaranteed QoS 클래스를 부여받으며, 노드의 메모리가 부족해지더라도 가장 마지막에 종료되는 보호 대상이 됩니다.
  • CPU 스로틀링(Throttling) 방지: limitsrequests보다 높게 설정하는 Burstable 구성은 피해야 합니다. CPU 사용량이 한도를 초과할 경우 리눅스 커널의 CFS(Completely Fair Scheduler) Bandwidth Control 메커니즘에 의해 CPU 스로틀링이 발생하며, 이는 API 서버의 응답 지연과 etcd의 리더 선출 실패를 유발하는 가장 흔한 원인입니다.
  • PriorityClass 할당: 컨트롤 플레인 컴포넌트 매니페스트에 priorityClassName: system-cluster-critical 또는 system-node-critical을 명시하여, 리소스 경합 발생 시 다른 어떤 파드보다 우선적으로 스케줄링되고 노드에 유지되도록 보장해야 합니다.

2. Kube-apiserver 리소스 최적화 전략

Kube-apiserver는 컨트롤 플레인에서 가장 많은 메모리와 CPU를 소비하는 거대한 무상태(Stateless) 라우팅 엔진입니다.

2.1. 메모리 (Memory) 할당 최적화

API 서버 메모리 사용량의 70% 이상은 백엔드 etcd의 부하를 줄이기 위해 운용하는 'Watch Cache (Cacher)'와 클라이언트 요청 처리를 위한 'In-flight Request Payload'가 차지합니다.

  • 클러스터 내에 생성된 시크릿(Secret), 컨피그맵(ConfigMap), 커스텀 리소스(CRD)의 객체 수가 수만 개 단위로 증가하면, 이를 메모리에 적재하는 Watch Cache의 크기도 선형적으로 증가합니다.
  • --target-ram-mb 플래그를 사용하여 API 서버가 캐싱 메커니즘에 사용할 적정 메모리 한도를 명시적으로 지시할 수 있습니다. 예를 들어 --target-ram-mb=4096으로 설정했다면, 파드의 Memory Limits는 버퍼를 두어 최소 6GB~8GB 수준으로 넉넉하게 할당해야 OOM Killed를 방지할 수 있습니다.
  • 대량의 데이터를 한 번에 조회하는 LIST 요청은 순식간에 기가바이트 단위의 메모리를 할당하므로, 메모리 스파이크를 견딜 수 있는 충분한 여유 공간(Headroom) 확보가 필수적입니다.

2.2. CPU 할당 최적화

API 서버의 CPU 사이클은 주로 TLS 암호화/복호화, JSON/Protobuf 직렬화 및 역직렬화, 그리고 어드미션 컨트롤러(Admission Controller) 웹훅 검증에 소모됩니다.

  • 클라이언트의 동시 요청 수(Concurrent Requests)가 높을수록, 그리고 Mutating/Validating Webhook이 많을수록 CPU 요구량은 기하급수적으로 증가합니다.
  • 초당 수천 건의 API 요청이 발생하는 대규모 클러스터(노드 1,000대 이상)의 경우, API 서버 파드당 최소 4 Core에서 8 Core 이상의 CPU를 할당해야 병목을 피할 수 있습니다.
  • 성능 모니터링 중 apiserver_request_duration_seconds 지표가 증가하는데 메모리는 여유롭다면, CPU 스로틀링이 발생하고 있는지 container_cpu_cfs_throttled_seconds_total 메트릭을 최우선으로 점검해야 합니다.

3. etcd 리소스 최적화 전략

etcd는 디스크 I/O 속도가 가장 중요한 컴포넌트이지만, 합의 알고리즘(Raft)과 다중 버전 동시성 제어(MVCC)를 유지하기 위해 CPU와 메모리 역시 매우 민감하게 관리되어야 합니다.

3.1. 메모리 (Memory) 할당 최적화

etcd는 내부적으로 bbolt라는 스토리지 엔진을 사용하며, 성능을 극대화하기 위해 데이터베이스 파일 전체를 메모리에 매핑(mmap)하여 사용합니다.

  • etcd의 최대 데이터베이스 크기 공간 제한(--quota-backend-bytes)은 기본 2GB이며, 대규모 환경에서는 최대 8GB까지 늘려 사용합니다.
  • 파드의 메모리 requestslimits는 반드시 설정된 데이터베이스 쿼터보다 크게 설정해야 합니다. (예: 쿼터가 8GB라면 최소 16GB 이상 할당 권장). 만약 할당된 메모리가 데이터베이스 크기보다 작으면 리눅스 커널은 끊임없이 페이지 폴트(Page Fault)를 발생시키며 디스크에서 데이터를 다시 읽어와야 하므로, etcd의 응답 지연 시간이 치명적으로 증가합니다.

3.2. CPU 할당 최적화

etcd 노드 간의 하트비트(Heartbeat)는 기본적으로 100ms 단위로 교환됩니다.

  • etcd 파드에 할당된 CPU 리소스가 부족하여 프로세스가 제때 스케줄링되지 못하면, 노드 간 하트비트 전송이 지연되고 결국 리더 선출(Leader Election)이 불필요하게 반복되는 클러스터 불안정 상태(Split-brain 위험)를 초래합니다.
  • 따라서 etcd 파드에는 최소 2~4 Core 이상의 전용 CPU를 보장(Guaranteed)하여, 컨텍스트 스위칭 대기 시간을 최소화해야 합니다.

4. Kube-controller-manager 및 Kube-scheduler 최적화 전략

이 두 컴포넌트는 평상시에는 리소스 소모가 적지만, 클러스터에 대규모 이벤트(노드 대거 장애, 대형 디플로이먼트 롤아웃 등)가 발생할 때 리소스 사용량이 폭증하는 특징을 가집니다.

4.1. Kube-controller-manager

  • 내부적으로 노드 컨트롤러, 레플리카셋 컨트롤러 등 수십 개의 컨트롤러가 고루틴(Goroutine) 형태로 병렬 실행됩니다.
  • 각 컨트롤러는 API 서버로부터 데이터를 받아 로컬 Informer 캐시(메모리)에 저장하므로, 클러스터 내의 전체 파드 및 서비스 개수에 비례하여 메모리를 지속적으로 점유합니다.
  • 노드 장애 발생 시 파드를 축출(Eviction)하고 재생성하는 과정에서 엄청난 CPU 스파이크가 발생합니다. 평시 기준이 아닌 장애 조치(Failover) 상황의 최대 부하를 기준으로 CPU Limits(최소 2 Core 이상 권장)를 산정해야 복구 지연을 막을 수 있습니다.

4.2. Kube-scheduler

  • 스케줄러의 리소스 소비는 '초당 스케줄링해야 하는 파드의 수'와 '스케줄링 규칙의 복잡도'에 정확히 비례합니다.
  • NodeAffinity, PodTopologySpreadConstraints, 복잡한 Taint/Toleration 규칙이 많을수록 모든 워커 노드를 대상으로 스코어링(Scoring)을 수행하는 데 막대한 CPU 연산이 필요합니다.
  • CPU 리소스를 최적화하려면 스케줄러 설정 플래그 중 --percentage-of-nodes-to-score를 튜닝하는 것이 효과적입니다. 클러스터 노드가 수천 대일 때 모든 노드를 검사하지 않고, 설정된 비율(예: 10~20%)의 노드만 합격하면 스코어링을 중단하고 스케줄링을 확정하도록 하여 CPU 사이클을 극적으로 절약할 수 있습니다.

5. 지속적인 최적화를 위한 모니터링 체계와 VPA 적용

컨트롤 플레인의 리소스 요구량은 클러스터가 성장함에 따라 계속 변화하므로, 한 번의 정적 할당으로 끝내서는 안 됩니다.

  • 메트릭 기반 튜닝: 프로메테우스(Prometheus)를 통해 container_memory_working_set_bytes (실제 사용 중인 메모리)와 container_cpu_usage_seconds_total (CPU 사용률) 메트릭을 추적해야 합니다. 특히 OOM Killed 이력을 나타내는 kube_pod_container_status_last_terminated_reason 메트릭에 대한 알림(Alert) 설정은 필수입니다.
  • 프로파일링(Profiling): 리소스 누수(Memory Leak)가 의심되거나 비정상적인 CPU 사용이 관찰될 경우, Kube-apiserver 등에 내장된 pprof 엔드포인트(/debug/pprof/heap, /debug/pprof/profile)를 호출하여 어떤 내부 함수나 자료구조가 리소스를 점유하고 있는지 코드 레벨의 디버깅을 수행해야 합니다.
  • VPA (Vertical Pod Autoscaler) 추천 모드 활용: 컨트롤 플레인 컴포넌트는 대부분 Static Pod로 관리되므로 VPA가 직접 리소스를 자동 변경(Auto-update)하도록 구성하기는 까다롭습니다. 대신 VPA를 UpdateMode: "Off"로 배포하여 백그라운드에서 실행 빈도와 리소스 소모 패턴을 기계학습하게 한 뒤, VPA가 제안하는 target 리소스 추천 값을 참고하여 관리자가 정기적으로 정적 매니페스트(/etc/kubernetes/manifests/)의 리소스 할당량을 튜닝하는 방식이 가장 안전하고 효율적인 최적화 파이프라인입니다.