본문 바로가기

DevOps/Kubernetes

[Kubernetes] Kubernetes 아키텍처 - kubectl 명령 이후의 동작

이 글은 Kubernetes를 처음 접하는 사람들이 "도대체 내가 입력한 명령이 어디로 가는 거지?" 라는 궁금증을 해소할 수 있도록, 아키텍처 전체를 순서대로 뜯어보는 글이다.


Kubernetes란 무엇인가?

컨테이너를 혼자 쓰면 어떤 문제가 생길까?

Docker를 처음 배우면 docker run 명령 하나로 컨테이너를 실행하는 것이 마법처럼 느껴진다. 하지만 실제 서비스를 운영하다 보면 금방 한계에 부딪힌다.

  • 컨테이너가 죽으면? → 직접 다시 실행해야 한다
  • 트래픽이 갑자기 몰리면? → 수동으로 컨테이너를 늘려야 한다
  • 서버가 10대, 100대면? → 어느 서버에서 무엇이 실행되는지 파악하기 어렵다
  • 배포 중 서비스를 중단하지 않으려면? → 복잡한 스크립트를 직접 작성해야 한다

이 문제들을 해결하기 위해 등장한 것이 컨테이너 오케스트레이션(Container Orchestration) 도구이고, 그 사실상의 표준이 Kubernetes(쿠버네티스, K8s) 이다.

Kubernetes의 핵심 철학: Desired State (원하는 상태)

Kubernetes의 가장 중요한 개념은 "선언적(Declarative) 방식" 이다.

방식 설명 예시
명령형 (Imperative) "이것을 지금 당장 해라" docker run nginx
선언형 (Declarative) "이런 상태여야 한다" kubectl apply -f pod.yaml

Kubernetes에게 "nginx Pod 3개가 항상 실행 중이어야 해" 라고 선언해두면, Kubernetes는 현실(Actual State)이 원하는 상태(Desired State)와 다를 때마다 자동으로 맞춰준다. Pod가 죽으면 새로 만들고, 서버가 추가되면 균형 있게 배치한다.


Kubernetes 클러스터 전체 구조

Kubernetes는 클러스터(Cluster) 단위로 운영된다. 클러스터는 크게 두 가지 역할의 노드로 구성된다.

구분 역할 비유
Control Plane 클러스터 전체를 관리하고 결정을 내림 회사의 경영진/관제탑
Worker Node 실제 애플리케이션(Pod)이 실행되는 곳 회사의 실무 직원들

아래는 이 글에서 다루는 전체 아키텍처 다이어그램이다. 각 컴포넌트가 어떤 위치에서 어떻게 연결되는지 먼저 큰 그림으로 확인하고 이후 섹션을 읽으면 이해가 훨씬 빠르다.

 

개발자(좌측)가 kubectl apply를 실행하면, Control Plane을 거쳐 Worker Node에 Pod가 생성되기까지의 전체 흐름을 나타낸다.


Control Plane 구성 요소

1. etcd — 클러스터의 데이터베이스(SSOT)

etcd는 Kubernetes의 모든 데이터를 저장하는 분산 Key-Value 데이터베이스이다. 클러스터에 어떤 Pod가 있는지, 어떤 노드가 존재하는지, 모든 설정 정보가 여기에 저장된다.

  • SSOT (Single Source of Truth): 클러스터의 "진짜 상태"는 오직 etcd에만 있다
  • 분산 합의 알고리즘 (Raft): 여러 etcd 인스턴스가 항상 같은 데이터를 유지
  • B+Tree 구조: etcd v3는 내부적으로 bbolt(B+Tree) 기반 저장소를 사용한다. B+Tree는 범위 쿼리와 순차 접근에 최적화되어 있다
  • gRPC 통신: etcd는 API Server와 gRPC 프로토콜로 통신한다. kubectl 등 외부 클라이언트는 API Server와 HTTPS(REST)로 통신한다. gRPC는 etcd↔API Server 구간 외에도 kubelet↔containerd(CRI) 구간에서도 사용된다

⚠️ etcd가 망가지면 클러스터 전체가 마비된다. 실제 운영 환경에서는 etcd를 3개 또는 5개의 홀수로 구성해 고가용성을 확보한다.


2. API Server — 클러스터의 중앙 게이트웨이

API Server는 Kubernetes의 모든 통신이 반드시 거쳐야 하는 중앙 허브이다. kubectl, Dashboard, 내부 컴포넌트 모두 API Server를 통해 통신한다.

API Server가 하는 일:

  1. 인증 (Authentication): "이 요청을 보낸 사람이 누구인가?"
  2. 인가 (Authorization / RBAC): "이 사람이 이 작업을 할 권한이 있는가?"
  3. 어드미션 컨트롤 (Admission Control): "이 요청이 클러스터 정책에 맞는가?"
  4. 상태 저장: 검증된 요청을 etcd에 저장
  5. 이벤트 발행: 다른 컴포넌트에게 "새 작업이 생겼다"고 알림


3. Scheduler — Pod의 배정 담당자

Scheduler는 "이 Pod를 어느 Node에 배치할 것인가"를 결정하는 컴포넌트이다. 단순히 빈 공간을 찾는 것이 아니라, 다양한 조건을 고려한다.

동작 방식: Scheduler는 API Server에 Pod 배치를 "요청받는" 것이 아니라, API Server를 Watch(감시) 하다가 nodeName이 비어있는 Pending Pod를 스스로 감지한다. 배치할 Node를 결정하면 해당 Pod의 spec.nodeName 필드를 업데이트하고, 이를 Watch하던 해당 Node의 kubelet이 Pod 생성을 시작한다.

Scheduler의 의사결정 과정:

Filtering 조건 예시:

  • 요청한 CPU/메모리가 남아있는가?
  • Pod에 지정한 nodeSelector와 일치하는가?
  • Node에 Taint가 있고 Pod에 Toleration이 없는가?

Scoring 조건 예시:

  • 자원이 균형 있게 사용되도록 점수를 계산한다
  • 같은 Deployment의 Pod가 여러 노드에 분산되도록 고려한다

4. Controller Manager — 클러스터의 자동화 루프 엔진

Controller Manager는 "원하는 상태"와 "현재 상태"를 계속 비교하며 자동으로 조정하는 컨트롤 루프들의 집합이다. 내부에는 수십 개의 컨트롤러가 동시에 동작한다.

Reconciliation Loop (조정 루프) 동작 원리:

예시: ReplicaSet Controller

  • Desired State: replicas: 3 (Pod 3개)
  • Actual State: Pod 2개 (1개가 죽음)
  • Action: Pod 1개 추가 생성 요청

5. Cloud Controller Manager — 클라우드와의 연결 다리

Cloud Controller Manager는 클라우드 공급자(AWS, GCP, Azure 등)의 API와 통신하는 컴포넌트이다. 온프레미스 환경에서는 없어도 된다.

담당 역할:

  • AWS ELB / GCP Load Balancer 자동 생성 (type: LoadBalancer Service 생성 시)
  • Node의 클라우드 인스턴스 상태 동기화 (인스턴스 종료 감지 → Node 자동 제거)
  • 클라우드 네트워크 라우팅 설정

클라우드 디스크(EBS, GCP PD 등)의 자동 프로비저닝은 CCM이 아니라 CSI(Container Storage Interface) Driver가 담당한다. CCM은 어디까지나 Node와 네트워크(LB) 관련 클라우드 리소스만 관리한다.


Worker Node 구성 요소 상세 해부

Worker Node는 실제 애플리케이션이 실행되는 서버이다. 각 Worker Node에는 kubelet, kube-proxy, Container Runtime(containerd), CNI 플러그인의 4가지 핵심 컴포넌트가 있다.


1. kubelet — Node의 관리자

kubelet은 각 Worker Node에서 실행되는 에이전트로, API Server를 Watch하다가 자신의 Node에 할당된 Pod를 감지해 실제로 생성/관리한다.

Watch 방식: API Server가 kubelet에게 직접 "Pod 만들어"라고 지시하는 것이 아니다. kubelet이 API Server를 지속적으로 감시하다가 spec.nodeName이 자신으로 설정된 Pod가 생기면 스스로 컨테이너 생성을 시작한다.

 

kubelet의 역할:

  • API Server에게 지속적으로 Node 상태 보고 (heartbeat)
  • 할당된 Pod의 컨테이너를 Container Runtime을 통해 실행
  • Pod의 헬스체크 수행 (liveness/readiness probe)
  • 볼륨 마운트 처리
  • 로그/메트릭 수집

kubelet은 Pod를 직접 실행하지 않고, containerd 같은 Container Runtime에게 실행을 위임한다.


2. kube-proxy — Service 트래픽의 교환원

kube-proxy는 각 Node에서 네트워크 규칙(iptables/IPVS)을 관리하여 Service로 들어오는 트래픽을 올바른 Pod로 라우팅한다.

핵심 포인트: ClusterIP라는 가상 IP는 실제로 특정 서버에 존재하지 않는다. kube-proxy가 iptables 또는 IPVS 규칙을 통해 이 가상 IP로 오는 트래픽을 실제 Pod IP로 변환(NAT)한다. IPVS 모드는 대규모 클러스터에서 iptables보다 훨씬 나은 성능을 제공한다.


3. Container Runtime — 컨테이너 실행 엔진

Container Runtime은 실제로 컨테이너를 실행하는 소프트웨어이다. Kubernetes는 CRI(Container Runtime Interface)라는 표준 인터페이스를 통해 다양한 런타임을 지원한다.

각 계층의 역할:

계층 역할
kubelet "이 컨테이너 이미지로 Pod 만들어줘" 라고 지시
containerd 이미지 관리, 컨테이너 생명주기 관리
containerd-shim 컨테이너마다 하나씩 생성되어 프로세스 감시
runc 실제로 Linux Namespace/cgroups를 이용해 컨테이너 격리 실행
Linux Kernel Namespace(격리), cgroups(자원 제한) 제공

OCI(Open Container Initiative)란?
컨테이너 이미지 형식과 런타임의 업계 표준 규격이다. 이 표준 덕분에 Docker로 만든 이미지를 containerd로도 실행할 수 있다.


4. CNI와 BIRD/BGP — Pod 네트워크의 도로 건설팀

CNI(Container Network Interface) 는 Pod에게 네트워크를 제공하는 플러그인 표준이다. 대표적인 구현체로 Calico, Flannel, Weave 등이 있다.

BIRD란?

  • Calico가 활용하는 독립 오픈소스 BGP 라우팅 데몬 (Bird Internet Routing Daemon)
  • Calico가 직접 만든 것이 아니라, 기존 오픈소스 BIRD 프로젝트를 내부적으로 사용한다
  • 각 Node를 BGP 라우터처럼 동작하게 만들어 Pod IP를 네트워크 전체에 광고
  • L3(네트워크 계층) 수준의 동적 IP 라우팅을 담당

BGP(Border Gateway Protocol)란?
인터넷에서 사용되는 동적 라우팅 프로토콜. Calico는 이 프로토콜을 사용해 "Pod X는 Node 2에 있다"는 정보를 클러스터 전체에 전파한다.


kubectl 명령 한 줄의 완전한 동작 흐름

이제 모든 구성요소를 이해했으니, kubectl apply -f pod.yaml 명령이 실제로 어떤 경로를 거치는지 처음부터 끝까지 추적해보자.


핵심 개념 정리

용어 사전

용어 설명
Pod Kubernetes에서 배포 가능한 가장 작은 단위. 1개 이상의 컨테이너 포함
Node Pod가 실행되는 서버 (물리/가상 머신)
Cluster Control Plane + Worker Node들의 집합
Namespace 클러스터 내의 논리적 격리 공간
Service Pod에 안정적인 네트워크 엔드포인트 제공
Deployment Pod의 배포/업데이트 방식을 선언하는 오브젝트
ReplicaSet 지정된 수의 Pod 복제본을 항상 유지
ConfigMap 정값을 컨테이너에 주입하는 오브젝트
Secret 민감한 정보(비밀번호, 토큰)를 안전하게 저장
PersistentVolume 컨테이너가 재시작되어도 유지되는 저장소

Kubernetes 핵심 원칙 요약


마무리

Kubernetes는 처음에는 복잡해 보이지만, 각 컴포넌트가 단일 책임 원칙에 따라 명확한 역할을 가지고 있다.

핵심만 기억하자:

  1. 모든 통신은 API Server를 통한다 — etcd, Scheduler, kubelet 모두 API Server와만 직접 통신
  2. etcd가 유일한 진실 — 클러스터의 모든 상태는 etcd에 있다
  3. Kubernetes는 선언적 — "어떻게"가 아닌 "무엇을" 원하는지 말하면 된다
  4. Controller Loop가 자동화의 핵심 — 현재 상태 ≠ 원하는 상태 → 자동 조정
  5. Pod는 Node에서 containerd → runc → 커널 순서로 실행된다

이 다섯 가지를 이해하면 Kubernetes의 나머지 기능들도 훨씬 자연스럽게 이해된다.


참고 자료