이전 글에서 docker-compose로 여러 컨테이너를 한 대의 컴퓨터에서 묶어 띄웠다. 그런데 실제 서비스는 컴퓨터 한 대로 끝나지 않는다. 수십 대의 서버에 컨테이너 수백 개가 흩어져 돌고, 트래픽에 따라 그 수가 출렁이며, 서버 한 대가 죽어도 서비스는 멈추면 안 된다. 이 규모를 사람 손으로 관리하는 것은 불가능하다. 이 문제를 푸는 것이 컨테이너 오케스트레이션(container orchestration) 이고, 그 사실상의 표준이 Kubernetes(쿠버네티스, 줄여서 K8s)다.

컨테이너가 많아지면 생기는 문제

컨테이너 하나, 혹은 한 대의 서버 위 컨테이너 몇 개라면 docker run이나 docker-compose로 충분하다. 하지만 규모가 커지면 사람이 직접 감당하기 어려운 일들이 쏟아진다.

  • 배치(scheduling): 새 컨테이너를 어느 서버에 띄울 것인가? 어떤 서버는 한가하고 어떤 서버는 메모리가 빠듯한데, 이걸 매번 사람이 골라야 하나?
  • 확장(scaling): 트래픽이 몰리면 컨테이너를 10개에서 50개로 늘리고, 한가해지면 다시 줄여야 한다. 이걸 수동으로?
  • 장애 복구(self-healing): 컨테이너가 죽거나 서버 한 대가 통째로 다운되면, 죽은 만큼을 다른 살아있는 서버에 다시 띄워야 한다. 새벽 3시에 사람이 깨어 대응할 수는 없다.
  • 무중단 배포(rolling update): 새 버전을 내보낼 때 서비스를 멈추지 않고, 컨테이너를 조금씩 교체해야 한다. 문제가 생기면 이전 버전으로 되돌려야(rollback) 한다.
  • 네트워킹·발견(service discovery): 컨테이너는 죽고 살기를 반복하며 IP가 계속 바뀐다. 그런데도 다른 컨테이너들은 안정적인 주소로 그들을 찾아야 한다.
  • 부하 분산(load balancing): 같은 일을 하는 컨테이너 50개에 요청을 고르게 나눠야 한다.

이 모든 것을 자동으로 처리해 주는 시스템이 오케스트레이터다.

오케스트레이션이란

오케스트레이션은 이름 그대로 오케스트라의 지휘에 비유할 수 있다. 수십 명의 연주자(컨테이너)가 여러 무대(서버)에 흩어져 있어도, 지휘자(오케스트레이터)가 전체를 보며 누가 무엇을 언제 연주할지 조율해 하나의 곡을 완성한다.

Kubernetes는 이 지휘자 역할을 한다. 핵심 아이디어는 선언형(declarative) 운영이다. 이전 글의 docker-compose에서 “어떤 상태이길 원하는지를 파일에 적는다”고 했는데, Kubernetes는 바로 그 사고방식을 대규모로 끌어올린 것이다.

  • 사용자는 “원하는 상태(desired state)” 만 선언한다. 예: “이 이미지를 쓰는 컨테이너를 항상 3개 띄워 두라.”
  • Kubernetes는 현재 상태(current state) 를 끊임없이 관찰하고, 원하는 상태와 다르면 스스로 맞춘다. 컨테이너가 2개로 줄면 1개를 새로 띄우고, 4개로 늘면 1개를 줄인다.

이렇게 “원하는 상태와 현재 상태의 차이를 계속 좁히는” 동작을 reconciliation(조정) 루프라 부른다. 사람이 “이렇게 해라(how)“를 일일이 명령하는 명령형(imperative) 이 아니라, “이런 상태여야 한다(what)“만 선언하면 시스템이 알아서 유지하는 것이 Kubernetes의 본질이다.

사용자: "웹 컨테이너 3개를 원한다"  ──선언──▶  [Kubernetes]
                                                  │
                                       현재 2개뿐임을 감지
                                                  │
                                       1개를 자동으로 새로 띄움
                                                  ▼
                                          원하는 상태(3개) 달성·유지

이 방식의 강력함은 장애 상황에서 드러난다. 서버가 죽어 컨테이너 1개가 사라져도, 사람이 개입할 필요 없이 Kubernetes가 그 차이를 감지해 다른 서버에 자동으로 다시 띄운다. “원하는 상태”라는 약속이 깨지지 않도록 시스템이 알아서 떠받치는 것이다.

Kubernetes의 큰 그림: 클러스터

Kubernetes는 여러 서버를 묶어 하나의 거대한 컴퓨터처럼 다룬다. 이 서버들의 묶음을 클러스터(cluster) 라 하고, 클러스터는 두 종류의 구성원으로 이뤄진다.

  • control plane(컨트롤 플레인) — 클러스터의 두뇌. 사용자의 “원하는 상태” 선언을 받고, 전체를 관찰하며, 어느 서버에 무엇을 띄울지 결정한다. (API 서버, 스케줄러, 상태 저장소 등으로 구성)
  • worker node(워커 노드) — 실제로 컨테이너가 실행되는 일꾼 서버들. control plane의 지시를 받아 컨테이너를 띄우고 상태를 보고한다.
              ┌─────────────────────────────┐
              │        Control Plane        │   ← 두뇌: 결정·조율
              │  (API 서버 / 스케줄러 / 저장소)  │
              └──────────────┬──────────────┘
                  지시 ↓        ↑ 상태 보고
        ┌──────────────┬───────┴──────┬──────────────┐
        ▼              ▼              ▼              ▼
   ┌─────────┐   ┌─────────┐    ┌─────────┐
   │ Worker  │   │ Worker  │    │ Worker  │     ...   ← 일꾼 서버들
   │ Node 1  │   │ Node 2  │    │ Node 3  │
   │[컨테이너]│   │[컨테이너]│    │[컨테이너]│
   └─────────┘   └─────────┘    └─────────┘

사용자는 개별 서버에 일일이 접속하지 않는다. control plane에 “원하는 상태”를 선언하면, control plane이 어느 워커 노드가 적당한지 골라 컨테이너를 배치하고, 이후 그 상태가 유지되도록 계속 돌본다. 사용자는 서버 한 대 한 대가 아니라 클러스터 전체를 하나의 자원 풀로 바라보면 된다.

요약

  • 컨테이너가 많아지면 배치·확장·장애 복구·무중단 배포·네트워킹을 사람이 손으로 관리할 수 없다. 이를 자동화하는 것이 컨테이너 오케스트레이션이고, 표준이 Kubernetes다.
  • Kubernetes의 핵심은 선언형 운영이다. 사용자는 “원하는 상태”만 선언하고, 시스템이 현재 상태를 관찰해 그 차이를 계속 좁힌다(reconciliation 루프) — 그래서 장애가 나도 스스로 복구한다.
  • Kubernetes는 여러 서버를 클러스터로 묶어, 결정·조율을 맡는 control plane과 컨테이너를 실제로 실행하는 worker node로 운영한다.
  • 그렇다면 “원하는 상태”는 구체적으로 무엇을 선언하는가? 이를 표현하는 핵심 오브젝트(Pod·Deployment·Service)를 다음 글에서 다룬다.