Docker & Kubernetes 완전 정복 6편: Kubernetes 기초 - 개념과 아키텍처
Docker & Kubernetes Complete Guide Part 6: Kubernetes Basics - Concepts and Architecture
서론: 컨테이너 오케스트레이션의 표준
지금까지 Docker를 통해 컨테이너를 생성하고 관리하는 방법을 배웠습니다. 하지만 실제 프로덕션 환경에서는 수십, 수백 개의 컨테이너를 여러 서버에 걸쳐 운영해야 합니다. 이때 각 컨테이너를 수동으로 관리하는 것은 사실상 불가능합니다.
이번 6편에서는 컨테이너 오케스트레이션의 사실상 표준이 된 Kubernetes(쿠버네티스, K8s)의 기초 개념과 아키텍처를 살펴보겠습니다. Kubernetes가 무엇인지, 왜 필요한지, 그리고 어떻게 구성되어 있는지 이해하면 클라우드 네이티브 환경에서의 애플리케이션 운영에 대한 전체적인 그림을 그릴 수 있습니다.
1. Kubernetes란?
1.1 Kubernetes의 정의
Kubernetes는 컨테이너화된 애플리케이션의 배포, 확장, 관리를 자동화하는 오픈소스 플랫폼입니다. 그리스어로 "조타수" 또는 "파일럿"을 의미하며, 컨테이너라는 "화물"을 적절히 운반하고 관리하는 역할을 합니다.
"K8s"라는 약칭은 K와 s 사이에 8글자(ubernete)가 있다는 것에서 유래했습니다.
1.2 Kubernetes의 역사
- 2014년: Google이 내부에서 사용하던 Borg 시스템의 경험을 바탕으로 Kubernetes를 오픈소스로 공개
- 2015년: 버전 1.0 릴리스, Cloud Native Computing Foundation(CNCF)에 기부
- 2018년: CNCF의 첫 번째 "졸업" 프로젝트
- 현재: 컨테이너 오케스트레이션의 사실상 표준으로 자리매김
1.3 Kubernetes가 제공하는 기능
- 서비스 디스커버리와 로드 밸런싱: DNS 이름이나 IP 주소로 컨테이너를 노출하고, 트래픽을 분산
- 스토리지 오케스트레이션: 로컬 스토리지, 클라우드 스토리지 등을 자동으로 마운트
- 자동화된 롤아웃과 롤백: 애플리케이션 변경 사항을 점진적으로 배포하고, 문제 시 이전 버전으로 롤백
- 자동 빈 패킹(Bin Packing): 리소스 요구사항에 따라 컨테이너를 노드에 최적 배치
- 자가 치유(Self-healing): 실패한 컨테이너를 재시작하고, 응답하지 않는 컨테이너를 교체
- 시크릿과 구성 관리: 민감한 정보를 안전하게 저장하고 관리
2. 왜 Kubernetes가 필요한가?
2.1 Docker만으로는 부족한 이유
단일 서버에서 몇 개의 컨테이너를 운영할 때는 Docker만으로 충분합니다. 하지만 실제 프로덕션 환경에서는 다음과 같은 요구사항이 있습니다:
- 수백 개의 컨테이너를 여러 서버에 분산 배포
- 트래픽 증가 시 자동으로 컨테이너 수 확장
- 컨테이너 장애 시 자동 복구
- 무중단 배포 (Rolling Update, Blue-Green, Canary)
- 컨테이너 간 네트워크 및 스토리지 관리
- 리소스 모니터링 및 로깅
2.2 컨테이너 오케스트레이션의 필요성
컨테이너 오케스트레이션이란 컨테이너의 배포, 관리, 확장, 네트워킹을 자동화하는 것을 말합니다. 오케스트라의 지휘자가 여러 악기를 조율하듯이, 컨테이너 오케스트레이터는 수많은 컨테이너를 조율합니다.
| 수동 관리의 문제점 | 오케스트레이션의 해결책 |
|---|---|
| 서버 장애 시 수동 복구 필요 | 자동 장애 감지 및 복구 |
| 트래픽 증가 시 수동 확장 | 자동 스케일링 (HPA, VPA) |
| 배포 시 다운타임 발생 | 무중단 롤링 업데이트 |
| 컨테이너 배치 최적화 어려움 | 자동 스케줄링 및 빈 패킹 |
| 서비스 간 통신 복잡 | 서비스 디스커버리 및 로드 밸런싱 |
2.3 Kubernetes vs 다른 오케스트레이션 도구
- Docker Swarm: Docker 네이티브 오케스트레이션, 단순하지만 기능이 제한적
- Apache Mesos: 범용 클러스터 관리 도구, 학습 곡선이 높음
- Nomad: HashiCorp의 오케스트레이션 도구, 가벼움
- Kubernetes: 가장 많은 기능, 가장 큰 생태계, 사실상 표준
3. Kubernetes 아키텍처
Kubernetes 클러스터는 크게 Control Plane(컨트롤 플레인)과 Worker Node(워커 노드)로 구성됩니다.
3.1 Control Plane (마스터 노드)
Control Plane은 클러스터의 "두뇌" 역할을 합니다. 클러스터의 상태를 관리하고, 워커 노드에서 실행될 워크로드를 스케줄링합니다.
3.1.1 API Server (kube-apiserver)
Kubernetes의 모든 통신의 중심입니다. kubectl 명령, 다른 컴포넌트, 외부 클라이언트 모두 API Server를 통해 클러스터와 상호작용합니다.
- RESTful API 제공
- 인증(Authentication), 권한 부여(Authorization) 처리
- 요청의 유효성 검사
- etcd와의 유일한 통신 창구
3.1.2 etcd
클러스터의 모든 상태 데이터를 저장하는 분산 키-값 저장소입니다.
- 클러스터 구성, 상태, 메타데이터 저장
- 고가용성을 위해 보통 3개 또는 5개의 인스턴스로 구성
- Raft 합의 알고리즘 사용
- 클러스터 백업 = etcd 백업
3.1.3 Scheduler (kube-scheduler)
새로 생성된 Pod를 어떤 노드에 배치할지 결정합니다.
- 리소스 요구사항 (CPU, 메모리) 고려
- 노드의 가용 리소스 확인
- 어피니티/안티어피니티 규칙 적용
- 테인트(Taint)와 톨러레이션(Toleration) 처리
3.1.4 Controller Manager (kube-controller-manager)
클러스터의 상태를 원하는 상태로 유지하는 다양한 컨트롤러들을 실행합니다.
- Node Controller: 노드 상태 모니터링
- Replication Controller: Pod 개수 유지
- Endpoints Controller: 서비스와 Pod 연결
- Service Account Controller: 계정 및 토큰 생성
3.1.5 Cloud Controller Manager (선택사항)
클라우드 제공자의 API와 통합하여 클라우드 특화 기능을 관리합니다.
- 로드 밸런서 프로비저닝
- 스토리지 볼륨 관리
- 노드 관리 (클라우드 인스턴스)
3.2 Worker Node
Worker Node는 실제 애플리케이션 컨테이너가 실행되는 서버입니다.
3.2.1 kubelet
각 노드에서 실행되는 에이전트로, Pod의 생명주기를 관리합니다.
- API Server로부터 Pod 명세(PodSpec) 수신
- 컨테이너 런타임에 컨테이너 생성/삭제 요청
- 컨테이너 상태 모니터링 및 보고
- 노드 상태 정보를 API Server에 보고
3.2.2 kube-proxy
각 노드에서 네트워크 프록시 역할을 수행합니다.
- Service의 가상 IP를 실제 Pod IP로 매핑
- iptables 또는 IPVS 규칙 관리
- 클러스터 내부 및 외부 트래픽 라우팅
- 로드 밸런싱 (라운드 로빈)
3.2.3 Container Runtime
실제로 컨테이너를 실행하는 소프트웨어입니다.
- containerd: Docker에서 분리된 업계 표준 런타임
- CRI-O: Kubernetes 전용 경량 런타임
- Docker Engine: Kubernetes 1.24부터 직접 지원 중단 (dockershim 제거)
3.3 아키텍처 다이어그램
┌─────────────────────────────────────────────────────────────────┐
│ CONTROL PLANE │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ API Server │ │ Scheduler │ │ Controller │ │
│ │ │ │ │ │ Manager │ │
│ └──────┬──────┘ └─────────────┘ └─────────────┘ │
│ │ │
│ ┌──────┴──────┐ │
│ │ etcd │ │
│ │ (Key-Value) │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
│ (API 통신)
│
┌─────────────────────────────────────────────────────────────────┐
│ WORKER NODE 1 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ kubelet │ │ kube-proxy │ │ Container │ │
│ │ │ │ │ │ Runtime │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Pod 1 │ │ Pod 2 │ │ Pod 3 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────────────┘
4. Kubernetes 핵심 오브젝트
4.1 Pod
Pod는 Kubernetes에서 생성하고 관리할 수 있는 가장 작은 배포 단위입니다.
Pod의 특징:
- 하나 이상의 컨테이너를 포함
- 같은 Pod의 컨테이너는 네트워크와 스토리지를 공유
- 같은 Pod의 컨테이너는 localhost로 통신
- 일반적으로 하나의 주 컨테이너 + 보조 컨테이너(Sidecar)
- Pod는 일시적(ephemeral) - 언제든 삭제되고 재생성될 수 있음
# pod-example.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.24
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
4.2 Service
Service는 Pod 집합에 대한 안정적인 네트워크 엔드포인트를 제공합니다. Pod의 IP는 변할 수 있지만, Service의 IP(ClusterIP)는 고정됩니다.
Service 타입:
- ClusterIP (기본값): 클러스터 내부에서만 접근 가능
- NodePort: 각 노드의 특정 포트로 외부 접근 허용
- LoadBalancer: 클라우드 로드 밸런서를 통한 외부 접근
- ExternalName: 외부 DNS 이름을 클러스터 내부로 매핑
# service-example.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx # 이 라벨을 가진 Pod에 트래픽 전달
ports:
- protocol: TCP
port: 80 # Service 포트
targetPort: 80 # Pod의 컨테이너 포트
type: ClusterIP
4.3 Deployment
Deployment는 Pod의 선언적 업데이트를 제공합니다. 원하는 상태를 정의하면 Deployment Controller가 실제 상태를 원하는 상태로 만들어줍니다.
Deployment의 기능:
- Pod 개수(replicas) 관리
- 롤링 업데이트 및 롤백
- 스케일링 (수동/자동)
- Pod 템플릿 관리
# deployment-example.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3 # 3개의 Pod 유지
selector:
matchLabels:
app: nginx
template: # Pod 템플릿
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.24
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 롤링 업데이트 시 추가 생성할 Pod 수
maxUnavailable: 0 # 롤링 업데이트 시 사용 불가 Pod 수
4.4 Namespace
Namespace는 클러스터를 논리적으로 분리하는 가상 클러스터입니다.
기본 Namespace:
- default: 별도 지정 없이 생성되는 리소스의 기본 네임스페이스
- kube-system: Kubernetes 시스템 컴포넌트용
- kube-public: 모든 사용자가 읽을 수 있는 공개 리소스
- kube-node-lease: 노드 하트비트 정보 저장
# namespace-example.yaml
apiVersion: v1
kind: Namespace
metadata:
name: development
labels:
environment: dev
---
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
environment: prod
Namespace 활용:
- 환경 분리 (dev, staging, production)
- 팀별 리소스 분리
- 리소스 쿼터(ResourceQuota) 적용
- 네트워크 정책(NetworkPolicy) 적용
5. kubectl 기초
kubectl은 Kubernetes 클러스터와 상호작용하는 커맨드라인 도구입니다.
5.1 kubectl 설치
# macOS (Homebrew)
brew install kubectl
# Windows (Chocolatey)
choco install kubernetes-cli
# Linux (curl)
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/
5.2 기본 명령어 구조
kubectl [command] [TYPE] [NAME] [flags]
# 예시
kubectl get pods # 모든 Pod 조회
kubectl get pod nginx-pod # 특정 Pod 조회
kubectl get pods -n kube-system # kube-system 네임스페이스의 Pod 조회
kubectl get pods -o wide # 상세 정보 포함 조회
kubectl get pods -o yaml # YAML 형식으로 출력
5.3 자주 사용하는 명령어
리소스 조회 (get)
# Pod 목록 조회
kubectl get pods
kubectl get pods -A # 모든 네임스페이스
# Service 목록 조회
kubectl get services
kubectl get svc # 약어 사용
# Deployment 목록 조회
kubectl get deployments
kubectl get deploy # 약어 사용
# 여러 리소스 동시 조회
kubectl get pods,services,deployments
# 라벨로 필터링
kubectl get pods -l app=nginx
# 모든 리소스 조회
kubectl get all
리소스 상세 정보 (describe)
# Pod 상세 정보
kubectl describe pod nginx-pod
# Node 상세 정보
kubectl describe node node-1
# Service 상세 정보
kubectl describe service nginx-service
리소스 생성 (create, apply)
# YAML 파일로 리소스 생성
kubectl apply -f deployment.yaml
# 디렉토리의 모든 YAML 파일 적용
kubectl apply -f ./manifests/
# 명령형으로 리소스 생성
kubectl create deployment nginx --image=nginx:1.24
kubectl create namespace my-namespace
# Dry-run (실제로 생성하지 않고 테스트)
kubectl apply -f deployment.yaml --dry-run=client
리소스 수정 (edit, patch, scale)
# 리소스 직접 편집 (에디터 열림)
kubectl edit deployment nginx-deployment
# 패치로 부분 수정
kubectl patch deployment nginx-deployment -p '{"spec":{"replicas":5}}'
# 스케일 조정
kubectl scale deployment nginx-deployment --replicas=5
리소스 삭제 (delete)
# 특정 리소스 삭제
kubectl delete pod nginx-pod
kubectl delete deployment nginx-deployment
# YAML 파일에 정의된 리소스 삭제
kubectl delete -f deployment.yaml
# 라벨로 삭제
kubectl delete pods -l app=nginx
# 네임스페이스와 그 안의 모든 리소스 삭제
kubectl delete namespace development
로그 및 디버깅
# Pod 로그 조회
kubectl logs nginx-pod
kubectl logs nginx-pod -f # 실시간 로그 스트리밍
kubectl logs nginx-pod --previous # 이전 컨테이너 로그
# 다중 컨테이너 Pod에서 특정 컨테이너 로그
kubectl logs nginx-pod -c sidecar
# Pod 내부에서 명령 실행
kubectl exec nginx-pod -- ls /usr/share/nginx/html
kubectl exec -it nginx-pod -- /bin/bash # 대화형 쉘
# 포트 포워딩 (로컬에서 Pod 접근)
kubectl port-forward pod/nginx-pod 8080:80
kubectl port-forward service/nginx-service 8080:80
5.4 컨텍스트와 네임스페이스 관리
# 현재 컨텍스트 확인
kubectl config current-context
# 사용 가능한 컨텍스트 목록
kubectl config get-contexts
# 컨텍스트 전환
kubectl config use-context my-cluster
# 기본 네임스페이스 변경
kubectl config set-context --current --namespace=development
5.5 유용한 kubectl 플러그인과 도구
# kubectx - 컨텍스트 빠른 전환
brew install kubectx
kubectx # 컨텍스트 목록 및 전환
kubens # 네임스페이스 목록 및 전환
# k9s - 터미널 UI
brew install k9s
k9s
# kubectl 자동 완성 (bash)
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc
# kubectl 별칭 설정
alias k='kubectl'
alias kgp='kubectl get pods'
alias kgs='kubectl get services'
6. 실습: 첫 번째 애플리케이션 배포
6.1 로컬 Kubernetes 환경 설정
# Docker Desktop에서 Kubernetes 활성화
# Settings > Kubernetes > Enable Kubernetes
# 또는 Minikube 사용
brew install minikube
minikube start
# 클러스터 상태 확인
kubectl cluster-info
kubectl get nodes
6.2 Nginx 배포하기
# 1. Deployment 생성
kubectl create deployment nginx-demo --image=nginx:1.24
# 2. Deployment 확인
kubectl get deployments
kubectl get pods
# 3. Service 생성 (NodePort 타입)
kubectl expose deployment nginx-demo --type=NodePort --port=80
# 4. Service 확인
kubectl get services
# 5. 접속 테스트 (Minikube)
minikube service nginx-demo
# 6. 또는 포트 포워딩
kubectl port-forward service/nginx-demo 8080:80
# 브라우저에서 http://localhost:8080 접속
6.3 스케일링 테스트
# Pod 개수 확장
kubectl scale deployment nginx-demo --replicas=5
# Pod 확인
kubectl get pods -o wide
# Pod 개수 축소
kubectl scale deployment nginx-demo --replicas=2
6.4 롤링 업데이트
# 이미지 업데이트
kubectl set image deployment/nginx-demo nginx=nginx:1.25
# 롤아웃 상태 확인
kubectl rollout status deployment/nginx-demo
# 롤아웃 히스토리
kubectl rollout history deployment/nginx-demo
# 롤백
kubectl rollout undo deployment/nginx-demo
6.5 정리
# 리소스 삭제
kubectl delete deployment nginx-demo
kubectl delete service nginx-demo
# 또는 한 번에
kubectl delete deployment,service nginx-demo
7. Kubernetes 학습 리소스
7.1 공식 문서
- Kubernetes 공식 문서: https://kubernetes.io/docs/
- Kubernetes 튜토리얼: https://kubernetes.io/docs/tutorials/
- kubectl 치트 시트: https://kubernetes.io/docs/reference/kubectl/cheatsheet/
7.2 로컬 학습 환경
- Minikube: 로컬 Kubernetes 클러스터
- Kind (Kubernetes in Docker): Docker 컨테이너로 클러스터 실행
- Docker Desktop: 내장 Kubernetes 지원
- k3s: 경량 Kubernetes 배포판
7.3 온라인 실습 환경
- Katacoda: 브라우저 기반 Kubernetes 실습
- Play with Kubernetes: 무료 온라인 Kubernetes 환경
결론
이번 6편에서는 Kubernetes의 기초 개념과 아키텍처를 살펴보았습니다. 핵심 내용을 정리하면:
- Kubernetes란: 컨테이너 오케스트레이션의 사실상 표준 플랫폼
- 아키텍처: Control Plane(API Server, etcd, Scheduler, Controller Manager)과 Worker Node(kubelet, kube-proxy, Container Runtime)로 구성
- 핵심 오브젝트: Pod(최소 배포 단위), Service(네트워크 엔드포인트), Deployment(선언적 Pod 관리), Namespace(논리적 분리)
- kubectl: Kubernetes 클러스터와 상호작용하는 CLI 도구
Kubernetes는 처음에는 복잡해 보이지만, 그 설계 철학인 "선언적 구성"과 "원하는 상태(Desired State)"를 이해하면 매우 강력하고 유연한 도구임을 알 수 있습니다.
다음 편에서는 Kubernetes 실전을 다룹니다. ConfigMap과 Secret을 통한 설정 관리, Ingress를 통한 외부 트래픽 라우팅, PersistentVolume을 통한 데이터 영속성 등 실제 운영에 필요한 심화 주제들을 살펴보겠습니다.