현대적인 애플리케이션 환경에서는 하나의 서버에 하나의 프로그램만 설치하여 운영하는 방식에서 벗어나, 여러 개의 컨테이너를 다양한 서버에 분산하여 운영하는 방식이 일반화되고 있습니다. Docker를 이용하면 애플리케이션을 컨테이너로 패키징하고 실행할 수 있지만, 서비스 규모가 커지고 컨테이너 수가 증가하면 단순한 Docker 명령어나 Docker Compose만으로는 관리가 어려워집니다.
예를 들어 FastAPI 애플리케이션을 운영한다고 가정해 보겠습니다. 처음에는 하나의 서버에서 컨테이너 하나만 실행하면 충분할 수 있습니다.
Internet
│
▼
Nginx
│
▼
FastAPI Container
│
▼
PostgreSQL
하지만 사용자가 증가하고 서비스 규모가 커지면 상황이 달라집니다.
Internet
│
▼
Load Balancer
│
├── FastAPI Container 1
├── FastAPI Container 2
├── FastAPI Container 3
├── FastAPI Container 4
└── FastAPI Container 5
컨테이너가 여러 개가 되면 다음과 같은 문제가 발생합니다.
컨테이너 하나가 장애로 종료되면 어떻게 다시 실행할 것인가?
트래픽이 증가하면 컨테이너를 어떻게 자동으로 늘릴 것인가?
여러 서버에 컨테이너를 어떻게 배치할 것인가?
새로운 버전을 배포할 때 서비스를 중단하지 않고 어떻게 업데이트할 것인가?
장애가 발생한 서버에서 실행 중인 컨테이너를 다른 서버로 어떻게 이동할 것인가?
이러한 문제를 해결하기 위한 대표적인 기술이 Kubernetes입니다.
이번 글에서는 Kubernetes의 기본 개념부터 Docker와 Kubernetes의 차이, 클러스터 구조, Node, Pod, Deployment, ReplicaSet, Service의 역할까지 시스템 엔지니어의 실무 관점에서 자세히 알아보겠습니다.
Kubernetes는 여러 서버에서 컨테이너화된 애플리케이션을 자동으로 배포하고 관리하기 위한 컨테이너 오케스트레이션 플랫폼입니다.
Kubernetes는 흔히 K8s라고도 부릅니다.
Kubernetes
│
├── Container 배포
├── Container 관리
├── 자동 복구
├── 자동 확장
├── Load Balancing
├── Rolling Update
└── 여러 서버의 Container 관리
여기서 오케스트레이션이라는 단어가 중요합니다.
오케스트라에서 여러 악기가 하나의 지휘에 따라 함께 연주하듯이 Kubernetes는 여러 서버와 수많은 컨테이너를 하나의 시스템에서 통합적으로 관리합니다.
예를 들어 10개의 서버가 있다고 가정해 보겠습니다.
Server 1
Server 2
Server 3
Server 4
Server 5
Server 6
Server 7
Server 8
Server 9
Server 10
Docker만 사용하는 경우 각 서버에 접속하여 직접 컨테이너를 관리해야 할 수 있습니다.
관리자
│
├── SSH → Server 1
├── SSH → Server 2
├── SSH → Server 3
└── SSH → Server 4
Kubernetes를 사용하면 여러 서버를 하나의 클러스터로 묶어 관리할 수 있습니다.
Kubernetes Cluster
│
┌───────────────┼───────────────┐
│ │ │
Node 1 Node 2 Node 3
│ │ │
Pods Pods Pods
관리자는 개별 서버가 아니라 Kubernetes 클러스터에 원하는 상태를 선언합니다.
FastAPI 컨테이너 5개를 실행하라
그러면 Kubernetes가 적절한 서버에 컨테이너를 배치하고 관리합니다.
Docker와 Kubernetes는 서로 경쟁하는 기술이 아닙니다. 역할이 다릅니다.
Docker는 기본적으로 컨테이너를 만들고 실행하는 기술입니다.
Source Code
│
▼
Dockerfile
│
▼
Docker Image
│
▼
Docker Container
반면 Kubernetes는 여러 개의 컨테이너를 대규모 환경에서 관리하는 기술입니다.
Docker Image
│
▼
Kubernetes
│
├── Container 배포
├── Container 복제
├── 장애 복구
├── Load Balancing
└── 자동 확장
간단하게 비교하면 다음과 같습니다.
| 구분 | Docker | Kubernetes |
|---|---|---|
| 주요 역할 | 컨테이너 생성 및 실행 | 컨테이너 대규모 관리 |
| 관리 대상 | 개별 컨테이너 | 여러 서버의 컨테이너 |
| 서버 환경 | 단일 서버 중심 | 다중 서버 클러스터 |
| 자동 복구 | 제한적 | 지원 |
| 자동 확장 | 직접 구현 | 지원 |
| 로드 밸런싱 | 별도 구성 | Service 기반 구성 가능 |
| 무중단 배포 | 직접 구성 | Deployment 기반 지원 |
| 주요 목적 | 애플리케이션 컨테이너화 | 컨테이너 오케스트레이션 |
관계를 그림으로 표현하면 다음과 같습니다.
Docker
│
│ Container 생성
▼
Container Image
│
│ Kubernetes 배포
▼
Kubernetes Cluster
│
├── Pod 1
├── Pod 2
├── Pod 3
└── Pod 4
Docker를 먼저 이해한 뒤 Kubernetes를 학습하는 이유도 여기에 있습니다. 컨테이너의 개념을 이해하지 못하면 Kubernetes의 구조를 이해하기 어렵습니다.
Kubernetes는 여러 대의 서버를 하나의 클러스터로 구성합니다.
기본적인 구조는 다음과 같습니다.
Kubernetes Cluster
│
┌──────────┴──────────┐
│ │
Control Plane Worker Node
│ │
│ Pods 실행
│
├── API Server
├── Scheduler
├── Controller Manager
└── etcd
Kubernetes 클러스터는 크게 Control Plane과 Worker Node로 구성됩니다.
Control Plane은 Kubernetes 클러스터를 관리하는 핵심 영역입니다.
쉽게 말하면 클러스터의 관리자 역할을 수행합니다.
주요 구성 요소는 다음과 같습니다.
Control Plane
│
├── API Server
├── Scheduler
├── Controller Manager
└── etcd
API Server는 Kubernetes의 모든 요청을 처리하는 중심 역할을 합니다.
예를 들어 관리자가 다음 명령어를 실행합니다.
kubectl apply -f deployment.yaml
요청 흐름은 다음과 같습니다.
Administrator
│
▼
kubectl
│
▼
API Server
│
▼
Kubernetes Control Plane
Kubernetes의 대부분의 관리 작업은 API를 통해 이루어집니다.
Scheduler는 새로운 Pod를 어떤 서버에 배치할지 결정합니다.
예를 들어 Worker Node가 3개 있다고 가정해 보겠습니다.
Worker Node 1
CPU 30%
Memory 40%
Worker Node 2
CPU 80%
Memory 70%
Worker Node 3
CPU 20%
Memory 30%
새로운 Pod가 생성되면 Scheduler는 다양한 조건을 고려하여 적절한 Node에 배치합니다.
New Pod
│
▼
Scheduler
│
▼
Worker Node 3
Controller Manager는 Kubernetes의 원하는 상태를 지속적으로 관리합니다.
예를 들어 관리자가 다음과 같이 설정합니다.
FastAPI Pod 3개 유지
현재 상태가 다음과 같다고 가정해 보겠습니다.
Pod 1 실행 중
Pod 2 실행 중
Pod 3 장애 발생
현재 Pod는 2개뿐입니다.
Controller는 원하는 상태와 현재 상태를 비교합니다.
원하는 상태: Pod 3개
현재 상태: Pod 2개
차이를 발견하면 새로운 Pod를 생성합니다.
Pod 1
Pod 2
Pod 3 새로 생성
이것이 Kubernetes의 자동 복구 개념입니다.
etcd는 Kubernetes 클러스터의 중요한 정보를 저장하는 분산 키-값 저장소입니다.
예를 들어 다음과 같은 정보가 저장됩니다.
Cluster Configuration
Node Information
Pod Information
Deployment Information
Service Information
Secret Information
Kubernetes에서 etcd는 매우 중요한 구성 요소이므로 운영 환경에서는 백업과 복구 전략이 필요합니다.
Worker Node는 실제 애플리케이션이 실행되는 서버입니다.
예를 들어 다음과 같습니다.
Worker Node 1
│
├── Pod A
├── Pod B
└── Pod C
Worker Node 2
│
├── Pod D
└── Pod E
Worker Node는 물리 서버일 수도 있고 가상 머신일 수도 있습니다.
실무에서는 다음과 같은 환경으로 구성할 수 있습니다.
VMware
│
├── Kubernetes Control Plane VM
│
├── Kubernetes Worker VM 1
│
├── Kubernetes Worker VM 2
│
└── Kubernetes Worker VM 3
또는 클라우드 환경에서도 사용할 수 있습니다.
AWS
│
└── Kubernetes Cluster
Azure
│
└── Kubernetes Cluster
Google Cloud
│
└── Kubernetes Cluster
Pod는 Kubernetes에서 가장 기본적인 배포 단위입니다.
Docker에서는 컨테이너를 직접 실행합니다.
Docker
│
▼
Container
Kubernetes에서는 일반적으로 Pod를 생성합니다.
Kubernetes
│
▼
Pod
│
▼
Container
즉, Kubernetes에서 직접 관리하는 기본 단위는 컨테이너가 아니라 Pod입니다.
일반적인 구조는 다음과 같습니다.
Pod
│
└── FastAPI Container
하나의 Pod 안에는 하나 이상의 컨테이너가 포함될 수 있습니다.
Pod
│
├── Application Container
│
└── Sidecar Container
예를 들어 애플리케이션 컨테이너와 로그 수집 컨테이너를 하나의 Pod로 구성할 수도 있습니다.
Pod
│
├── FastAPI
│
└── Log Collector
Pod 내부의 컨테이너는 네트워크와 저장 공간의 일부를 공유할 수 있습니다.
하지만 실무에서는 서로 독립적으로 확장해야 하는 애플리케이션을 같은 Pod에 무조건 넣는 것은 권장되지 않습니다.
간단한 Nginx Pod는 YAML 파일로 만들 수 있습니다.
파일 이름을 nginx-pod.yaml로 생성합니다.
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
생성합니다.
kubectl apply -f nginx-pod.yaml
Pod 상태를 확인합니다.
kubectl get pods
출력 예시는 다음과 같습니다.
NAME READY STATUS RESTARTS
nginx-pod 1/1 Running 0
Pod 상세 정보를 확인합니다.
kubectl describe pod nginx-pod
Pod 로그를 확인합니다.
kubectl logs nginx-pod
Pod 내부에 접속할 수도 있습니다.
kubectl exec -it nginx-pod -- /bin/bash
하지만 실제 서비스에서는 Pod를 직접 생성하는 방식보다 Deployment를 사용하는 경우가 많습니다.
Deployment는 애플리케이션의 Pod를 선언하고 관리하는 Kubernetes 객체입니다.
예를 들어 다음과 같이 선언할 수 있습니다.
FastAPI Pod 3개 유지
Deployment의 구조는 다음과 같습니다.
Deployment
│
▼
ReplicaSet
│
├── Pod 1
├── Pod 2
└── Pod 3
관리자가 직접 Pod 하나하나를 관리할 필요가 없습니다.
Deployment가 원하는 상태를 관리합니다.
Desired State
│
▼
FastAPI Pod 3개
현재 상태가 다음과 같다고 가정해 보겠습니다.
Pod 1 정상
Pod 2 정상
Pod 3 장애
Deployment는 자동으로 새로운 Pod를 생성합니다.
Deployment
│
├── Pod 1
├── Pod 2
└── New Pod 3
이것이 Kubernetes가 가진 대표적인 Self-Healing 기능입니다.
Nginx를 3개 실행하는 Deployment를 만들어 보겠습니다.
nginx-deployment.yaml 파일을 생성합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
이 파일의 핵심은 다음과 같습니다.
replicas: 3
즉, Pod를 3개 유지하라는 의미입니다.
적용합니다.
kubectl apply -f nginx-deployment.yaml
Deployment를 확인합니다.
kubectl get deployment
Pod를 확인합니다.
kubectl get pods
예상 구조는 다음과 같습니다.
Nginx Deployment
│
▼
ReplicaSet
│
┌───┼───┐
│ │ │
Pod Pod Pod
1 2 3
ReplicaSet은 지정된 개수의 Pod가 실행되도록 유지하는 역할을 합니다.
예를 들어 다음과 같습니다.
replicas = 3
정상 상태입니다.
Pod 1 Running
Pod 2 Running
Pod 3 Running
Pod 하나가 삭제되었다고 가정해 보겠습니다.
kubectl delete pod nginx-pod-xxxxx
그러면 일시적으로 다음과 같은 상태가 됩니다.
Pod 1 Running
Pod 2 Running
ReplicaSet은 원하는 개수가 부족하다는 것을 확인합니다.
원하는 상태 = 3
현재 상태 = 2
새로운 Pod를 생성합니다.
Pod 1 Running
Pod 2 Running
Pod 3 New Running
이러한 자동 복구 기능 때문에 Kubernetes는 대규모 서비스 운영에 적합합니다.
Pod는 영구적인 서버가 아닙니다.
Pod가 삭제되거나 재생성되면 IP 주소가 변경될 수 있습니다.
Old Pod
IP: 10.0.1.10
장애 발생
│
▼
New Pod
IP: 10.0.1.25
애플리케이션이 Pod의 IP 주소를 직접 사용하면 문제가 발생합니다.
이 문제를 해결하기 위해 Service를 사용합니다.
Client
│
▼
Service
│
├── Pod 1
├── Pod 2
└── Pod 3
Service는 고정된 접근 지점을 제공합니다.
예를 들어 FastAPI 서비스가 3개의 Pod로 구성되어 있다면 다음과 같습니다.
FastAPI Service
│
├── FastAPI Pod 1
├── FastAPI Pod 2
└── FastAPI Pod 3
클라이언트는 특정 Pod가 아니라 Service에 연결합니다.
Frontend
│
▼
backend-service
│
├── Pod 1
├── Pod 2
└── Pod 3
Service가 적절한 Pod로 요청을 전달합니다.
실제 애플리케이션을 Kubernetes에서 구성하면 다음과 같은 구조가 됩니다.
Internet
│
▼
Ingress
│
▼
Service
│
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
Pod 1 Pod 2 Pod 3
│ │ │
└──────────┼──────────┘
│
FastAPI
│
▼
Database Service
│
▼
PostgreSQL
각 Kubernetes 객체의 역할을 정리하면 다음과 같습니다.
| 구성 요소 | 역할 |
| Cluster | Kubernetes 전체 환경 |
| Control Plane | 클러스터 관리 |
| Node | 실제 Pod가 실행되는 서버 |
| Pod | 컨테이너 실행 단위 |
| Deployment | Pod 배포 및 관리 |
| ReplicaSet | 지정된 수의 Pod 유지 |
| Service | Pod에 안정적인 네트워크 제공 |
| Ingress | 외부 HTTP/HTTPS 요청 처리 |
서비스 사용자가 증가하면 Pod를 늘릴 수 있습니다.
처음에는 다음과 같습니다.
FastAPI Deployment
Pod 1
Pod 2
Pod 3
트래픽이 증가하면 Pod를 10개로 확장할 수 있습니다.
kubectl scale deployment fastapi --replicas=10
그러면 다음과 같이 변경됩니다.
FastAPI Deployment
Pod 1
Pod 2
Pod 3
Pod 4
Pod 5
Pod 6
Pod 7
Pod 8
Pod 9
Pod 10
Kubernetes는 수동 확장뿐 아니라 CPU와 메모리 사용량을 기준으로 자동 확장하는 구조도 구성할 수 있습니다.
CPU Usage 30%
│
▼
Pod 3개 유지
CPU Usage 80%
│
▼
Pod 6개로 증가
이러한 기능은 클라우드 환경과 함께 사용할 때 특히 강력합니다.
운영 중인 애플리케이션을 업데이트할 때 모든 서버를 동시에 중지하면 서비스 장애가 발생할 수 있습니다.
기존 방식은 다음과 같습니다.
Application Stop
│
▼
New Version Deploy
│
▼
Application Start
서비스가 중단되는 시간이 발생합니다.
Kubernetes의 Deployment는 Rolling Update 방식으로 배포할 수 있습니다.
Version 1.0
Pod A
Pod B
Pod C
새로운 버전을 배포합니다.
Version 1.1
New Pod A 생성
│
▼
정상 동작 확인
│
▼
Old Pod A 종료
이 과정을 반복합니다.
Old Pod A → New Pod A
Old Pod B → New Pod B
Old Pod C → New Pod C
구조는 다음과 같습니다.
Rolling Update
Old Pod
│
▼
New Pod 생성
│
▼
Health Check
│
▼
Old Pod 종료
서비스를 완전히 중단하지 않고 새로운 버전으로 변경할 수 있다는 것이 큰 장점입니다.
Docker Compose는 여러 컨테이너를 하나의 서버에서 관리하는 데 매우 편리합니다.
Single Server
│
Docker Compose
│
├── Nginx
├── FastAPI
├── PostgreSQL
└── Redis
Kubernetes는 여러 서버에서 대규모 컨테이너를 관리하는 데 적합합니다.
Kubernetes Cluster
│
┌───┼───┐
│ │
Node 1 Node 2
│ │
Pods Pods
따라서 학습 순서는 다음과 같이 진행하는 것이 좋습니다.
Linux
↓
Docker
↓
Docker Compose
↓
Container Network
↓
Container Storage
↓
Kubernetes
↓
Kubernetes Deployment
↓
Service
↓
Ingress
↓
Helm
처음부터 Kubernetes를 학습하기보다 Docker와 Docker Compose를 충분히 이해한 후 Kubernetes로 넘어가는 것이 좋습니다.
처음 Kubernetes를 학습할 때는 다음과 같은 환경을 사용할 수 있습니다.
Windows / Mac
│
▼
VirtualBox 또는 Hyper-V
│
├── Rocky Linux VM
│
├── Rocky Linux VM
│
└── Rocky Linux VM
클러스터 구조는 다음과 같이 만들 수 있습니다.
Kubernetes Cluster
Control Plane
192.168.10.10
Worker Node 1
192.168.10.11
Worker Node 2
192.168.10.12
개념을 학습하는 단계에서는 단일 노드 환경도 사용할 수 있습니다.
Single Node Kubernetes
│
├── Control Plane
└── Worker Node
학습이 진행되면 실제 여러 Node를 구성하여 클러스터 장애와 Pod 재배치를 실습하는 것이 좋습니다.
Kubernetes 학습을 위해 다음과 같은 프로젝트를 구성할 수 있습니다.
Internet
│
▼
Ingress
│
├── Frontend Service
│ │
│ ├── Vue Pod 1
│ └── Vue Pod 2
│
└── Backend Service
│
├── FastAPI Pod 1
├── FastAPI Pod 2
└── FastAPI Pod 3
│
▼
PostgreSQL
실습 목표는 다음과 같습니다.
1. Kubernetes Cluster 구축
2. kubectl 설치 및 연결
3. Pod 생성
4. Deployment 생성
5. Pod 복제
6. Service 생성
7. Nginx Ingress 구성
8. 애플리케이션 배포
9. Rolling Update
10. 장애 발생 시 자동 복구 확인
11. Pod 수동 확장
12. 자동 확장 구성
Kubernetes를 학습할 때는 명령어만 외우기보다 각 구성 요소의 관계를 이해하는 것이 중요합니다.
가장 중요한 구조는 다음과 같습니다.
Developer
│
▼
Docker Image 생성
│
▼
Container Registry
│
▼
Kubernetes Deployment
│
▼
ReplicaSet
│
▼
Pod
│
▼
Container
사용자의 요청은 다음 구조를 통해 전달됩니다.
User
│
▼
Internet
│
▼
Ingress
│
▼
Service
│
▼
Pod
│
▼
Container
장애가 발생하면 다음과 같이 처리됩니다.
Pod 장애
│
▼
Kubernetes 감지
│
▼
현재 상태 확인
│
▼
원하는 Pod 개수 확인
│
▼
새로운 Pod 생성
이 흐름을 이해하면 Kubernetes의 핵심 개념을 훨씬 쉽게 이해할 수 있습니다.
Kubernetes는 단순히 Docker 컨테이너를 실행하는 도구가 아닙니다. 여러 서버에 분산된 컨테이너를 자동으로 배포하고, 장애가 발생하면 복구하며, 서비스 트래픽에 따라 확장하고, 새로운 버전을 안정적으로 배포할 수 있도록 도와주는 컨테이너 오케스트레이션 플랫폼입니다.
이번 글에서 반드시 기억해야 할 핵심은 다음과 같습니다.
Docker
│
└── 컨테이너 생성과 실행
Kubernetes
│
└── 대규모 컨테이너 관리
그리고 Kubernetes의 가장 중요한 기본 구조는 다음과 같습니다.
Cluster
│
├── Control Plane
│
└── Worker Node
│
▼
Pod
│
▼
Container
애플리케이션을 실제로 운영할 때는 다음 구조를 기억하면 됩니다.
Deployment
│
▼
ReplicaSet
│
▼
Pod 여러 개
│
▼
Container
외부 요청은 다음과 같이 처리됩니다.
Internet
│
▼
Ingress
│
▼
Service
│
▼
Pod
│
▼
Application
Docker와 Docker Compose가 하나의 서버에서 컨테이너 기반 서비스를 구축하는 기술이라면, Kubernetes는 여러 서버와 대규모 컨테이너 환경을 자동으로 운영하기 위한 기술입니다.