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

리더 선출(Leader Election) 메커니즘: 컨트롤 매니저와 스케줄러의 HA 구성

by K8s Architect 2026. 3. 18.

리더 선출(Leader Election) 메커니즘: 컨트롤 매니저와 스케줄러의 HA 구성

1. 컨트롤 플레인 고가용성(HA)과 리더 선출의 필요성

API 서버(Kube-apiserver)는 완벽한 무상태(Stateless) 프로세스이므로, 여러 대를 동시에 실행하고 로드밸런서를 통해 트래픽을 분산하는 액티브-액티브(Active-Active) 구성이 가능합니다. 하지만 Kube-controller-manager와 Kube-scheduler는 다릅니다. 이 컴포넌트들은 클러스터의 상태를 지속적으로 관찰하고 능동적으로 변경(예: 파드 생성/삭제, 노드 할당)을 가하는 주체입니다.

만약 세 대의 마스터 노드에서 세 개의 스케줄러가 동시에 액티브 상태로 동작한다면, 하나의 빈 노드에 동시에 파드를 할당하려 드는 치열한 경쟁 상태(Race Condition)와 데이터 충돌이 발생합니다. 컨트롤러 매니저 역시 파드 개수가 하나 부족할 때, 세 개의 컨트롤러가 동시에 파드 생성 요청을 보내어 파드가 세 개 생성되는 심각한 논리적 오류를 범하게 됩니다.

따라서 이들은 반드시 액티브-스탠바이(Active-Standby) 구조로 동작해야 합니다. 여러 인스턴스가 실행되더라도 오직 단 하나의 인스턴스만이 '리더(Leader)'가 되어 실제 작업을 수행하고, 나머지 인스턴스들은 대기(Standby) 상태로 리더의 헬스를 감시하는 방식입니다. 이 과정을 완벽하게 조율하는 분산 합의 기술이 바로 쿠버네티스의 '리더 선출(Leader Election)' 메커니즘입니다.

2. 분산 락(Distributed Lock)과 Lease API 오브젝트

리더 선출의 핵심은 여러 프로세스 중 하나만 획득할 수 있는 '분산 락(Lock)'을 구현하는 것입니다. 쿠버네티스는 외부 시스템(ZooKeeper, Redis 등)을 도입하지 않고, 자신이 가장 잘 다루는 etcd와 API 서버를 활용하여 이를 자체적으로 구현했습니다.

과거에는 이 락을 구현하기 위해 Endpoints나 ConfigMap 오브젝트의 어노테이션(Annotation) 필드를 편법으로 사용했습니다. 하지만 리더가 주기적으로 자신의 생존을 알리기 위해 어노테이션을 업데이트할 때마다, 해당 리소스를 감시(Watch)하는 수많은 시스템 컴포넌트들에게 불필요한 이벤트 트래픽이 폭주하는 성능 문제가 있었습니다.

이를 근본적으로 해결하기 위해 쿠버네티스 v1.14부터 coordination.k8s.io API 그룹에 속한 Lease(임대) 오브젝트가 공식적인 리더 선출의 표준으로 도입되었습니다. Lease 오브젝트는 오직 리더 선출의 상태만을 가볍게 기록하기 위해 설계되었으며, 네임스페이스 격리를 통해 클러스터 전체의 이벤트 노이즈를 획기적으로 줄여줍니다. kube-system 네임스페이스를 조회해보면 kube-schedulerkube-controller-manager라는 이름의 Lease 오브젝트를 직접 확인할 수 있습니다.

3. 리더 선출 동작 원리와 파라미터 최적화

리더 선출 메커니즘은 락을 획득하고, 유지하며, 잃었을 때 재선출하는 세 가지 라이프사이클로 동작합니다. 이 과정은 컴포넌트 실행 시 부여되는 세 가지 핵심 파라미터에 의해 정밀하게 통제됩니다.

  • --leader-elect-lease-duration (기본값 15초): 리더가 자신이 획득한 락(Lease)을 유지할 수 있는 유효 기간입니다. 리더가 갱신을 멈추면 이 시간이 경과한 후 락이 만료(Expire)된 것으로 간주됩니다.
  • --leader-elect-renew-deadline (기본값 10초): 현재 리더가 자신의 Lease 오브젝트를 갱신(Renew)하기 위해 API 서버에 하트비트를 보내는 주기입니다. 리더는 유효 기간이 끝나기 전에 지속적으로 renewTime을 최신화하여 자신이 살아있음을 증명해야 합니다.
  • --leader-elect-retry-period (기본값 2초): 대기(Standby) 중인 인스턴스들이 리더 자리가 비었는지(Lease가 만료되었는지) 확인하고, 비어있다면 락 획득을 시도하는 주기입니다.

세 대의 Kube-scheduler 인스턴스가 동시에 시작되면, 이들은 즉시 API 서버에 Lease 오브젝트 생성을 요청합니다. etcd의 강력한 일관성과 낙관적 동시성 제어(Optimistic Concurrency Control) 덕분에, 가장 먼저 도착한 단 하나의 요청만이 성공하여 오브젝트를 생성합니다. 이 승리자가 리더가 되며, 자신의 ID를 Lease 오브젝트의 holderIdentity 필드에 기록합니다. 나머지 패배자들은 대기 상태로 진입하여 주기적으로(2초마다) Lease 오브젝트를 조회하며 renewTime이 갱신되는지 감시합니다.

4. 페일오버(Failover) 시나리오와 스플릿 브레인 방지

운영 중 액티브 리더 노드에 커널 패닉이나 네트워크 단절 장애가 발생한 상황을 가정해 봅니다.

  1. 리더의 갱신 실패: 리더 프로세스는 더 이상 10초(renew-deadline)마다 Lease 오브젝트를 업데이트할 수 없습니다.
  2. 락 만료: API 서버의 Lease 오브젝트 renewTime이 업데이트되지 않은 채 15초(lease-duration)가 경과합니다.
  3. 새로운 경쟁 시작: 대기 중이던 두 대의 스탠바이 인스턴스들은 2초(retry-period)마다 Lease를 확인하다가, 만료 시간을 넘긴 것을 감지합니다. 이들은 즉시 기존 holderIdentity를 자신의 ID로 덮어쓰기 위한 API 업데이트(PUT) 요청을 보냅니다.
  4. 리더 교체: API 서버(etcd)에 먼저 도달한 요청이 승인되며, 해당 인스턴스는 즉시 활성화되어 스케줄링 메인 루프를 가동합니다. 클러스터의 중단 시간은 최대 lease-duration을 넘지 않습니다.

이 과정에서 가장 치명적인 오류인 스플릿 브레인(두 개의 리더가 동시에 활성화되는 현상)은 쿠버네티스의 resourceVersion 필드를 통해 완벽하게 차단됩니다. 스탠바이 인스턴스들이 락을 획득하려 할 때, 자신이 읽었던 시점의 resourceVersion을 함께 보냅니다. 만약 A 인스턴스가 찰나의 차이로 먼저 락을 획득하여 Lease가 업데이트되면 resourceVersion이 변경됩니다. 직후 도착한 B 인스턴스의 요청은 버전 불일치(Conflict, HTTP 409) 에러를 반환받고 락 획득에 실패하여 다시 대기 상태로 돌아갑니다.

5. 클라우드 및 대규모 환경에서의 주의사항

리더 선출 파라미터는 네트워크 환경에 매우 민감합니다. API 서버 앞단의 로드밸런서 타임아웃, etcd의 디스크 I/O 지연, 또는 클러스터 내부의 네트워크 패킷 드랍이 발생하면, 현재 리더가 정상적으로 동작하고 있음에도 불구하고 갱신 하트비트가 지연될 수 있습니다.

만약 하트비트 지연이 lease-duration을 초과하면, 스탠바이 인스턴스가 새로운 리더로 승격되는 불필요한 페일오버 현상(Leader Flapping)이 발생합니다. 이는 수만 개의 파드를 관리하는 컨트롤러 매니저가 메모리 캐시를 처음부터 다시 채우게 만들어(Cold Start) 클러스터 전체에 심각한 부하 스파이크를 유발합니다.

따라서 지연 시간(Latency)이 불안정한 멀티 리전(Multi-Region) 클러스터나 부하가 극심한 대규모 인프라에서는, 리더 갱신 실패로 인한 연쇄 장애를 방지하기 위해 lease-duration을 기본 15초에서 30초나 60초 이상으로 충분히 늘리고, 이에 비례하여 renew-deadline을 튜닝하는 보수적인 HA 아키텍처 설계가 필수적입니다.