Kubernetes, Control Plane

· 6분 읽기

Control Plane은 Desired State를 받아들이고, Actual State를 감시하며, 두 상태를 일치시키기 위한 결정을 내린다.

Architecture

flowchart TB
    User["kubectl / API 클라이언트"] --> API["kube-apiserver"]

    subgraph "Control Plane"
        API <-->|읽기/쓰기| etcd[(etcd)]
        SCH["kube-scheduler"] -->|Watch & Bind| API
        CM["kube-controller-manager"] -->|Watch & Update| API
        CCM["cloud-controller-manager"] -->|Watch & Update| API
    end

    subgraph "Worker Node"
        kubelet -->|Watch & Report| API
        kp["kube-proxy"] -->|Watch| API
    end

모든 컴포넌트는 kube-apiserver를 통해서만 통신한다.

etcd에 직접 접근하는 컴포넌트는 kube-apiserver뿐이다.

이 중앙 집중식 설계가 Kubernetes의 보안과 일관성을 보장한다.

kube-apiserver

kube-apiserver는 Kubernetes의 유일한 진입점이다.

모든 컴포넌트(kubectl, kubelet, scheduler, controller)는 API Server의 RESTful API를 통해 클러스터와 상호작용한다.

API 요청 처리 파이프라인

모든 API 요청은 이 파이프라인을 순차적으로 통과한다.

1. Authentication (인증)

요청자가 누구인지 확인한다. 여러 인증 방식을 동시에 사용할 수 있다:

  • X.509 클라이언트 인증서
  • Bearer Token (ServiceAccount Token)
  • OIDC (OpenID Connect)
  • Webhook Token Authentication

2. Authorization (인가)

인증된 사용자가 해당 작업을 수행할 권한이 있는지 확인한다:

  • RBAC(Role-Based Access Control): 가장 널리 사용되는 방식. Role/ClusterRole과 RoleBinding/ClusterRoleBinding으로 권한을 정의한다
  • Node Authorization: kubelet의 API 접근을 제한한다
  • Webhook Authorization: 외부 서비스에 권한 판단을 위임한다

3. Admission Control (승인 제어)

요청을 수정(Mutating)하거나 거부(Validating)할 수 있는 플러그인 체인이다.

flowchart LR
    REQ["요청"] --> M1["Mutating<br/>Admission"]
    M1 --> M2["Mutating<br/>Webhook"]
    M2 --> V1["Validating<br/>Admission"]
    V1 --> V2["Validating<br/>Webhook"]
    V2 --> OK["승인"]
  • Mutating Admission: 요청을 수정한다 (기본값 주입, 사이드카 주입 등)

  • Validating Admission: 요청을 검증하고 거부할 수 있다 (보안 정책 등)

Watch 메커니즘

컴포넌트들은 API Server에 Watch 요청을 보내고, 리소스 변경 시 실시간 알림을 받는다.

sequenceDiagram
    participant Client as kubelet / controller
    participant API as kube-apiserver
    participant WC as Watch Cache
    participant etcd

    Client->>API: Watch(resourceVersion=100)
    API->>WC: 캐시에서 이벤트 조회
    Note over WC: 슬라이딩 윈도우에<br/>최근 이벤트 보관
    WC-->>Client: ADDED event (rv=101)
    WC-->>Client: MODIFIED event (rv=102)

    Note over etcd: 새로운 변경 발생
    etcd-->>WC: 이벤트 전파
    WC-->>Client: DELETED event (rv=103)

Watch Cache:

  • API Server는 etcd의 부하를 줄이기 위해 Watch Cache를 유지한다

  • 리소스 타입별로 독립된 캐시 인스턴스가 존재한다

  • 슬라이딩 윈도우 방식으로 최근 이벤트를 보관하여 Watch 요청에 응답한다

  • LIST 요청도 Watch Cache에서 직접 응답할 수 있어 etcd 부하를 줄여준다

etcd

etcd는 Kubernetes 클러스터의 모든 상태 데이터를 저장하는 분산 키-값 저장소이다.

Pod, Service, ConfigMap, Secret 등 모든 리소스 정보가 etcd에 저장된다.

Raft 알고리즘으로 데이터 일관성을 보장하고, 모든 읽기가 가장 최신의 쓰기를 반영한다.

Watch 를 지원하기 때문에 키의 변경 사항을 실시간으로 구독할 수 있다.

flowchart LR
    Client["API Server"] --> Leader["Leader"]
    Leader -->|로그 복제| F1["Follower 1"]
    Leader -->|로그 복제| F2["Follower 2"]
    Leader -->|로그 복제| F3["Follower 3"]
    Leader -->|로그 복제| F4["Follower 4"]

etcd는 계층적 키-값 구조로 Kubernetes 리소스를 저장한다.

/registry/pods/default/nginx-abc123
/registry/pods/kube-system/coredns-xyz456
/registry/services/specs/default/my-service
/registry/deployments/default/my-app
/registry/secrets/default/my-secret

kube-scheduler

kube-scheduler는 새로 생성된 Pod를 어느 노드에 배치할지 결정하는 컴포넌트이다.

Pod가 생성되면 spec.nodeName이 비어있는 상태로 API Server에 등록되고, scheduler가 적절한 노드를 찾아 바인딩한다.

flowchart LR
    Q["스케줄링 큐"] --> Filter["Filtering<br />(필터링)"]
    Filter --> Score["Scoring<br />(점수화)"]
    Score --> Bind["Binding<br />(바인딩)"]

    Filter -.->|"부적합 노드 제거"| F1["Node A ✗"]
    Filter -.->|"부적합 노드 제거"| F2["Node B ✗"]
    Score -.->|"점수 비교"| S1["Node C: 80점"]
    Score -.->|"점수 비교"| S2["Node D: 95점 ★"]

Node Affinity

Pod가 특정 노드에 배치되도록 요청한다.

Pod Affinity / Anti-Affinity

Pod가 다른 Pod와 같은/다른 노드에 배치되도록 요청한다.

  • Affinity: 관련 Pod끼리 같은 노드/존에 배치 (캐시 활용, 지연 시간 감소)

  • Anti-Affinity: 같은 Pod를 다른 노드/존에 분산 (고가용성)

Taints & Tolerations

노드가 특정 Pod를 거부하는 메커니즘이다.

  • Taint: 노드에 설정. “나는 이런 Pod를 거부한다”

  • Toleration: Pod에 설정. “나는 이 Taint를 허용한다”

Priority와 Preemption

  • Priority: PriorityClass로 Pod의 중요도를 정의한다

  • Preemption: 높은 우선순위 Pod가 스케줄링될 수 없을 때, 낮은 우선순위 Pod를 축출하여 자리를 만든다

kube-controller-manager

kube-controller-manager는 여러 Controller를 하나의 프로세스에서 실행하는 컴포넌트이다.

각 Controller는 클러스터의 현재 상태를 원하는 상태로 수렴시키는 Reconciliation Loop(조정 루프)를 실행한다.

Controller 패턴

flowchart TB
    Observe["관찰 (Observe)<br />API Server Watch로<br />현재 상태 파악"]
    Diff["비교 (Diff)<br />현재 상태 vs<br />원하는 상태"]
    Act["조치 (Act)<br />차이를 해소하는<br />API 호출"]

    Observe --> Diff --> Act --> Observe

사용자가 “원하는 상태”를 선언하면, Controller가 지속적으로 현재 상태를 관찰하고 원하는 상태로 수렴시킨다.

주요 빌트인 Controller

Controller관찰 대상하는 일
ReplicaSetPod 수원하는 Pod 수를 유지 (부족하면 생성, 초과하면 삭제)
DeploymentReplicaSetRolling Update, Rollback 관리
StatefulSetPod순서 보장 생성/삭제, 안정적 네트워크 ID
DaemonSetNode, Pod모든 (또는 선택된) 노드에 Pod 1개씩 유지
JobPod완료될 때까지 Pod 실행, 실패 시 재시도
CronJob시간스케줄에 따라 Job 생성
NodeNode 상태노드 하트비트 모니터링, NotReady 노드의 Pod 축출
ServiceAccountNamespace새 Namespace에 기본 ServiceAccount 생성
EndpointSliceService, PodService 변경 시 EndpointSlice 갱신
NamespaceNamespaceNamespace 삭제 시 하위 리소스 정리

cloud-controller-manager

cloud-controller-manager는 클라우드 프로바이더 고유 로직을 Kubernetes 코어에서 분리하기 위한 컴포넌트이다.

베어메탈 클러스터처럼 클라우드 환경이 아닌 경우에는 cloud-controller-manager가 필요 없다.

원래 클라우드 관련 로직은 kube-controller-manager 안에 포함되어 있었다. 하지만 이 구조에서는 클라우드 프로바이더가 Kubernetes 릴리스 주기에 종속되는 문제가 있었다. cloud-controller-manager로 분리함으로써, 클라우드 프로바이더는 Kubernetes 코어와 독립적으로 기능을 개발하고 릴리스할 수 있게 되었다.

내장 Controller

  • Node Controller: 클라우드 API를 통해 노드의 존재 여부를 확인하고, 클라우드에서 삭제된 인스턴스를 클러스터에서 제거한다

  • Route Controller: 클라우드 인프라에 적절한 네트워크 라우트를 설정하여 노드 간 Pod 통신을 가능하게 한다

  • Service Controller: type: LoadBalancer Service 생성 시 클라우드 로드 밸런서를 프로비저닝하고, 삭제 시 해제한다

References