왜 docker run만으로는 부족한가
서버 한 대에 컨테이너 서너 개를 올리는 정도라면 docker run으로 충분합니다. 아니, 충분한 정도가 아니라 그게 정답입니다. 이 단계에서 쿠버네티스를 꺼내는 건 이력서 스크린샷 찍을 컵라면 하나 끓이겠다고 산업용 보일러를 설치하는 꼴입니다. 문제는 컨테이너가 서너 개에서 서른 개, 서버가 한 대에서 다섯 대로 늘어나는 순간부터 시작됩니다.
새벽 3시에 컨테이너가 죽으면 누가 다시 띄우는가
docker run으로 띄운 컨테이너는 죽으면 그냥 죽어 있습니다. --restart=always 옵션을 주면 같은 호스트 안에서는 다시 띄워주지만, 호스트 자체가 죽으면 그걸로 끝입니다. 실무에서는 이 문제를 이런 식으로 임시 봉합하곤 합니다.
# 예전에 흔히 보던 "수동 오케스트레이션"
while true; do
if ! docker ps | grep -q my-api; then
docker run -d --name my-api my-api:latest
fi
sleep 5
done이 스크립트는 동작은 합니다. 하지만 이 스크립트가 도는 서버 자체가 죽으면 아무 의미가 없고, 트래픽이 늘어 컨테이너를 3개로 늘려야 할 때 로드밸런서 설정까지 손으로 바꿔야 합니다. 배포 하나 하려면 SSH로 서버 다섯 대를 순서대로 접속해서 docker pull → docker stop → docker run을 반복해야 하고, 그 와중에 순서를 하나라도 틀리면 서비스가 잠깐 통째로 죽습니다.
docker-compose는 답이 아니다
docker-compose.yml로 여러 컨테이너를 한 번에 관리하면 문제가 풀린 것처럼 보입니다. 실제로 로컬 개발 환경이나 사이드 프로젝트라면 compose가 정답인 경우가 많습니다. 하지만 compose는 태생적으로 단일 호스트 도구입니다. 서버 한 대의 자원이 바닥나면 그냥 그 위에서 컨테이너들이 서로 자원을 다투게 될 뿐, "다른 서버로 옮겨서 띄운다"는 개념 자체가 없습니다.
# docker-compose.yml — 이 파일 자체는 잘못이 없다
services:
api:
image: my-api:latest
restart: always
deploy:
replicas: 3 # 이 옵션은 사실 swarm 모드가 아니면 무시된다deploy.replicas처럼 여러 대에 걸친 배포를 흉내 내는 옵션이 있긴 하지만, 이걸 제대로 쓰려면 Docker Swarm으로 갈아타야 합니다. Swarm이 나쁜 기술은 아니지만, 커뮤니티와 생태계가 쿠버네티스 쪽으로 완전히 기울면서 사실상 유지보수 모드에 들어간 지 오래입니다. 여러 대의 서버를 하나의 클러스터처럼 다루고 싶다면, 지금 시점에서는 선택지가 사실상 하나로 좁혀져 있습니다.
오케스트레이션이 실제로 해결하는 문제
쿠버네티스가 특별히 똑똑한 기술은 아닙니다. 오히려 아이디어는 단순합니다 — "이 상태를 유지해줘"라고 선언하면, 실제 상태가 그 선언과 어긋날 때마다 시스템이 알아서 맞춰 놓습니다. 컨테이너가 죽으면 다시 띄우고, 서버 한 대가 통째로 사라지면 살아있는 다른 서버에 옮겨 띄우고, 트래픽이 몰리면 복제본을 늘립니다. 이 반복 작업을 사람이 스크립트로 짜지 않아도 되게 만드는 것, 그게 오케스트레이션의 전부입니다.
이 책은 그 "선언한 상태를 유지시키는" 메커니즘이 실제로 어떻게 동작하는지를 Pod 하나부터 차근차근 따라가면서 보여줍니다. 다음 장에서는 그 메커니즘을 굴리는 부품들 — 컨트롤 플레인과 노드 — 을 먼저 살펴보겠습니다.