Skip to main content

Cluster Architecture

모든 통신은 API Server를 경유한다 — K8s 내부 동작의 핵심


📌 이 글의 목적

K8s 클러스터의 내부 구조를 컴포넌트 단위로 이해하는 것이 목표. 각 컴포넌트가 무슨 일을 하고, 어떻게 협력하는지를 알면 트러블슈팅, HA 설계, CKA 시험의 기반이 됨.


1. Control Plane 컴포넌트

1.1 API Server (kube-apiserver)

K8s의 중앙 허브. 모든 내부/외부 통신이 API Server를 경유함.

역할설명
REST API모든 오브젝트의 CRUD를 REST API로 제공
인증/인가요청자가 누구인지(인증), 무엇을 할 수 있는지(인가, RBAC) 확인
Admission Control요청을 최종 검증/변환 (Webhook, ResourceQuota 등)
etcd 접근유일하게 etcd와 직접 통신하는 컴포넌트
flowchart TB
kubectl["kubectl"] --> Auth["1. 인증<br/>(X.509, Token, OIDC)"]
Auth --> Authz["2. 인가<br/>(RBAC)"]
Authz --> Admission["3. Admission Control<br/>(Webhook, Validation)"]
Admission --> etcd_write["4. etcd에 저장"]

요청 처리 순서:

  1. 인증(Authentication) — 요청자가 누구인가 (인증서, 토큰)
  2. 인가(Authorization) — 이 사용자가 이 작업을 할 수 있는가 (RBAC)
  3. Admission Control — 정책 검증 (ResourceQuota 초과?, 필수 레이블 있는가?)
  4. etcd에 저장 — 검증 통과 후 상태 저장

1.2 etcd

분산 Key-Value 저장소. K8s의 모든 클러스터 상태가 저장됨.

항목설명
합의 알고리즘Raft — 리더 선출, 로그 복제, 과반수 합의
데이터모든 K8s 오브젝트 (Pod, Service, ConfigMap, Secret...)
접근API Server만 접근 (다른 컴포넌트는 API Server 경유)
권장 노드 수3, 5, 7 (홀수 — 과반수 합의를 위해)

etcd와 Proxmox Corosync 비교:

etcd (K8s)Corosync (Proxmox)
역할클러스터 상태 저장멤버십, 메시징, 쿼럼
합의RaftTotem (링 기반)
데이터Key-Value (모든 오브젝트)설정 파일 (pmxcfs)
쿼럼과반수 (3노드 → 2)과반수 (3노드 → 2)

etcd 토폴로지:

토폴로지설명추천
Stackedetcd가 Control Plane 노드에 같이 동작✅ 간편, 소~중규모
Externaletcd가 별도 서버에서 동작대규모, 더 안정적
flowchart TB
subgraph Stacked["Stacked etcd"]
M1["Master 1<br/>API Server + etcd"]
M2["Master 2<br/>API Server + etcd"]
M3["Master 3<br/>API Server + etcd"]
end

subgraph External_etcd["External etcd"]
MA["Master 1<br/>API Server"]
MB["Master 2<br/>API Server"]
MC["Master 3<br/>API Server"]
E1["etcd 1"]
E2["etcd 2"]
E3["etcd 3"]
MA & MB & MC --> E1 & E2 & E3
end

etcd 백업/복원 — CKA 시험 필출:

# 스냅샷 백업
ETCDCTL_API=3 etcdctl snapshot save /tmp/etcd-backup.db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key

# 스냅샷 복원
ETCDCTL_API=3 etcdctl snapshot restore /tmp/etcd-backup.db \
--data-dir=/var/lib/etcd-restored

# 복원 후 etcd의 data-dir을 변경하고 재시작

1.3 kube-scheduler

Pending 상태의 Pod를 어떤 노드에 배치할지 결정.

flowchart LR
Pending["Pending Pod"] --> Filter["필터링<br/>(부적합 노드 제거)"]
Filter --> Score["스코어링<br/>(적합 노드 순위)"]
Score --> Bind["바인딩<br/>(노드 배정)"]
단계역할예시
필터링조건을 못 맞추는 노드 제거CPU/메모리 부족, Taint 불일치, nodeSelector 불일치
스코어링남은 노드에 점수 부여리소스 여유, Affinity 일치도, 균등 분산
바인딩최고 점수 노드에 Pod 배정API Server에 업데이트

💡 VMware DRS와 유사한 역할이지만, DRS는 이미 실행 중인 VM을 재배치(밸런싱)하고, K8s Scheduler는 새 Pod의 최초 배치만 담당함. 실행 중인 Pod를 자동으로 옮기지는 않음(Descheduler 별도 설치 필요).

1.4 kube-controller-manager

선언된 상태와 현재 상태를 일치시키는 컨트롤 루프 모음.

flowchart LR
Observe["현재 상태 관찰"] --> Compare["선언된 상태와 비교"]
Compare -->|"불일치"| Act["조정 (Pod 생성/삭제 등)"]
Act --> Observe
Compare -->|"일치"| Observe
컨트롤러역할
Deployment ControllerDeployment → ReplicaSet 관리
ReplicaSet Controller원하는 수만큼 Pod 유지
Node Controller노드 상태 감시, NotReady 노드의 Pod 축출
Job ControllerJob/CronJob 관리
Endpoint ControllerService ↔ Pod 매핑
ServiceAccount Controller네임스페이스별 기본 SA 생성

1.5 cloud-controller-manager

클라우드 프로바이더(AWS, Azure, GCP)와 연동하는 컨트롤러. 온프레미스에서는 사용하지 않음.

역할예시
노드 관리클라우드 VM 상태와 K8s 노드 동기화
로드밸런서Service type=LoadBalancer → 클라우드 LB 생성
라우팅클라우드 네트워크 라우팅 테이블 관리

2. Worker Node 컴포넌트

2.1 kubelet

노드의 에이전트. API Server로부터 Pod 스펙을 받아 컨테이너를 실행/관리함.

역할설명
Pod 관리API Server에서 Pod 스펙 수신 → CRI를 통해 컨테이너 생성
상태 보고노드/Pod 상태를 API Server에 주기적으로 보고
Probe 실행Liveness/Readiness/Startup Probe 실행
볼륨 마운트PVC에 따라 볼륨을 Pod에 마운트
리소스 관리cgroups로 CPU/메모리 제한 적용
flowchart TB
API["API Server"] -->|"Pod 스펙"| Kubelet["kubelet"]
Kubelet -->|"CRI"| Runtime["Container Runtime<br/>(containerd)"]
Runtime --> Container["컨테이너"]
Kubelet -->|"CSI"| Storage["스토리지"]
Kubelet -->|"상태 보고"| API

2.2 kube-proxy

Service의 네트워크 규칙을 노드에 적용.

모드방식특징
iptables (기본)iptables 규칙으로 트래픽 라우팅대부분의 환경에서 충분
IPVSLinux IPVS(IP Virtual Server) 사용대규모(Service 1000+)에서 성능 우수

Service IP(ClusterIP)로 들어오는 트래픽을 실제 Pod IP로 분산하는 역할.

2.3 Container Runtime

실제 컨테이너를 실행하는 엔진.

런타임특징현재 위치
containerdDocker에서 분리된 경량 런타임✅ 가장 많이 사용
CRI-ORed Hat 주도, OCI 표준 전용OpenShift
DockerK8s 1.24에서 제거 (Dockershim)❌ 사용 불가

⚠️ "K8s에서 Docker를 못 쓴다"는 것은 Docker 데몬을 런타임으로 쓸 수 없다는 뜻. Docker로 빌드한 이미지는 OCI 표준이므로 containerd에서 정상 실행됨.


3. 통신 흐름 상세

3.1 Deployment 생성 전체 흐름

sequenceDiagram
participant User as kubectl
participant API as API Server
participant etcd as etcd
participant DC as Deployment<br/>Controller
participant RSC as ReplicaSet<br/>Controller
participant Sched as Scheduler
participant KL as kubelet
participant CR as containerd

User->>API: 1. kubectl apply -f deploy.yaml
API->>API: 2. 인증 → 인가 → Admission
API->>etcd: 3. Deployment 저장

DC->>API: 4. Deployment 변경 감지 (Watch)
DC->>API: 5. ReplicaSet 생성 요청
API->>etcd: 6. ReplicaSet 저장

RSC->>API: 7. ReplicaSet 변경 감지
RSC->>API: 8. Pod 생성 요청 (Pending)
API->>etcd: 9. Pod 저장 (nodeName 없음)

Sched->>API: 10. Pending Pod 감지
Sched->>Sched: 11. 필터링 → 스코어링
Sched->>API: 12. Pod에 nodeName 배정
API->>etcd: 13. Pod 업데이트 (nodeName 있음)

KL->>API: 14. 자기 노드의 Pod 변경 감지
KL->>CR: 15. CRI로 컨테이너 생성
CR->>KL: 16. 컨테이너 Running
KL->>API: 17. Pod 상태 → Running
API->>etcd: 18. 상태 업데이트

핵심 패턴:

  • 모든 컴포넌트는 API Server를 Watch하여 변경을 감지함
  • 각 컨트롤러는 자기 관심사만 처리 (Deployment Controller는 ReplicaSet만, Scheduler는 Pending Pod만)
  • 이벤트 드리븐 — 폴링이 아니라 Watch 기반

3.2 Watch 메커니즘

flowchart LR
Controller["컨트롤러"] -->|"Watch 등록"| API["API Server"]
API -->|"변경 이벤트 스트리밍"| Controller
Controller -->|"조정 액션"| API
  • 컨트롤러가 API Server에 Watch를 등록하면, 관련 오브젝트가 변경될 때마다 실시간으로 이벤트를 받음
  • 내부적으로 Informer 패턴 사용 — 로컬 캐시 + Watch 조합으로 API Server 부하 최소화

4. HA 구성

4.1 Control Plane HA

flowchart TB
LB["로드밸런서<br/>(HAProxy/Nginx/클라우드 LB)"]

subgraph CP["Control Plane (×3)"]
M1["Master 1<br/>API Server + etcd"]
M2["Master 2<br/>API Server + etcd"]
M3["Master 3<br/>API Server + etcd"]
end

subgraph Workers["Worker Nodes"]
W1["Worker 1"]
W2["Worker 2"]
W3["Worker 3"]
end

LB --> M1 & M2 & M3
W1 & W2 & W3 --> LB
컴포넌트HA 방식
API Server여러 인스턴스 + 앞단 로드밸런서. Stateless라 단순
etcd3/5/7 노드 Raft 클러스터. 과반수 유지 필수
SchedulerLeader Election — 하나만 Active, 나머지 Standby
Controller ManagerLeader Election — 하나만 Active, 나머지 Standby

4.2 Worker Node 장애 처리

flowchart LR
NodeFail["Worker 노드 장애"] --> NodeCtrl["Node Controller<br/>NotReady 감지"]
NodeCtrl -->|"5분 대기<br/>(node-monitor-grace-period)"| Evict["Pod 축출<br/>(Eviction)"]
Evict --> Reschedule["Scheduler가<br/>다른 노드에<br/>Pod 재배치"]
단계시간설명
kubelet 상태 보고 중단즉시노드가 NotReady로 전환
대기~5분일시적 네트워크 장애일 수 있으므로 대기
Pod 축출5분 후Taint(unreachable) 적용 → Pod 삭제
재스케줄링즉시ReplicaSet Controller가 부족한 Pod를 감지 → Scheduler가 새 노드에 배치

5. Proxmox/VMware 위에 K8s 배포

5.1 VM 설계 가이드

역할권장 스펙수량
Master2 vCPU, 4GB RAM, 50GB 디스크3 (HA)
Worker4+ vCPU, 8+ GB RAM, 100GB 디스크3+
LB (선택)1 vCPU, 1GB RAM1~2

5.2 kubeadm 기반 설치 흐름

flowchart TD
Prereq["1. 사전 준비<br/>(swap off, 커널 모듈, sysctl)"]
Runtime["2. Container Runtime 설치<br/>(containerd)"]
KubeTools["3. kubeadm, kubelet, kubectl 설치"]
Init["4. kubeadm init<br/>(첫 번째 Master)"]
CNI["5. CNI 설치<br/>(Calico/Cilium)"]
JoinCP["6. 나머지 Master join"]
JoinWorker["7. Worker join"]
Verify["8. 클러스터 검증"]

Prereq --> Runtime --> KubeTools --> Init --> CNI --> JoinCP --> JoinWorker --> Verify
# 사전 준비 (모든 노드)
swapoff -a
modprobe br_netfilter overlay
cat <<EOF | tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system

# kubeadm init (첫 번째 Master)
kubeadm init \
--control-plane-endpoint "lb.k8s.local:6443" \
--upload-certs \
--pod-network-cidr=10.244.0.0/16

# kubeconfig 설정
mkdir -p $HOME/.kube
cp /etc/kubernetes/admin.conf $HOME/.kube/config

# CNI 설치 (Calico 예시)
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/calico.yaml

# Worker join
kubeadm join lb.k8s.local:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash>

5.3 Proxmox + K8s 연동 포인트

연동방법
VM 생성 자동화Terraform bpg/proxmox + Cloud-Init
K8s 설치 자동화Ansible (kubespray)
스토리지Ceph CSI → Proxmox Ceph 연동, NFS CSI
네트워크Proxmox Bridge/VLAN + Calico/Cilium CNI
GPU PassthroughProxmox IOMMU → K8s GPU Operator

정리

컴포넌트위치핵심 역할
API ServerControl Plane모든 통신의 관문. 유일한 etcd 접근자
etcdControl Plane클러스터 상태 저장. Raft 합의
SchedulerControl PlanePending Pod → 적합 노드에 배치
Controller ManagerControl Plane선언 상태와 현재 상태를 맞추는 컨트롤 루프
kubeletWorkerPod 생명주기 관리. CRI로 런타임 호출
kube-proxyWorkerService 네트워크 규칙 적용 (iptables/IPVS)
Container RuntimeWorker실제 컨테이너 실행 (containerd)

다음 글

→ #3 Pod & Workload Resources — Pod 생명주기, Deployment, StatefulSet, DaemonSet


🔗 관련 문서


📝 참고 자료