컨트롤 플레인(Control Plane) 이해
쿠버네티스 컨트롤 플레인의 구성 요소인 API Server, etcd, Scheduler, Controller Manager의 역할과 상호 통신 방식, 고가용성(HA) 구성을 다룹니다.
지난 글에서 클러스터 전체 구조를 살펴봤다. 이번에는 컨트롤 플레인(Control Plane)을 더 깊이 들여다본다. 컨트롤 플레인은 클러스터의 두뇌로, 워커 노드에서 실행되는 파드들을 관리·제어하는 모든 결정이 이 곳에서 이루어진다.
컨트롤 플레인의 핵심 원칙
컨트롤 플레인의 작동 방식은 하나의 패턴으로 설명된다: Watch-Reconcile 루프다.
- etcd에 저장된 **원하는 상태(Desired State)**를 감시(Watch)
- 실제 상태(Actual State)와 비교
- 차이가 있으면 조정(Reconcile)해서 원하는 상태로 만들기
이 루프가 모든 컨트롤 플레인 컴포넌트의 기본 동작이다.
컴포넌트 간 통신 구조
중요한 설계 원칙이 있다: 모든 컴포넌트는 반드시 API Server를 통해서만 통신한다. Scheduler가 etcd에 직접 쓰거나, Controller Manager가 kubelet에 직접 명령하지 않는다. 모든 것이 API Server를 경유한다.
이 덕분에 단일 진입점에서 인증·인가·감사 로그를 일관되게 처리할 수 있다.
API Server 심층 이해
API Server는 K8s의 RESTful API를 제공하는 프론트엔드다. 들어오는 요청을 처리하는 순서는 다음과 같다.
요청 수신
→ 인증(Authentication): TLS 인증서, ServiceAccount 토큰, OIDC 등
→ 인가(Authorization): RBAC, ABAC 정책 확인
→ Admission Control: Validating/Mutating Webhook 처리
→ etcd 읽기/쓰기
→ 응답 반환
# API Server 로그에서 요청 흐름 확인
kubectl -n kube-system logs -l component=kube-apiserver | tail -30
# 특정 리소스에 대한 접근 권한 확인
kubectl auth can-i create pods
kubectl auth can-i create pods --as=system:serviceaccount:default:mysa
Admission Controller는 API Server의 관문 역할을 하는 플러그인이다. LimitRanger(리소스 기본값 설정), ResourceQuota(네임스페이스 자원 제한), PodSecurity(보안 정책) 같은 내장 컨트롤러 외에 커스텀 Webhook도 연결할 수 있다.
Controller Manager의 컨트롤러들
Controller Manager는 20개 이상의 컨트롤러를 하나의 프로세스로 실행한다. 대표적인 컨트롤러의 동작을 살펴보면 컨트롤 플레인의 핵심 메커니즘이 명확해진다.
ReplicaSet Controller: desired replicas = 3이고 현재 실행 중인 파드가 2개면, 파드 1개 생성 요청을 API Server에 보낸다.
Node Controller: 노드로부터 상태 보고가 40초 이상 오지 않으면 NotReady 상태로 전환하고, 5분이 지나면 해당 노드의 파드를 다른 노드로 재스케줄한다.
Deployment Controller: Deployment 오브젝트가 변경되면 새 ReplicaSet을 만들고 롤링 업데이트를 조율한다.
# 컨트롤러 매니저 파드 확인
kubectl -n kube-system describe pod -l component=kube-controller-manager
# 컨트롤러 매니저 리더 정보 (HA 환경)
kubectl -n kube-system get lease kube-controller-manager
Scheduler의 선택 알고리즘
Scheduler는 nodeName이 없는 파드를 감지하면 다음 두 단계로 노드를 선택한다.
Filtering (필터링): 파드를 실행할 수 없는 노드를 제거한다.
- 요청한 CPU/메모리를 수용할 여유가 없는 노드
- taint가 있는데 toleration이 없는 노드
- nodeSelector 조건을 만족하지 않는 노드
- 파드가 요구하는 볼륨을 마운트할 수 없는 노드
Scoring (스코어링): 남은 노드에 점수를 매겨 최고점 노드를 선택한다.
- 이미지가 미리 다운로드되어 있는 노드에 가중치
- 자원이 균등하게 분산될수록 높은 점수
- anti-affinity에 맞게 분산 배치
# Scheduler 로그 확인
kubectl -n kube-system logs -l component=kube-scheduler | grep -i "successfully assigned"
# 특정 파드가 어느 노드에 스케줄되었는지 확인
kubectl get pod <pod-name> -o wide
고가용성(HA) Control Plane
프로덕션 클러스터에서는 Control Plane을 3대 이상 구성한다. 단일 장애점(Single Point of Failure)을 제거하기 위해서다.
API Server: 무상태(stateless)이므로 여러 대를 그대로 병렬 실행하고, 앞에 Load Balancer를 두면 된다.
etcd: Raft 합의 알고리즘으로 클러스터링된다. 과반수 이상의 노드가 쓰기에 동의해야 커밋된다. 3대면 1대 장애, 5대면 2대 장애를 견딜 수 있다.
Scheduler / Controller Manager: 동시에 여러 인스턴스가 실행되더라도 하나만 리더(Active)로 동작하고 나머지는 Standby 상태를 유지하는 리더 선출(Leader Election) 방식을 사용한다.
# HA 환경에서 현재 리더 확인
kubectl -n kube-system get lease kube-scheduler -o yaml
# spec.holderIdentity 필드가 현재 리더 파드 이름
# kubeadm으로 HA 클러스터 초기화 예시
kubeadm init --control-plane-endpoint="lb.example.com:6443" \
--upload-certs
컨트롤 플레인 컴포넌트 모니터링
# kubeadm 클러스터에서 컨트롤 플레인 파드 상태
kubectl -n kube-system get pods | grep -E "apiserver|etcd|scheduler|controller"
# 컴포넌트 헬스 체크 (deprecated이지만 여전히 유용)
kubectl get componentstatuses
# API Server 헬스 직접 확인
curl -k https://localhost:6443/healthz
curl -k https://localhost:6443/livez
curl -k https://localhost:6443/readyz
지난 글: 쿠버네티스 클러스터 아키텍처
다음 글: etcd: 클러스터의 두뇌 저장소
읽어주셔서 감사합니다. 😊