도커는 알겠는데, 쿠버네티스는 왜 이렇게 어렵게 느껴질까?
개발자 커뮤니티에서 자주 들리는 말이 있습니다. "도커는 정말 직관적이고 좋은데, 쿠버네티스는 시작하려고 하니 거대한 벽처럼 느껴져요." 많은 개발자가 컨테이너 기술의 편리함에 매료되어 도커를 사용하기 시작하지만, 컨테이너 오케스트레이션의 사실상 표준으로 자리 잡은 쿠버네티스 앞에서는 높은 진입 장벽을 체감하곤 합니다.
이러한 어려움은 당연한 것입니다. 저자 역시 서문에서 "도커와 쿠버네티스를 공부하고 실제로 도입하기 위해 매우 힘든 과정을 거쳤습니다"라고 고백하며, 이러한 경험이 오히려 초보자를 위한 책을 집필하는 계기가 되었다고 밝히고 있습니다.
그렇다면 쿠버네티스는 왜 이렇게 어렵게 느껴지는 걸까요? 그리고 이 거대한 벽을 넘기 위해서는 어떻게 접근해야 할까요? 『시작하세요! 도커/쿠버네티스(개정2판)』의 내용을 바탕으로 그 이유와 해결책을 알아보겠습니다.
1. 도커 엔진에서 쿠버네티스 클러스터로: 사고의 전환이 필요합니다
가장 큰 차이점은 관리의 범위와 추상화 수준입니다.
도커: 도커 엔진은 하나의 호스트에서 컨테이너를 생성하고 관리하는 주체입니다. 우리는 docker run, docker ps 같은 명확한 명령어를 통해 컨테이너라는 대상을 직접 제어합니다. 이는 마치 강력한 엔진 하나를 다루는 것과 같습니다.
쿠버네티스: 반면 쿠버네티스는 여러 서버를 하나의 클러스터로 묶어 자원의 풀(Pool)로 만들고, 그 위에 수많은 컨테이너를 효율적으로 배치하고 관리하는 '오케스트레이션' 도구입니다. 이는 하나의 엔진이 아닌, 수많은 악기로 구성된 오케스트라 전체를 지휘하는 것과 같습니다. 이 과정에서 서버 장애, 부하 분산, 서비스 발견 등 훨씬 더 복잡한 문제들을 해결해야 합니다.
이러한 개념의 도약이 쿠버네티스를 처음 접하는 개발자에게 큰 혼란을 줍니다. 『시작하세요! 도커/쿠버네티스』는 이러한 혼란을 줄이기 위해, 1부에서 도커의 기본 개념부터 도커 스웜(Swarm)을 통한 클러스터링의 기초까지 차근차근 밟아나간 뒤, 자연스럽게 2부에서 쿠버네티스로 넘어가도록 구성되어 있습니다.
2. 새로운 개념의 홍수: '파드'는 대체 무엇일까?
도커의 세계는 이미지(Image)와 컨테이너(Container)라는 비교적 단순한 개념으로 이루어져 있습니다. 하지만 쿠버네티스는 완전히 새로운 용어들을 제시합니다.
파드(Pod), 레플리카셋(ReplicaSet), 디플로이먼트(Deployment), 서비스(Service), 인그레스(Ingress), PV/PVC...
이 중 가장 기본이 되는 단위는 바로 파드(Pod)입니다. 도커 사용자는 "컨테이너를 실행하면 되지, 왜 굳이 파드라는 개념을 또 만들었을까?"라는 의문을 갖게 됩니다.
쿠버네티스에서 파드는 컨테이너 애플리케이션의 기본 단위이며, 1개 이상의 컨테이너로 구성된 집합입니다. 가장 큰 특징은 파드 안의 컨테이너들이 네트워크와 같은 리눅스 네임스페이스를 공유한다는 점입니다.
예를 들어, 로그를 수집하는 '사이드카(sidecar)' 컨테이너가 메인 애플리케이션 컨테이너와 함께 하나의 파드로 묶이면, 두 컨테이너는 마치 한 서버에서 실행되는 것처럼 localhost를 통해 통신할 수 있습니다. 이는 도커의 단일 컨테이너 모델에서는 볼 수 없었던 강력한 설계 패턴입니다.
이 책은 6장에서 이 '파드'의 개념을 가장 먼저, 그리고 비중 있게 다룸으로써 쿠버네티스의 가장 기초적인 벽돌을 제대로 쌓을 수 있도록 돕습니다.
3. '명령'에서 '선언'으로: YAML 파일과의 싸움
도커를 사용할 때는 주로 다음과 같은 명령형(Imperative) 방식을 사용합니다.
# "nginx 컨테이너를 80번 포트로 실행해줘!" 라는 직접적인 명령
docker run -d -p 80:80 --name my-nginx nginx
하지만 쿠버네티스는 선언형(Declarative) 방식을 지향합니다. 우리는 YAML 파일을 통해 "우리가 원하는 바람직한 상태(Desired State)"를 정의하고, 쿠버네티스는 현재 상태를 그 상태와 일치시키기 위해 스스로 동작합니다.
실전 사례: 고가용성 웹 서버 배포
단순히 Nginx 컨테이너 하나를 띄우는 것이 목표라면 도커가 더 간편합니다. 하지만 "Nginx 파드 3개가 항상 안정적으로 실행되는 상태"를 유지하고 싶다면 어떻게 해야 할까요?
이때 우리는 다음과 같은 디플로이먼트(Deployment) YAML 파일을 작성하여 쿠버네티스에 전달합니다.
# 책 285페이지의 예제 6.6을 참고한 코드입니다. [cite: 1727]
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx-deployment
spec:
replicas: 3 # 1. 우리는 파드 3개가 실행되는 상태를 원한다고 '선언'합니다.
selector:
matchLabels:
app: my-nginx
template: # 2. 파드는 이런 모습(nginx 이미지 사용 등)이어야 합니다.
metadata:
labels:
app: my-nginx
spec:
containers:
- name: nginx
image: nginx:1.10
ports:
- containerPort: 80
kubectl apply -f 명령어로 위 YAML 파일을 전달하면, 쿠버네티스의 디플로이먼트 컨트롤러는 다음의 동작을 수행합니다.
replicas: 3 설정을 확인하고, app: my-nginx 라벨을 가진 파드가 3개인지 확인합니다.
현재 파드가 0개이므로, template에 정의된 명세대로 파드 3개를 생성합니다.
만약 사용자가 실수로 파드 하나를 지우거나 특정 노드에 장애가 발생해 파드가 사라지면, 컨트롤러는 즉시 "바람직한 상태(3개)와 현재 상태(2개)가 다르다"는 것을 인지하고 부족한 파드 1개를 다른 노드에 자동으로 생성해줍니다.
이처럼 쿠버네티스는 YAML을 통해 우리가 원하는 최종 상태를 '선언'하면, 그 상태를 유지하기 위해 끊임없이 노력하는 '자체 회복(self-healing)' 능력을 갖추고 있습니다. 이것이 바로 쿠버네티스의 핵심 가치이자, YAML 파일이 복잡해 보이는 이유입니다.
결론: 거대한 벽이 아닌, 올라가야 할 계단으로
쿠버네티스가 어렵게 느껴지는 이유는 단순히 기능이 많아서가 아니라, 분산 시스템을 관리라는 복잡한 문제를 해결하기 위해 새로운 추상화 계층과 작동 방식을 도입했기 때문입니다.
『시작하세요! 도커/쿠버네티스(개정2판)』는 이러한 진입 장벽을 다음과 같은 방법으로 낮춰줍니다.
체계적인 학습 순서: 가장 익숙한 도커부터 시작해 점진적으로 쿠버네티스의 핵심 개념(파드 -> 레플리카셋 -> 디플로이먼트)으로 나아갑니다.
친절하고 명확한 설명: 저자의 경험을 바탕으로 초보자가 가장 혼란스러워하는 지점을 정확히 짚어주고 쉬운 언어로 설명합니다.
풍부한 실습 예제: 모든 개념을 YAML 파일 예제와 함께 설명하고, 깃허브를 통해 코드를 제공하여 직접 따라 하며 체득할 수 있도록 돕습니다.
쿠버네티스라는 벽 앞에서 혼자서 좌절하고 있다면, 먼저 그 벽을 넘었던 선배 개발자가 만든 친절한 계단을 이용해 보는 것은 어떨까요? 이 책은 여러분이 컨테이너 오케스트레이션 전문가로 나아가는 가장 튼튼한 첫 계단이 되어줄 것입니다.
https://wikibook.co.kr/docker-kube-rev2/
도커를 처음 접하는 개발자를 위한 도커 컨테이너와 이미지의 기본적인 개념을 먼저 설명한 뒤, 도커 컴포즈와 스웜 모드를 통해 컨테이너 애플리케이션을 YAML 파일로 작성하고 클러스터에서 배포하는 방법을 소개합니다. 나아가 도커 컨테이너, 도커 컴포즈, 스웜 모드에서 학습한 지식을 활용해 쿠버네티스의 기초 사용법, 다양한 쿠버네티스 오브젝트의 사용 방법 및 심화 개념까지 알아봅니다.