infra
Platform

모듈 맵

[Docker] 도커 스웜의 한계와 쿠버네티스(K8s) 전환 로드맵

0 / 27 완료

펼치기
0 / 27 완료0%

Docker · 24 / 27

[Docker] 도커 스웜의 한계와 쿠버네티스(K8s) 전환 로드맵

Docker Compose에서 Kubernetes로 넘어가는 개념적 다리 — Pod, Deployment, Service가 docker run, Compose와 어떻게 대응되는지 이해합니다

컨테이너 오케스트레이션과 Kubernetes 입문

🚨INCIDENT ALERT
HIGH

단일 서버에서는 Compose로 충분했지만, 서버가 여러 대가 되자 배포·복구·스케일링이 모두 수동 작업이 됩니다. 장애가 나면 어느 노드에서 무엇이 죽었는지 찾는 데만 시간이 소모되고, 롤백도 일관되지 않습니다. 이 시점부터는 "컨테이너 실행"보다 "원하는 상태를 자동 유지"하는 오케스트레이션 사고가 필요합니다. 이 모듈은 Docker 경험을 Kubernetes 운영 개념으로 자연스럽게 연결합니다.

이 모듈의 위치: Docker Compose까지 배웠다면 "서버가 여러 대면 어떻게 하나?"라는 질문이 생깁니다. 그 답이 오케스트레이션입니다. 현업 표준은 Kubernetes(K8s)입니다. 이 모듈은 Docker 지식을 K8s 개념에 연결하는 다리 역할을 합니다.


이번 챕터에서 배울 것

Docker를 알면 Kubernetes의 절반은 이미 이해한 겁니다. 컨테이너 이미지, 포트 바인딩, 볼륨, 환경변수 — 모두 K8s에서 같은 개념이 다른 문법으로 존재합니다. 낯선 용어들을 Docker 용어에 대응시키면서 배우면 훨씬 빠릅니다.

  • 1오케스트레이션이 왜 필요한가 — Compose 한계와 멀티 노드의 현실
  • 2Docker 개념 → Kubernetes 개념 1:1 매핑 (run→Pod, Compose→Deployment)
  • 3kubectl 기본 명령 — docker CLI와 비교해서 배우기
  • 4첫 번째 Deployment 배포 — YAML 작성부터 외부 노출까지
  • 5롤링 업데이트와 롤백 — Kubernetes가 무중단 배포를 처리하는 방식
실습 환경 준비

minikube는 노트북에서 단일 노드 Kubernetes를 실행하는 도구입니다. 실제 클러스터 없이 이 모듈의 모든 실습을 진행할 수 있습니다.

minikube 설치 확인 (로컬 K8s 클러스터)
minikube version
minikube 시작
minikube start
kubectl 설치 확인
kubectl version --client
클러스터 연결 확인
kubectl cluster-info
minikube 미설치 시 대안 (Docker Desktop)

Docker Desktop의 Settings → Kubernetes → Enable Kubernetes로 로컬 클러스터 활성화 가능합니다

💡개념

왜 Compose로는 부족한가 — 오케스트레이션의 필요성

Docker Compose로 운영 중인 서버가 다운됐습니다. 모든 컨테이너가 중단됩니다. 수동으로 서버를 복구하고 docker-compose up을 다시 실행해야 합니다. 트래픽이 갑자기 2배가 됐습니다. 컨테이너를 더 실행하려면 또 다른 서버에 SSH로 접속해서 수동으로 docker run을 해야 합니다. 배포할 때마다 잠깐 서비스가 중단됩니다. Compose는 단일 서버에서 컨테이너를 편하게 관리하는 도구지, 여러 서버를 자동으로 관리하는 도구가 아닙니다.

오케스트레이션 필요성

Compose의 한계

Docker Compose가 해결하는 것:
✓ 로컬 개발 환경 멀티 컨테이너 관리
✓ 단일 서버에서 서비스 간 네트워크
✓ 볼륨, 환경변수, 의존성 관리

Docker Compose가 해결하지 못하는 것:
✗ 여러 서버(노드)에 컨테이너 분산
✗ 노드 장애 시 자동 복구
✗ 트래픽에 따른 자동 스케일링
✗ 무중단 롤링 업데이트
✗ 서비스 간 부하분산

Kubernetes가 해결하는 것

Kubernetes(K8s)는 컨테이너 오케스트레이션 플랫폼입니다. 여러 서버를 하나의 클러스터로 추상화하고, 컨테이너의 배포·스케일링·복구를 자동화합니다.

[K8s 클러스터 구조]

Control Plane (마스터)
┌─────────────────────────────┐
│  API Server  │  Scheduler   │
│  etcd        │  Controller  │  ← 클러스터 상태 관리
└─────────────────────────────┘
         ↕ 명령/상태 동기화
Worker 노드들
┌──────────┐ ┌──────────┐ ┌──────────┐
│  Node 1  │ │  Node 2  │ │  Node 3  │
│ [Pod A]  │ │ [Pod B]  │ │ [Pod C]  │
│ [Pod D]  │ │ [Pod E]  │ │          │
└──────────┘ └──────────┘ └──────────┘

→ Node 2 장애 시: Pod B, E를 Node 1, 3으로 자동 재스케줄
→ 트래픽 급증 시: Pod 수를 자동으로 늘림 (HPA)
→ 배포 시: Pod를 순차적으로 교체 (무중단 롤링 업데이트)

💡개념

Docker → Kubernetes 개념 매핑

K8s를 처음 배울 때 가장 힘든 것은 새로운 용어들입니다. Pod, Deployment, Service, ConfigMap, Ingress — 낯선 이름들이 쏟아집니다. 그런데 이 개념들은 Docker에서 이미 알고 있는 것들과 정확히 대응됩니다. 매핑을 알면 절반은 이미 이해한 겁니다.

Docker에서 Kubernetes로 개념 매핑

핵심 개념 매핑

Docker / ComposeKubernetes역할
docker runPod컨테이너 실행 단위
docker-compose.yml serviceDeployment컨테이너 수·이미지·설정 선언
--replicas: 3replicas: 3동일 — 복제본 수
-p 8080:80Service (NodePort/LB)외부 포트 노출
docker networkService (ClusterIP)컨테이너 간 통신
-e KEY=VALUEenv + ConfigMap환경변수
-e PASSWORD=...Secret민감한 환경변수
-v /host:/containerPersistentVolumeClaim영구 볼륨
healthcheck:livenessProbe / readinessProbe헬스체크
docker logskubectl logs컨테이너 로그
docker exec -itkubectl exec -it컨테이너 접속
docker pskubectl get pods실행 중인 컨테이너 목록

Pod란?

Pod는 K8s에서 가장 작은 배포 단위입니다. docker run nginx가 컨테이너 하나를 실행하는 것처럼, K8s에서는 Pod 안에 컨테이너가 실행됩니다. 대부분의 경우 Pod 하나 = 컨테이너 하나입니다.

YAML
# docker run nginx와 동일한 K8s Pod
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx:1.25-alpine
    ports:
    - containerPort: 80

Deployment란?

Pod를 직접 만들지 않고 Deployment를 사용합니다. Deployment는 "nginx를 3개 실행하고 항상 3개 상태를 유지하라"는 선언입니다. Pod가 죽으면 자동으로 새 Pod를 만듭니다.

YAML
# docker-compose.yml의 service와 대응
# services:
#   web:
#     image: nginx:1.25-alpine
#     deploy:
#       replicas: 3

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3          # Compose의 replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25-alpine
        ports:
        - containerPort: 80

1첫 번째 Deployment 배포 — YAML 작성부터 외부 노출까지

minikube 환경에서 nginx를 3개 복제본으로 배포하고, Service로 외부에 노출합니다.

YAML
# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25-alpine
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30080
Kubernetes
# Deployment와 Service 동시 배포
kubectl apply -f nginx-deployment.yaml

# 배포 상태 확인
kubectl get pods
kubectl get deployment nginx-deployment
kubectl get service nginx-service

# minikube에서 외부 접근 URL 확인
minikube service nginx-service --url
kubectl apply -f nginx-deployment.yaml
🔍실행 후 확인할 것
  • kubectl get pods 에서 Pod 3개가 모두 Running 상태인지 확인
  • kubectl get deployment nginx-deployment — READY 컬럼이 3/3인지 확인
  • kubectl describe pod <pod-name> 에서 Events 섹션에 에러 없이 Started가 찍히는지
  • minikube service nginx-service --url 로 받은 URL을 curl로 호출하면 nginx 응답이 오는지
  • kubectl get replicaset — Deployment가 ReplicaSet을 통해 Pod를 관리하는 구조 확인

트러블슈팅

증상

Deployment를 배포했는데 Pod가 Running이 되지 않고 계속 Pending 상태입니다.

Kubernetes
kubectl get pods
# NAME                               READY   STATUS    RESTARTS   AGE
# nginx-deployment-7d9c4bbfd-xk2p9   0/1     Pending   0          2m

kubectl describe pod nginx-deployment-7d9c4bbfd-xk2p9
# Events:
#   Warning  FailedScheduling  2m  default-scheduler
#   0/1 nodes are available: 1 Insufficient memory.

원인 진단

Kubernetes
# 노드 리소스 현황 확인
kubectl describe nodes | grep -A 5 "Allocated resources"
# Allocated resources:
#   Resource    Requests    Limits
#   cpu         950m (47%)  2 (100%)
#   memory      1900Mi (95%) 2000Mi (99%)
# → 메모리가 거의 꽉 찬 상태

# Pod의 리소스 요청량 확인
kubectl get pod nginx-deployment-7d9c4bbfd-xk2p9 -o yaml | grep -A 10 resources

해결

Kubernetes
# 방법 1: 다른 Pod 삭제하여 리소스 확보
kubectl get pods --all-namespaces | grep -v Running
# 불필요한 Pod 삭제

# 방법 2: Deployment에 resources.requests 조정
kubectl edit deployment nginx-deployment
# resources:
#   requests:
#     memory: "64Mi"   ← 낮춤
#     cpu: "100m"

# 방법 3: minikube 메모리 늘려서 재시작
minikube stop
minikube start --memory=4096

증상

kubectl apply 직후에는 Running이었다가 금방 Error → CrashLoopBackOff로 바뀝니다.

Kubernetes
kubectl get pods
# NAME                              READY   STATUS             RESTARTS   AGE
# myapp-deployment-abc123-x7k2p   0/1     CrashLoopBackOff   5          3m

# 재시작 횟수가 계속 늘어남
kubectl get pods -w
# myapp-..   0/1   Error              3   90s
# myapp-..   0/1   CrashLoopBackOff   3   95s
# myapp-..   0/1   Running            4   110s
# myapp-..   0/1   Error              4   115s

원인 진단

Kubernetes
# 컨테이너 로그 확인 — docker logs와 동일한 역할
kubectl logs myapp-deployment-abc123-x7k2p
# Error: Cannot find module '/app/server.js'   ← 이런 에러 메시지 확인

# 이전 충돌 컨테이너의 로그 확인
kubectl logs myapp-deployment-abc123-x7k2p --previous

# Pod 상세 이벤트 확인
kubectl describe pod myapp-deployment-abc123-x7k2p
# Events:
#   Warning  BackOff  2m  kubelet  Back-off restarting failed container

주요 원인별 해결

Kubernetes
# 원인 1: 이미지 내 실행 파일 경로 오류 → Dockerfile ENTRYPOINT/CMD 확인
# 원인 2: 환경변수 누락 → kubectl get pod -o yaml 로 env 확인
# 원인 3: ConfigMap/Secret 마운트 실패 → kubectl describe pod Events 확인

# 임시 디버깅: 같은 이미지로 셸 접속
kubectl run debug --image=myapp:latest --restart=Never -it -- /bin/sh

증상

단일 노드에서는 Pod 간 통신이 잘 됐는데, 멀티 노드 클러스터(또는 Swarm) 환경에서 서로 다른 노드에 뜬 Pod끼리 통신이 안 됩니다.

Kubernetes
# Pod A (Node 1)에서 Pod B (Node 2)로 ping/curl 실패
kubectl exec -it pod-a -- curl http://pod-b-service
# curl: (7) Failed to connect to pod-b-service port 80: Connection timed out

원인 진단

로컬 터미널
# 노드 간 오버레이 네트워크 포트 확인 (방화벽 문제)
# Kubernetes(Flannel/Calico): UDP 8472, UDP 4789 필요
# Kubernetes API: TCP 6443
# Swarm: TCP 2377, TCP/UDP 7946, UDP 4789

# 방화벽 상태 확인
sudo firewall-cmd --list-all  # CentOS/RHEL
sudo ufw status               # Ubuntu

해결

로컬 터미널
# Ubuntu (ufw) — 오버레이 네트워크 포트 허용
sudo ufw allow 6443/tcp    # K8s API Server
sudo ufw allow 8472/udp    # Flannel VXLAN
sudo ufw allow 4789/udp    # Overlay network
sudo ufw allow 7946/tcp    # Calico BGP / Swarm gossip
sudo ufw allow 7946/udp

# 설정 후 Pod 간 통신 재확인
kubectl exec -it pod-a -- curl http://pod-b-service

💼
실무 맥락
현업 패턴

"Compose로 충분한가" — 팀이 Kubernetes로 전환하는 실제 기준점

스타트업 초기에는 EC2 한 대에 docker-compose로 운영합니다. 빠르고 단순합니다. 그러다 어느 순간 이런 상황이 옵니다: 새벽 3시에 서버가 멈추고, 자동 복구가 없어서 수동으로 SSH 접속해서 docker-compose up을 칩니다. 다음 날 오전 트래픽 피크 때 컨테이너를 더 늘려야 하는데 새 서버에 일일이 접속해서 설정합니다. 이 지점이 오케스트레이션을 고민해야 할 때입니다.

팀 규모별 현실적 판단:

1~3명 팀, 단일 서버:
  → docker-compose + systemd restart=always 로 충분
  → K8s 도입하면 운영 오버헤드가 더 큼

4~10명 팀, 서버 3대 이상:
  → Kubernetes 도입 고려 시작
  → EKS/GKE 같은 매니지드 서비스가 현실적

10명+ 팀, MSA:
  → K8s는 선택이 아닌 필수
  → Helm, ArgoCD, Istio 등 생태계 전체 활용

실무에서 K8s를 배워야 하는 이유: 대부분의 중소기업 이상 회사의 인프라는 이미 K8s로 전환됐거나 전환 중입니다. 채용 공고에서 "K8s 운영 경험"이 필수 요건으로 등장하는 비율이 빠르게 늘고 있습니다. Docker를 잘 안다면 K8s 진입 장벽은 생각보다 낮습니다 — 이 모듈에서 배운 개념 매핑이 그 다리 역할을 합니다.

다음 모듈에서는 Kubernetes 트랙에서 실제 클러스터 운영, Helm 패키지 관리, 그리고 서비스 메시(Istio)를 심층적으로 다룹니다.

지식 확인

퀴즈 — 5문제

Q1

Docker Compose의 `services` 항목이 Kubernetes에서 대응되는 개념은?

Q2

kubectl apply -f deployment.yaml 명령 후 Pod가 CrashLoopBackOff 상태입니다. 원인 파악을 위한 첫 번째 명령은?

Q3

Kubernetes에서 외부 트래픽을 Pod에 전달하려면 무엇이 필요한가?

Q4

배포 후 문제가 생겨서 이전 버전으로 되돌려야 합니다. 올바른 명령은?

Q5

docker-compose.yml에서 environment 항목이 Kubernetes에서 대응되는 방법으로 가장 적절한 것은?

0 / 5 답변

🧪 실습으로 확인하기

Docker Compose 멀티 서비스 구성

초급

docker-compose.yml로 nginx + 앱 컨테이너를 함께 정의하고, 서비스 간 통신과 볼륨 마운트를 구성한다.

35📋 4단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요

docker중급 · 60
[Docker] 빌드 자동화와 이미지 태그 배포 파이프라인 구축
Docker 트랙 계속
networking입문 · 45
[Network] OSI 7계층과 TCP/IP 4계층 모델 실무적 관점 분석
Networking 트랙 시작점