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

Kube-apiserver 성능 튜닝과 병목 현상 해결 가이드

by K8s Architect 2026. 3. 17.

Kube-apiserver 성능 튜닝과 병목 현상 해결 가이드

쿠버네티스 클러스터의 규모가 수백 개의 노드와 수만 개의 파드로 확장됨에 따라, 모든 통신의 중심인 Kube-apiserver는 필연적으로 극심한 트래픽 부하에 직면하게 됩니다. API 서버의 응답 지연은 파드 스케줄링 지연, 컨트롤러 동기화 실패, 노드 NotReady 상태 등 클러스터 전체의 연쇄적인 장애를 유발합니다. 본 가이드에서는 Kube-apiserver의 성능을 저하시키는 주요 병목 지점을 분석하고, 이를 해결하기 위한 엔터프라이즈 수준의 튜닝 기법을 제시합니다.

1. 병목 현상의 진단과 핵심 메트릭 모니터링

성능 튜닝의 첫걸음은 직관이 아닌 메트릭(Metrics)을 기반으로 병목 구간을 정확히 진단하는 것입니다. Kube-apiserver는 내부적으로 방대한 프로메테우스(Prometheus) 메트릭을 노출합니다. 성능 저하가 의심될 때 가장 먼저 확인해야 할 핵심 지표는 다음과 같습니다.

  • apiserver_request_duration_seconds: API 요청 처리에 소요된 시간입니다. verb(GET, LIST, POST 등) 및 resource별로 구분하여 모니터링해야 합니다. 특히 LIST 요청의 지연 시간이 급증한다면 Watch Cache 누락이나 etcd 병목을 의심해야 합니다.
  • apiserver_current_inflight_requests: 현재 처리 중인 동시 요청 수입니다. 이 수치가 설정된 한계치에 지속적으로 머물러 있다면 클라이언트의 요청이 큐에서 대기하거나 버려지고(Drop) 있음을 의미합니다.
  • etcd_request_duration_seconds: API 서버가 etcd와 통신하는 데 걸리는 시간입니다. API 서버 자체의 CPU/메모리가 넉넉함에도 응답이 느리다면 십중팔구 etcd의 디스크 I/O 지연이 원인입니다.

2. API Priority and Fairness (APF)를 통한 트래픽 셰이핑

과거에는 --max-requests-inflight--max-mutating-requests-inflight 플래그를 통해 단순히 전체 동시 요청 수만 제한했습니다. 이 방식은 중요도가 낮은 외부 모니터링 도구의 과도한 LIST 요청이 클러스터 생존에 필수적인 Kubelet의 NodeStatus 업데이트 트래픽을 밀어내는 치명적인 문제를 안고 있었습니다.

APF(API Priority and Fairness)는 이러한 '시끄러운 이웃(Noisy Neighbor)' 문제를 해결하는 지능형 트래픽 제어 메커니즘입니다.

  • FlowSchema: 유입되는 요청의 주체(User, ServiceAccount)와 대상(Resource, Verb)을 분석하여 트래픽을 분류합니다.
  • PriorityLevelConfiguration: 분류된 트래픽에 우선순위(Priority)와 동시 처리 한도(Concurrency Shares)를 할당합니다.

튜닝 가이드:
기본 설정된 APF 정책은 대부분의 환경에 적합하지만, 대규모 CI/CD 파이프라인이나 무거운 커스텀 컨트롤러를 운영하는 경우 병목이 발생할 수 있습니다. apiserver_flowcontrol_rejected_requests_total 메트릭이 증가한다면 특정 컨트롤러가 너무 많은 요청을 보내 차단당하고 있다는 뜻입니다. 이때는 해당 서비스 어카운트를 위한 전용 FlowSchema를 생성하고, 시스템 핵심 컴포넌트(System:masters, Kubelet 등)와 격리된 별도의 PriorityLevelConfiguration을 할당하여 트래픽 대역폭을 보장해야 합니다.

3. Watch Cache (Cacher) 최적화 및 메모리 튜닝

Kube-apiserver는 클라이언트의 잦은 LISTWATCH 요청으로부터 백엔드 etcd를 보호하기 위해 내부에 인메모리 캐시(Watch Cache)를 운용합니다. 클라이언트가 API 요청 시 명시적으로 캐시 우회를 지시하지 않는 한, API 서버는 이 캐시에서 데이터를 즉시 반환하여 응답 속도를 극대화합니다.

튜닝 가이드:
클러스터에 생성되는 리소스(예: Secret, ConfigMap, Custom Resource)의 수가 수만 개 단위로 폭증하면, 기본 캐시 크기 한계로 인해 캐시 미스(Cache Miss)가 발생하고 모든 부하가 etcd로 쏟아집니다.

  • --watch-cache-sizes 플래그를 사용하여 특정 리소스의 캐시 크기를 명시적으로 늘려야 합니다. 예: --watch-cache-sizes=secrets#10000,configmaps#10000
  • 캐시 크기를 늘리면 API 서버 파드의 메모리 사용량이 급증하므로, 반드시 Kube-apiserver 파드의 리소스 제한(Limits)을 충분히(예: 8GB~16GB 이상) 상향 조정하여 OOM(Out Of Memory) Killed가 발생하지 않도록 방어해야 합니다.
  • 페이징(Paging) 및 청킹(Chunking) 활용: 클라이언트(컨트롤러) 개발 시 LIST 요청에 반드시 limit 파라미터를 포함하여, 한 번에 수만 개의 오브젝트를 메모리에 적재하려다 API 서버가 뻗는 현상을 방지해야 합니다.

4. etcd 병목 현상 해소

Kube-apiserver 성능 저하의 80% 이상은 사실 etcd의 성능 한계에서 비롯됩니다. API 서버를 아무리 튜닝해도 백엔드 저장소가 느리면 소용이 없습니다.

튜닝 가이드:

  • 디스크 I/O 최적화: etcd는 WAL(Write-Ahead Log)을 디스크에 fsync(동기화)해야만 다음 작업을 진행할 수 있습니다. etcd 데이터 디렉토리를 반드시 프로비저닝된 IOPS가 매우 높은 전용 NVMe SSD에 마운트하십시오.
  • 이벤트(Events) 리소스 분리: 클러스터에서 발생하는 수많은 상태 전환 로그(Events)는 디스크 쓰기 작업의 주범입니다. 대규모 클러스터에서는 코어 리소스를 저장하는 메인 etcd 클러스터와, 이벤트를 전담하여 저장하는 이벤트용 etcd 클러스터를 물리적으로 분리하는 --etcd-servers-overrides=/events#https://... 옵션 적용이 필수적입니다.
  • 컴팩션(Compaction)과 디프래그(Defragmentation) 주기를 최적화하여 데이터베이스 파일 크기 증가로 인한 성능 저하를 막아야 합니다.

5. 수평적 확장 (Scale-out)과 로드밸런싱 전략

Kube-apiserver는 완벽한 무상태(Stateless) 프로세스이므로 수평적 확장이 매우 자유롭습니다. CPU 사용률이 임계치를 넘어가면 인스턴스 개수를 3대, 5대, 10대 이상으로 유연하게 늘려 부하를 분산할 수 있습니다.

튜닝 가이드:

  • API 서버 인스턴스를 늘린 후에는 앞단에 위치한 로드밸런서(L4/L7)의 알고리즘을 튜닝해야 합니다. 단순한 라운드 로빈(Round Robin)보다는 '최소 연결(Least Connection)' 알고리즘을 사용하여, 무거운 Watch 스트리밍 커넥션이 특정 API 서버에 편중되는 현상을 방지하십시오.
  • HTTP/2 커넥션 재사용 최적화: 쿠버네티스 클라이언트(Client-go)는 HTTP/2 연결을 맺고 오랫동안 유지합니다. API 서버를 증설하더라도 기존 클라이언트들이 기존 연결을 끊지 않아 부하가 분산되지 않는 현상(Sticky Connection)이 발생할 수 있습니다. 이를 완화하기 위해 외부 로드밸런서 레벨에서 주기적으로 커넥션을 끊어주거나(Connection Draining), API 서버의 GOAWAY 프레임 전송 주기를 튜닝하는 고급 설정이 필요할 수 있습니다.
  • API Aggregation을 통한 부하 분산: Metrics Server나 대형 커스텀 컨트롤러 서버를 코어 API 서버와 통합하지 않고 API Aggregation Layer를 통해 백엔드로 분리함으로써, 메인 Kube-apiserver의 트래픽 라우팅 부하를 획기적으로 낮출 수 있습니다.