클러스터를 관리하는 구성 요소 묶음.
-
kube-apiserver — 모든 요청의 단일 진입점. REST API
- 인증 → 인가 → 어드미션 → etcd 기록
- 유일하게 etcd 와 직접 말한다
-
etcd — 클러스터의 모든 상태를 담은 키-값 저장소
- 여기가 곧 '진실' 이다. 백업 대상 1순위
- Raft 합의를 쓰므로 홀수(3·5)로 구성한다
-
kube-scheduler — 새 파드를 '어느 노드에 둘지' 정한다
- 정하기만 하고 실행은 안 한다 (노드 이름을 기록할 뿐)
controller-manager 여러 컨트롤러를 한 프로세스에 모아 돌린다
- cloud-controller-manager — 클라우드 연동 (LB 생성 · 노드 등록 · 볼륨)
워커 노드 쪽
-
kubelet — 노드의 대리인. "내 노드에 배정된 파드" 를 받아 런타임에 실행시킨다
- 상태를 계속 보고한다
- kubelet 이 죽으면 그 노드의 파드는 계속 돌지만
- 새 배포·상태 보고가 멈춘다 (NotReady)
-
kube-proxy — 서비스 가상 IP 로 온 트래픽을 실제 파드로 보낸다
-
런타임 — containerd · CRI-O — 실제로 컨테이너를 만든다
모든 소통이 API 서버를 거친다
kubelet 도, 스케줄러도, 컨트롤러도 서로 직접 말하지 않는다 전부 API 서버를 통해 상태를 읽고 쓴다
- 장점 — 구성 요소를 갈아 끼우기 쉽다 (스케줄러를 직접 만들 수도 있다)
- 감사·인가를 한곳에서 건다
- 대가 — API 서버가 병목이자 단일 장애점이 된다
- HA 구성에서 API 서버를 여러 대 두고 앞에 LB 를 둔다
etcd 운영
- 정기 스냅숏 백업이 1순위 운영 과제다
- etcdctl snapshot save snap.db --endpoints=... --cacert=... --cert=... --key=...
- 홀수 노드로 구성한다 — 3대면 1대까지, 5대면 2대까지 견딘다
- 디스크 지연에 매우 민감하다 → SSD 필수
- 느려지면 리더 선출이 반복되고 클러스터 전체가 불안정해진다
HA 구성
-
API 서버 — 여러 대 + 앞에 LB. 무상태라 쉽게 늘린다
-
etcd — 3대 또는 5대 (홀수). 정족수가 필요하다
-
스케줄러·CM — 여러 대를 띄우되 리더 선출로 한 대만 활동한다
- (동시에 여러 대가 조정 루프를 돌면 충돌한다)
-
컨트롤 플레인이 전부 죽어도
- 이미 뜬 파드는 계속 돈다
- kube-proxy 규칙도 그대로라 서비스도 동작한다
- 다만 새 배포 · 자동 복구 · 스케일링이 멈춘다
-
"클러스터가 죽었다" 와 "서비스가 죽었다" 는 다른 말이다
static pod
kubeadm 클러스터에서 컨트롤 플레인은 static pod 로 뜬다
- /etc/kubernetes/manifests/*.yaml
- kubelet 이 이 디렉터리를 감시해 직접 띄운다
- API 서버 없이도 뜰 수 있어야 하므로 이 방식이다
API 서버가 죽어 kubectl 이 안 되면 이 파일과 crictl 로 직접 본다 crictl ps -a | grep apiserver crictl logs <id>
면접 함정
- ❌ "스케줄러가 파드를 실행한다" → 노드 이름만 적는다. 실행은 kubelet이다.
- ❌ "컨트롤 플레인이 죽으면 서비스가 멈춘다" → 이미 뜬 파드는 계속 돈다. 새 배포·복구가 멈출 뿐이다.