[k8s] 2. 클러스터 아키텍처와 컴포넌트 (클러스터, 마스터노드, 워커노드)
🌟 들어가며
쿠버네티스를 처음 접할 때 가장 먼저 마주하는 질문 중 하나는, “Kubernetes는 정확히 어떤 구조로 동작하는가?” 라는 것이다.
쿠버네티스는 단일 실행 파일이 아니라, 여러 개의 컴포넌트들이 유기적으로 동작하는 분산 시스템이다. 이러한 구조를 이해하면, 단순한 명령어 실행을 넘어서 클러스터를 어떻게 설계하고 운영해야 할지에 대한 감이 잡힌다.
🏗️ Kubernetes 클러스터란?
Kubernetes 클러스터는 하나 이상의 마스터 노드(Control Plane)와 여러 개의 워커 노드(Worker Node)로 구성된다.
- 마스터 노드는 클러스터의 두뇌 역할을 하며, 전반적인 상태를 감시하고 명령을 내린다.
- 워커 노드는 실제로 사용자의 컨테이너(Pod)를 실행하는 작업 공간이다.
이 구조는 마치 본사(마스터)와 지점(워커)으로 나뉜 조직처럼, 컨트롤 타워와 작업 수행 단위를 분리해 유연하고 확장 가능한 환경을 제공한다.
🧠 컨트롤 플레인(Control Plane) = 마스터노드(Master Node)의 구성 요소
컨트롤플레인 vs 마스터노드 용어 정리
컨트롤플레인(Control Plane)
- 클러스터의 상태를 관리하고, 워커 노드와 파드 등 모든 리소스를 제어하는 논리적/기능적 집합
- 주요 컴포넌트로는 kube-apiserver, etcd, kube-scheduler, kube-controller-manager 등이 있다
마스터노드(Master Node)
- 컨트롤플레인 컴포넌트가 실제로 실행되는 물리적(혹은 가상) 머신 또는 노드를 의미한다
- 즉, 컨트롤플레인 역할을 수행하는 서버를 마스터노드라고 부른다
전통적으로 “마스터노드”라는 용어를 사용했지만, 최근 Kubernetes 공식 문서와 커뮤니티에서는 “컨트롤플레인 노드(Control Plane Node)”라는 용어를 더 많이 사용한다. 여러 개의 마스터노드(컨트롤플레인 노드)를 두어 고가용성(HA) 구성을 할 수도 있다.
즉, 마스터노드 = 컨트롤플레인 역할을 하는 노드로, 실질적으로는 같은 의미로 사용된다.
API Server (kube-apiserver)
클러스터의 중앙 진입점이자, 유일한 통신 창구다. 모든 요청은 결국 API Server를 거쳐 처리되며, kubectl 명령어도 내부적으로 이 API를 호출한다. 클라이언트뿐 아니라 다른 컴포넌트들도 모두 API Server와 대화한다.
여기서의 API 요청이란 Kubernetes API 를 말하며, 파드의 컨테이너 내부의 어플리케이션으로 전달되는 API 요청과는 별개다.
Controller Manager (kube-controller-manager)
쿠버네티스의 자동화 엔진 역할을 한다. Deployment, ReplicaSet, Node 상태 등 다양한 리소스의 목표 상태와 실제 상태를 비교하고, 필요할 경우 새로운 Pod을 만들거나, 장애 난 노드를 대체하는 등의 작업을 수행한다.
컨트롤러는 “무언가가 잘못됐을 때 자동으로 복구해주는 메커니즘”을 담당한다.
Scheduler (kube-scheduler)
스케줄러는 새로운 Pod을 어떤 워커 노드에 배치할지 결정하는 역할을 한다. 노드의 자원 사용량, 레이블, 어피니티 등의 조건을 고려해 가장 적절한 위치를 찾는다.
“이 Pod은 어느 노드에 띄우는 게 가장 적합할까?”
→ 이 질문에 답하는 게 스케줄러의 일이다.
나는 CPU의 스케쥴링과 비슷한 의미로 이해했다.
etcd
etcd는 Kubernetes의 상태 정보를 저장하는 고가용성 키-값 저장소다. 모든 클러스터의 객체 정보(Pod, Service, ConfigMap 등)는 etcd에 저장되며, 이 데이터는 영속적이고 일관성을 보장해야 하므로 매우 중요하다.
운영 환경에서는 etcd의 백업과 복원 전략을 반드시 준비해야 한다.
⚙️ 워커 노드의 구성 요소
kubelet
워커 노드에서 동작하는 핵심 에이전트로, Pod이 정상적으로 실행되고 있는지 감시하고, API Server로부터 받은 명령에 따라 컨테이너를 실행하거나 종료시킨다.
“이 Pod 잘 실행 중이야? 문제가 생기진 않았어?”
→ kubelet이 계속 확인한다.
컨테이너 런타임
컨테이너를 실제로 실행해주는 프로그램이다. 예전에는 Docker가 주로 쓰였지만, 지금은 containerd, CRI-O 같은 런타임이 더 표준적으로 사용된다. Kubernetes는 CRI(Container Runtime Interface)를 통해 다양한 런타임을 추상화하여 지원한다.
왜 Docker 런타임 지원이 중단(deprecate) 되었나?
Kubernetes는 컨테이너를 실행하기 위해 “컨테이너 런타임”이라는 소프트웨어와 통신한다.
예전에는 Docker가 가장 널리 쓰였지만, Docker는 Kubernetes가 요구하는 표준 인터페이스(CRI, Container Runtime Interface)를 지원하지 않는다. 그래서 Kubernetes는 Docker와 직접 통신할 수 없고, 중간에 “Dockershim”이라는 별도의 어댑터 레이어가 필요했다.
Dockershim을 유지·관리하는 부담이 커지고, containerd, CRI-O처럼 CRI를 직접 지원하는 런타임이 발전하면서 Kubernetes는 Docker 런타임 지원을 중단하기로 했다고 한다.
엥, 그럼 Docker는 Kubernetes에서 완전히 안쓰이나?
당연히 아니다.
Docker는 여전히 이미지 빌드, 개발 환경 등에서 매우 많이 사용된다.
Docker로 만든 이미지(Dockerfile로 빌드한 결과)는 표준인 OCI(Open Container Initiative) 포맷이라 containerd, CRI-O 등 다른 런타임에서도 그대로 사용할 수 있다.
즉, 이미지 빌드와 개발에는 Docker를 계속 쓰고, Kubernetes 노드에서 컨테이너를 실행하는 런타임만 containerd, CRI-O 등으로 바뀐 것이다.
kube-proxy
각 노드에서 네트워크 트래픽을 적절한 Pod으로 라우팅해주는 역할을 한다. 예를 들어, Service를 통해 들어온 요청을 실제 Pod으로 전달할 때 경로를 조절해주는 게 kube-proxy다. iptables 또는 IPVS를 사용해 내부 라우팅 테이블을 설정한다.
service에 대해서는 나중에 정리해두겠지만, service 리소스를 생성하면 kube-proxy가 각 노드에서 해당 서비스의 ClusterIP와 포트에 대한 iptables 또는 IPVS 규칙을 자동으로 설정한다. 이 규칙들을 통해 서비스 IP로 들어오는 트래픽을 실제 파드(엔드포인트)로 라우팅한다.
kube-proxy는 Kubernetes API 서버를 감시하여 서비스나 엔드포인트(파드)가 추가/삭제/변경될 때마다 자동으로 네트워크 규칙을 갱신하기 때문에, 파드가 늘어나거나 줄어들어도 kube-proxy가 알아서 라우팅 테이블을 최신 상태로 유지한다.
따라서, 사용자는 특수한 네트워크 환경의 경우를 제외하고, Service와 파드(Deployment 등)만 선언하면 되고, kube-proxy의 별도 설정이나 수동 개입이 필요 없다.
🚀 클러스터 구성과 확장
쿠버네티스는 기본적으로 수평 확장에 매우 유리하게 설계되어 있다.
워커노드를 자유롭게 추가하거나 제거할 수 있으며, 컨트롤 플레인도 HA 구성을 통해 확장할 수 있다.
마스터 노드 역시 3개 이상 구성하면 고가용성이 가능하며, etcd 역시 클러스터링이 가능하다.
실무에서는 컨트롤 플레인 3개 + 워커 노드 N개 구성을 많이 사용한다고 한다.
근데 컨트롤 플레인은 왜 3개를 많이 사용할까?
마스터노드(컨트롤 플레인)의 확장시 홀수 개가 권장 된다
“홀수 개의 컨트롤 플레인 노드를 사용해 Split-Brain과 같은 네트워크 분할 문제를 방지하라” – Kubernetes 공식 문서
멘토링 때 멘토님께서 말씀해주신 내용이다. 이유와 내용은 이해했으나 자세한 이유는 몰라서 검색을 통해 찾아보았었다.
Kubernetes 클러스터에서 컨트롤 플레인을 홀수 개로 구성하는 것은 고가용성(HA)과 데이터 일관성을 보장하기 위한 핵심 원칙이다.
이는 내부 스토리지 시스템인 etcd와 RAFT 합의 알고리즘의 동작 방식과 직접적으로 연관되어 있다.
- etcd: 앞서 설명했듯이 클러스터의 모든 상태 정보(파드, 서비스, 노드 등)를 저장하는 분산 키-값 저장소이다.
- RAFT 알고리즘: etcd가 데이터 일관성을 유지하기 위해 사용하는 합의(Consensus) 알고리즘이다.
RAFT 알고리즘의 기본 원리
RAFT는 분산 시스템에서 여러 노드가 일관된 결정을 내리기 위한 합의 알고리즘이다.
-
리더 선출: 클러스터는 리더(Leader)를 선출해 모든 쓰기 작업을 리더가 주도한다. 이때 리더 외의 노드들은 Follower 노드가 된다.
-
로그 복제: 리더는 변경 사항을 팔로워(Follower) 노드에 복제하며, 투표를 통해 과반수(Quorum) 이상의 노드가 동의해야 작업이 완료된다.
-
장애 복구: 리더가 장애나면 새로운 리더를 선출하며, 로그의 일관성을 유지합니다. 새로운 리더 선출은 리더가 선출되었을 당시 다음 리더를 위한 후보에 우선순위를 두어 우선도에 따라 리더 노드가 결정된다.
투표 시, 후보자의 로그가 자신보다 최신일 때만 투표한다. 최초 클러스터 구성 시 모든 노드가 처음 시작하면 로그가 동일하게 비어 있는데, 각 노드의 Election Timeout 은 랜덤하게 설정되어 가장 짧은 타임아웃을 가진 노드가 먼저 후보자가 되어 자기 자신에게 투표하고, 다른 노드들에게 투표를 요청한다.
홀수 구성이 필수적인 이유
(1) 과반수(Quorum) 확보
- 과반수 = (전체 노드 수 / 2) + 1
- 예: 3노드 → 과반수 2, 5노드 → 과반수 3
- 홀수로 구성하면 최소한의 노드로 장애 허용 능력을 극대화한다.
- 3노드: 1개 장애 허용 → 2노드로 정상 동작
- 5노드: 2개 장애 허용 → 3노드로 정상 동작
(2) Split-Brain 방지
- 짝수 노드(예: 4개)에서 네트워크가 반으로 갈리면(2:2), 양쪽 모두 과반수를 확보하지 못해 시스템이 정지된다.
- 홀수 노드(예: 3개)는 항상 한 쪽이 우세하여 Split-Brain(동일한 수의 노드로 분할) 문제가 발생하지 않는다.
(3) 자원 효율성
- 홀수 노드는 같은 장애 허용 능력을 가진 짝수 노드보다 적은 자원으로 운영된다.
- 예: 3노드(1개 장애 허용) vs 4노드(1개 장애 허용) → 3노드가 더 효율적
따라서 홀수 구성은 RAFT 알고리즘의 과반수 규칙을 안정적으로 만족시키기 위한 필수적인 구성이다. 이를 통해 고가용성과 자원 효율성의 균형을 얻을 수 있으며, 이 원칙은 etcd 뿐만 아니라 ZooKeeper, Consul 등 모든 RAFT 기반 분산 시스템에 적용된다고 한다.
🎯 줄이며
쿠버네티스를 단순히 명령어 기반으로만 접근하다 보면, 실제 장애 상황이나 트러블 슈팅 시 구조를 모르면 어디서 무엇이 잘못됐는지를 알기 어렵게된다. 그래서 Kubernetes 클러스터가 어떤 구조로 되어있는지 정리해보았다. 특히, 멘토님이 말씀해주셨던 ‘홀수 구성’의 이유를 좀 더 자세히 찾아보면서 내부 동작 원리를 조금이나마 이해할 수 있던 시간이라 의미가 깊었다.

