본문 바로가기
1. K8s Core & Architecture/1.1. 컨트롤 플레인 (Control Plane) 심층 분석

클러스터 상태(State)와 명세(Spec)의 차이: 선언적 API의 본질

by K8s Architect 2026. 3. 19.

클러스터 상태(State)와 명세(Spec)의 차이: 선언적 API의 본질

쿠버네티스를 처음 접하는 개발자나 시스템 엔지니어가 가장 먼저, 그리고 가장 깊이 이해해야 하는 개념은 바로 '선언적(Declarative) API'의 작동 방식입니다. 쿠버네티스는 수천 대의 서버와 수만 개의 컨테이너를 관리하기 위해 기존의 '명령형(Imperative)' 접근 방식을 철저히 배제하고 선언적 패러다임을 채택했습니다. 이 선언적 아키텍처를 지탱하는 두 개의 핵심 기둥이 바로 쿠버네티스 리소스 객체 내부에 존재하는 Spec(명세)Status(상태)입니다. 이 두 필드의 차이점과 상호작용 원리를 완벽히 이해하는 것은 쿠버네티스의 자가 치유(Self-healing) 및 자동화 메커니즘을 마스터하는 첫걸음입니다.

1. 명령형(Imperative) 인프라의 한계와 선언적(Declarative) 패러다임

전통적인 스크립트 기반의 인프라 관리나 도커(Docker) 명령어는 전형적인 '명령형' 방식입니다. "A 서버에 접속해라", "B 컨테이너를 실행해라", "네트워크를 연결해라"와 같이 수행해야 할 작업의 '절차(How)'를 시스템에 직접 지시합니다. 이러한 방식은 시스템의 규모가 작을 때는 직관적이지만, 대규모 분산 시스템에서는 치명적인 한계를 드러냅니다. 명령을 수행하는 도중 네트워크가 끊기거나 서버가 다운되면, 스크립트는 중간에 실패하게 되고 시스템은 어떤 상태에 머물러 있는지 예측할 수 없는 미궁에 빠집니다.

반면 쿠버네티스의 '선언적' 방식은 작업의 절차를 지시하지 않습니다. 대신 시스템이 최종적으로 도달해야 할 '목표 상태(What)'만을 API 서버에 선언(Declare)합니다. "나는 Nginx 웹 서버 컨테이너가 항상 3개 실행되고 있기를 원한다"라는 명세서(YAML)를 제출하기만 하면, 쿠버네티스 내부의 컨트롤러들이 현재 시스템을 관찰하고 알아서 절차를 계산하여 목표를 달성해 냅니다.

2. Spec (명세): 사용자가 요구하는 '원하는 상태(Desired State)'

모든 쿠버네티스 워크로드 리소스(Deployment, StatefulSet, Pod 등)의 YAML 매니페스트에는 spec이라는 핵심 필드가 존재합니다.

  • 정의: spec은 클러스터 관리자나 애플리케이션 개발자가 쿠버네티스 시스템에 요구하는 '원하는 상태(Desired State)'를 정의한 명세서입니다.
  • 작성 주체: 오직 사용자(또는 CI/CD 파이프라인과 같은 클라이언트)만이 spec을 작성하고 수정할 권한을 가집니다.
  • 내용: 사용할 컨테이너 이미지의 버전, 할당할 CPU와 메모리 리소스의 제한량(Limits/Requests), 유지해야 할 파드의 개수(Replicas), 파드가 배포될 노드의 조건(NodeAffinity) 등 시스템이 갖추어야 할 모든 조건이 포함됩니다.
  • 불변성 및 버전 관리: spec에 기록된 내용은 etcd에 저장되며, 사용자가 명시적으로 API를 호출하여 수정(Update/Patch)하기 전까지는 절대 변하지 않는 '진실의 근원(Source of Truth)' 역할을 합니다. 이러한 특성 덕분에 spec 매니페스트 파일들을 Git 저장소에 올려 버전 관리를 하는 GitOps 아키텍처가 가능해집니다.

3. Status (상태): 시스템이 보고하는 '현재 상태(Current State)'

사용자가 spec을 정의하여 API 서버에 제출하면, 쿠버네티스는 해당 오브젝트 메타데이터 안에 status라는 새로운 필드를 동적으로 생성하고 지속적으로 업데이트합니다.

  • 정의: status는 쿠버네티스 클러스터 인프라 위에서 해당 리소스가 실제로 구동되고 있는 '현재 상태(Current State)'를 나타냅니다.
  • 작성 주체: 사용자는 절대 status 필드를 직접 수정할 수 없습니다. 이 필드는 오직 쿠버네티스 시스템 내부의 컴포넌트들(Kubelet, Kube-controller-manager 등)만이 읽고 쓸 수 있는 읽기 전용(Read-only) 데이터입니다.
  • 내용: 파드가 현재 어느 워커 노드에 스케줄링되었는지, 컨테이너의 IP 주소는 무엇인지, 컨테이너가 정상적으로 실행 중(Running)인지 아니면 에러로 인해 재시작 대기 중(CrashLoopBackOff)인지 등 실시간 런타임 정보가 낱낱이 기록됩니다.

4. 선언적 API의 심장: 조정 루프 (Reconciliation Loop)

SpecStatus라는 두 개의 데이터가 준비되면, 쿠버네티스의 진정한 마법인 '조정 루프(Reconciliation Loop)'가 작동을 시작합니다. 컨트롤 플레인에 위치한 수많은 컨트롤러(Controller)들은 자신이 담당하는 리소스를 대상으로 무한한 반복 루프를 돌며 다음 세 가지 작업을 수행합니다.

  1. 관찰 (Observe): 컨트롤러는 API 서버의 Watch 메커니즘을 통해 etcd에 저장된 리소스의 spec(원하는 상태)과 실제 클러스터 노드들로부터 보고되는 status(현재 상태)를 실시간으로 모니터링합니다.
  2. 비교 및 차이 분석 (Diff): specstatus의 값을 비교합니다. 시스템이 정상적이라면 이 두 값은 완전히 일치해야 합니다. (예: spec.replicas = 3, status.readyReplicas = 3)
  3. 조정 (Act / Reconcile): 만약 두 값 사이에 불일치(Drift)가 발견되면, 컨트롤러는 statusspec과 일치시키기 위해 필요한 실제 물리적/논리적 액션을 취합니다.

5. 불일치(Drift)가 만들어내는 완벽한 자가 치유(Self-Healing)

이러한 SpecStatus의 비교 메커니즘이 쿠버네티스에 완벽한 자가 치유 능력을 부여합니다.

예를 들어, 사용자가 spec에 파드 3개를 요구(Deployment 생성)했다고 가정해 보겠습니다.
최초 상태에는 클러스터에 파드가 없으므로 status의 파드 개수는 0입니다. 레플리카셋 컨트롤러는 이 불일치를 발견하고 API 서버에 파드 3개의 생성을 지시하여 status를 3으로 만듭니다.

운영 도중, 파드 1개가 구동 중이던 워커 노드의 하드웨어 장애로 인해 전원이 꺼졌습니다.
이때 쿠버네티스는 "노드가 죽었으니 파드를 다시 살려라"라는 절차적인 명령을 내리지 않습니다. 노드가 다운되면 Kubelet의 상태 보고가 끊기고, 노드 컨트롤러는 해당 노드의 파드들을 삭제 처리합니다. 그 결과 API 서버의 status에 기록된 파드 개수는 2개로 줄어듭니다.

레플리카셋 컨트롤러는 다시 한 번 spec(여전히 3개)과 status(2개로 감소)를 비교합니다. 1개가 부족하다는 것을 인지한 컨트롤러는 즉시 건강한 다른 워커 노드에 새로운 파드 1개를 스케줄링하도록 API 서버에 요청합니다. 결과적으로 status는 다시 3이 되며 시스템은 평온을 되찾습니다. 장애 복구 과정에 어떠한 사람의 개입도, 복잡한 절차적 스크립트도 필요하지 않습니다.

6. 멱등성(Idempotency)과 인프라의 영속성 보장

명령형 시스템에서 "파드를 1개 더 추가하라(+1)"는 명령을 네트워크 지연으로 인해 두 번 전송하면 파드가 2개 추가되는 치명적인 상태 오염이 발생합니다. 하지만 쿠버네티스의 선언적 API에서는 spec.replicas: 3이라는 명세서를 1번 제출하든 100번 제출하든 시스템의 최종 결과는 항상 '파드 3개'로 동일합니다. 이를 '멱등성(Idempotency)'이라고 부릅니다.

쿠버네티스의 모든 아키텍처는 이 SpecStatus의 분리, 그리고 끊임없는 조정(Reconciliation)을 통해 완성됩니다. 관리자가 새벽에 장애 알람을 받고 급하게 서버에 접속할 필요가 없는 이유는, 쿠버네티스 내부의 컨트롤러가 24시간 365일 지치지 않고 Status를 확인하며, 사용자가 선언해 둔 이상적인 Spec의 세계로 인프라를 끊임없이 되돌려 놓고 있기 때문입니다. 선언적 API의 본질은 바로 시스템 스스로가 '현재'를 파악하고 '미래의 목표'를 향해 끝없이 항해하도록 만드는 자율 주행 인프라의 핵심 엔진입니다.