1. 개요

쿠버네티스를 처음 만졌을 때 Pod, ReplicaSet, Deployment, Service, Ingress 를 각각 외웠다. 외운 건 많은데 “그래서 이게 뭘 하는 시스템인가” 는 설명을 못 했다. 홈랩에서 k3s 를 반년 굴리고 나서야 한 문장으로 정리됐다.

원하는 상태를 선언해 두면, 컨트롤러가 현재 상태를 그 모양으로 계속 맞춘다.

이 시리즈는 그 한 문장으로 나머지 개념을 엮는다. 컨테이너가 VM 과 뭐가 다른지는 인프라 기초 1 - 컨테이너는 가상머신이 아니다에서 다뤘으니 여기서는 그 위, 여러 대의 서버에 컨테이너를 배치하고 유지하는 부분만 본다. 이미 쓴 운영 경험담 글들(NetworkPolicy default-deny 의 정확한 의미론, SealedSecret 을 값 없이 검증하기 등)이 전제하는 기초를 채우는 글이기도 하다.

총 8편이다.

  1. 선언과 조정 루프 (이 글)
  2. Kubernetes 기초 2 - Pod 와 프로브
  3. Kubernetes 기초 3 - Deployment 와 롤링 업데이트
  4. Kubernetes 기초 4 - Service 와 DNS
  5. Kubernetes 기초 5 - Ingress 와 Gateway API
  6. Kubernetes 기초 6 - ConfigMap, Secret, 볼륨
  7. Kubernetes 기초 7 - 스케줄링과 리소스
  8. Kubernetes 기초 8 - kubectl 로 문제 찾는 순서

2. 핵심 내용

2-1. 명령이 아니라 선언이다

docker run 은 명령이다. 실행하면 컨테이너가 하나 뜨고, 죽으면 그걸로 끝이다. 쿠버네티스에서는 “이런 상태여야 한다” 는 YAML 을 API 서버에 저장한다. 그 뒤는 컨트롤러 몫이다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3          # 원하는 상태: 3개
  selector:
    matchLabels: { app: web }
  template:
    metadata:
      labels: { app: web }
    spec:
      containers:
        - name: web
          image: ghcr.io/example/web:1.4.0

이 YAML 은 “web 을 3개 띄워라” 가 아니라 “web 이 3개 떠 있는 상태여야 한다” 는 기록이다. 2개뿐이면 하나를 더 만들고, 4개면 하나를 지운다.

2-2. 조정 루프

컨트롤러는 같은 일을 무한히 반복한다.

원하는 상태를 읽는다 → 실제 상태를 읽는다 → 다르면 고친다 → 처음으로

파드를 손으로 지워도 다시 생기는 이유가 이것이다. 누가 되살리는 게 아니라 “개수가 모자란 걸 발견해서 채운” 것이다. 안 뜨는 걸 볼 때도 “왜 안 뜨지” 대신 “원하는 상태는 뭐고 현재 상태는 뭐고 조정하는 쪽이 무엇에 막혔나” 를 물으면 진단이 빨라진다.

2-3. 누가 무엇을 하나

flowchart LR
    U[kubectl apply<br/>YAML] --> API[API 서버]
    API <--> E[(etcd<br/>원하는 상태 저장)]
    C[컨트롤러 매니저<br/>감시 · 비교 · 조정] <-->|watch| API
    S[스케줄러<br/>어느 노드에?] <--> API
    K[kubelet<br/>노드마다 1개] <--> API
    K --> R[컨테이너 런타임]

컨트롤 플레인이 두뇌이고 노드가 손발이다.

구성 요소하는 일
API 서버모든 요청의 입구. 상태를 읽고 쓰는 유일한 창구
etcd원하는 상태를 저장하는 key-value 저장소
컨트롤러 매니저Deployment, ReplicaSet 같은 컨트롤러들이 도는 곳
스케줄러새 Pod 를 어느 노드에 둘지 정한다
kubelet노드에서 Pod 가 명세대로 도는지 보고 컨테이너 런타임에 지시한다

컴포넌트끼리 직접 부르지 않는다. 전부 API 서버를 바라보고 변화를 감시(watch)한다. 스케줄러는 노드에 배정만 기록하고, kubelet 이 그 기록을 보고 실제로 띄운다.

k3s 는 이 구성 요소를 바이너리 하나로 묶은 가벼운 배포판이다. 홈랩처럼 노드가 몇 대 안 되는 환경에서 쓰기 좋은 이유다. 왜 옮겼는지는 DoEatFit k3s 운영기 1 - 단일 서버에서 k3s로에 있다.

2-4. 이 원리가 GitOps 로 이어진다

선언이 YAML 이니 그 기록을 git 에 두면 “지금 운영에 뭐가 떠 있나” 의 답이 항상 git 에 있다. ArgoCD 가 클러스터를 git 에 맞추는 것도 같은 조정 루프의 바깥 층이다. 그 설정의 함정은 ArgoCD prune·selfHeal 과 fail-closed 태그 치환에 적었다.


3. 마무리

요약

  • 쿠버네티스는 원하는 상태를 선언하면 컨트롤러가 현재 상태를 계속 맞추는 시스템이다.
  • 컨트롤러는 “읽고, 비교하고, 고치고” 를 반복한다. 파드가 되살아나는 건 그 결과다.
  • 모든 컴포넌트는 API 서버를 통해서만 말하고, 상태는 etcd 에 있다.
  • 선언이 YAML 이라서 그 기록을 git 에 두는 GitOps 가 자연스럽게 따라온다.

다음은 Kubernetes 기초 2 - Pod 와 프로브이다.