Docker & Kubernetes 입문 가이드 | 컨테이너부터 오케스트레이션까지
이 글의 핵심
Docker 컨테이너 기초부터 Kubernetes 클러스터까지. 실습 예제 위주의 컨테이너·오케스트레이션 입문. 실전 예제와 코드로 개념부터 활용까지 정리합니다. Docker·Kubernetes·Container 중심으로 설명합니다.
이 글의 핵심
이미지·컨테이너·Compose로 로컬을 맞춘 뒤, Pod·Deployment·Service까지 Kubernetes 맥락을 잡는다. “한 번에 전부”보다는 자주 쓰는 경로를 따라가게 정리했다.
역사 한 줄과 왜 지금 Docker·Kubernetes인가
격리는 오래전부터 있었습니다. 유닉스의 chroot(1982)는 프로세스가 보는 루트 디렉터리를 바꿔 파일 시스템 관점의 감옥을 만들었고, 이후 FreeBSD jail, Linux namespaces와 cgroups가 합쳐지며 “가벼운 격리”가 성숙했습니다. Docker(2013년 전후, dotCloud에서 공개)는 이런 커널 기능을 이미지·레지스트리·CLI로 포장해, 애플리케이션을 재현 가능한 단위로 나누기 쉽게 만들었습니다. 즉 Docker의 핵심은 “가상 OS를 또 올린다”가 아니라, 같은 커널 위에서 프로세스 묶음을 패키징한다는 점입니다.
Kubernetes는 구글 내부의 Borg 경험을 바탕으로, 컨테이너가 많아졌을 때 생기는 문제—어디에 몇 개 띄울지, 죽으면 어떻게 다시 띄울지, 서로 어떻게 찾을지—를 선언적으로 풀려는 오케스트레이션입니다. 2015년 공개 이후 CNCF로 이관되어 생태계가 커졌고, 지금은 “VM 한 대에 Compose”에서 시작해 팀·트래픽·규정이 커지면 클러스터를 검토하는 식의 단계적 도입이 흔합니다.
아래 사전 지식 절의 VM 대비 도표는 “왜 컨테이너가 가벼운가”를 보여 주고, 이어지는 장들은 그다음 무엇을 맞춰야 운영이 되는가(이미지, Compose, kubectl)를 실습 중심으로 이어집니다. 한 번에 외울 필요 없이, 로컬 한 스택을 먼저 재현하고 필요할 때마다 절을 다시 열어도 됩니다.
사전 지식 (초보자를 위한 기초)
1. 가상화란?
가상화는 한 대의 물리 서버에서 여러 환경을 나눠 돌리는 기술이다.
전통적인 방식:
┌─────────────────┐
│ 애플리케이션 │
├─────────────────┤
│ 운영체제 │
├─────────────────┤
│ 물리 서버 │
└─────────────────┘
가상 머신 (VM):
┌─────────────────┐
│ 앱 A │ 앱 B │
├─────────┼───────┤
│ OS A │ OS B │ ← 각각 전체 OS 필요 (무거움)
├─────────────────┤
│ 하이퍼바이저 │
├─────────────────┤
│ 물리 서버 │
└─────────────────┘
컨테이너 (Docker):
┌─────────────────┐
│ 앱 A │ 앱 B │
├─────────┼───────┤
│ Docker Engine │ ← OS 공유 (가벼움)
├─────────────────┤
│ 운영체제 │
├─────────────────┤
│ 물리 서버 │
└─────────────────┘
차이점:
- VM: 전체 OS 포함, 무겁고 느림 (GB 단위)
- 컨테이너: OS 커널 공유, 가볍고 빠름 (MB 단위)
2. 왜 Docker를 사용할까?
“내 컴퓨터에서는 되는데…” 문제 해결!
개발자 A의 환경:
- Python 3.9
- PostgreSQL 13
- Ubuntu 20.04
개발자 B의 환경:
- Python 3.11
- PostgreSQL 15
- macOS
→ 같은 코드인데 다르게 동작할 수 있다.
Docker를 쓰면 같은 이미지를 기준으로 맞추기 쉬워져서, 환경 차이로 생기는 디버깅을 줄이는 데 도움이 된다.
3. 컨테이너의 장점
이식성 (Portability)
# 개발 환경에서 테스트
docker run myapp
# 프로덕션 환경에서도 동일하게 실행
docker run myapp
격리성 (Isolation)
컨테이너 A: Node.js 14
컨테이너 B: Node.js 18
→ 서로 영향 없이 독립적으로 실행
효율성 (Efficiency)
VM: 부팅 시간 수 분, 메모리 GB 단위
컨테이너: 시작 시간 수 초, 메모리 MB 단위
1. Docker란 무엇인가?
Docker의 핵심 개념
Docker는 애플리케이션을 컨테이너로 묶어 실행하는 플랫폼이다.
Docker 구성 요소:
┌─────────────────────────────────┐
│ Docker Image │ ← 실행 파일 (레시피)
│ (읽기 전용, 불변) │
└─────────────────────────────────┘
↓ docker run
┌─────────────────────────────────┐
│ Docker Container │ ← 실행 중인 인스턴스
│ (읽기/쓰기, 실행 중) │
└─────────────────────────────────┘
이미지는 읽기 전용 레이어의 묶음이고, 컨테이너는 그 위에서 돌아가는 프로세스·쓰기 레이어까지 포함한 실행 단위다.
Docker 아키텍처
┌──────────────────────────────────────┐
│ Docker Client (CLI) │
│ docker run, docker build │
└──────────────┬───────────────────────┘
│ REST API
┌──────────────▼───────────────────────┐
│ Docker Daemon │
│ - 이미지 관리 │
│ - 컨테이너 실행 │
│ - 네트워크 관리 │
└──────────────┬───────────────────────┘
│
┌──────────────▼───────────────────────┐
│ Docker Registry │
│ (Docker Hub) │
│ - 이미지 저장소 │
└──────────────────────────────────────┘
2. Docker 설치 및 기본 명령어
Docker 설치
Windows/Mac:
# Docker Desktop 다운로드 및 설치
# https://www.docker.com/products/docker-desktop
Linux (Ubuntu):
# Docker 설치
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# 현재 사용자를 docker 그룹에 추가
sudo usermod -aG docker $USER
# 설치 확인
docker --version
# Docker version 24.0.7, build afdd53b
기본 명령어
1) 이미지 다운로드 및 실행
# Docker Hub에서 이미지 다운로드
docker pull nginx
# 컨테이너 실행
docker run -d -p 8080:80 --name my-nginx nginx
# -d: 백그라운드 실행
# -p 8080:80: 호스트 8080 포트를 컨테이너 80 포트로 매핑
# --name: 컨테이너 이름 지정
# 브라우저에서 http://localhost:8080 접속 → Nginx 페이지 확인
2) 컨테이너 관리
# 실행 중인 컨테이너 목록
docker ps
# 모든 컨테이너 목록 (중지된 것 포함)
docker ps -a
# 컨테이너 중지
docker stop my-nginx
# 컨테이너 시작
docker start my-nginx
# 컨테이너 재시작
docker restart my-nginx
# 컨테이너 삭제
docker rm my-nginx
# 컨테이너 로그 확인
docker logs my-nginx
# 컨테이너 내부 접속
docker exec -it my-nginx bash
3) 이미지 관리
# 이미지 목록
docker images
# 이미지 삭제
docker rmi nginx
# 사용하지 않는 이미지 정리
docker image prune
# 모든 리소스 정리 (컨테이너, 이미지, 볼륨, 네트워크)
docker system prune -a
3. Dockerfile 작성법
Dockerfile이란?
Dockerfile은 이미지를 빌드하기 위한 설계도다.
Node.js 애플리케이션 예제
1) 프로젝트 구조
my-app/
├── Dockerfile
├── package.json
├── package-lock.json
└── server.js
2) server.js
// 변수 선언 및 초기화
const express = require('express');
const app = express();
const PORT = 3000;
app.get('/', (req, res) => {
res.json({ message: 'Hello from Docker!' });
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
3) package.json
{
"name": "my-app",
"version": "1.0.0",
"dependencies": {
"express": "^4.18.0"
},
"scripts": {
"start": "node server.js"
}
}
4) Dockerfile
# 1. 베이스 이미지 선택
FROM node:18-alpine
# 2. 작업 디렉토리 설정
WORKDIR /app
# 3. 의존성 파일 복사
COPY package*.json ./
# 4. 의존성 설치
RUN npm install --production
# 5. 애플리케이션 코드 복사
COPY . .
# 6. 포트 노출
EXPOSE 3000
# 7. 실행 명령어
CMD ["npm", "start"]
5) 이미지 빌드 및 실행
# 이미지 빌드
docker build -t my-app:1.0 .
# 컨테이너 실행
docker run -d -p 3000:3000 --name my-app my-app:1.0
# 테스트
curl http://localhost:3000
# {"message":"Hello from Docker!"}
Dockerfile 최적화
레이어 캐싱 활용
# ❌ 비효율적 (코드 변경 시 매번 npm install)
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN npm install
CMD ["npm", "start"]
# ✅ 효율적 (package.json 변경 시만 npm install)
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["npm", "start"]
멀티 스테이지 빌드
# 빌드 스테이지
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 프로덕션 스테이지
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]
# 이미지 크기: 1GB → 100MB
4. Docker Compose 활용
Docker Compose란?
Docker Compose는 여러 컨테이너를 한 번에 띄우고 묶어 주는 도구다.
실전 예제: Node.js + PostgreSQL + Redis
docker-compose.yml
version: '3.8'
services:
# Node.js 애플리케이션
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://user:password@db:5432/mydb
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
volumes:
- ./src:/app/src # 코드 변경 시 자동 반영
# PostgreSQL 데이터베이스
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mydb
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
# Redis 캐시
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
postgres_data:
실행 명령어
# 모든 서비스 시작
docker-compose up -d
# 로그 확인
docker-compose logs -f
# 특정 서비스 로그
docker-compose logs -f app
# 서비스 중지
docker-compose down
# 볼륨까지 삭제
docker-compose down -v
5. Kubernetes 기초
Kubernetes란?
Kubernetes (K8s)는 컨테이너를 배포·확장·복구까지 자동화하려는 오케스트레이션 플랫폼이다.
Docker: 컨테이너 실행
Kubernetes: 수백 개의 컨테이너를 자동으로 관리
예시:
- 컨테이너가 죽으면 자동으로 재시작
- 트래픽 증가 시 자동으로 컨테이너 추가
- 로드 밸런싱 자동 처리
Kubernetes 아키텍처
┌─────────────────────────────────────────┐
│ Control Plane (마스터) │
│ - API Server: 모든 요청 처리 │
│ - Scheduler: Pod 배치 결정 │
│ - Controller: 상태 관리 │
│ - etcd: 클러스터 데이터 저장 │
└─────────────┬───────────────────────────┘
│
┌─────────┼─────────┐
│ │ │
┌───▼───┐ ┌──▼────┐ ┌──▼────┐
│ Node1 │ │ Node2 │ │ Node3 │ ← Worker Nodes
│ Pod A │ │ Pod B │ │ Pod C │
│ Pod D │ │ Pod E │ │ │
└───────┘ └───────┘ └───────┘
핵심 개념
Pod
- 가장 작은 배포 단위
- 1개 이상의 컨테이너 포함
- 같은 Pod 내 컨테이너는 IP 공유 Deployment
- Pod의 선언적 업데이트
- 롤링 업데이트, 롤백 지원
- 레플리카 수 관리 Service
- Pod에 대한 네트워크 접근
- 로드 밸런싱
- 고정된 IP/DNS 제공
6. Kubernetes 설치 및 기본 명령어
Minikube 설치 (로컬 테스트용)
# macOS
brew install minikube
# Windows (Chocolatey)
choco install minikube
# Linux
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
# Minikube 시작
minikube start
# kubectl 설치 확인
kubectl version --client
기본 kubectl 명령어
# 클러스터 정보
kubectl cluster-info
# 노드 목록
kubectl get nodes
# Pod 목록
kubectl get pods
# 모든 리소스 목록
kubectl get all
# 상세 정보
kubectl describe pod <pod-name>
# 로그 확인
kubectl logs <pod-name>
# Pod 내부 접속
kubectl exec -it <pod-name> -- bash
7. Pod와 Deployment
Pod 생성
nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
# Pod 생성
kubectl apply -f nginx-pod.yaml
# Pod 확인
kubectl get pods
# Pod 삭제
kubectl delete pod nginx-pod
Deployment 생성
nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3 # 3개의 Pod 실행
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
# Deployment 생성
kubectl apply -f nginx-deployment.yaml
# Deployment 확인
kubectl get deployments
# Pod 확인 (3개 생성됨)
kubectl get pods
# 스케일링 (5개로 증가)
kubectl scale deployment nginx-deployment --replicas=5
# 롤링 업데이트
kubectl set image deployment/nginx-deployment nginx=nginx:1.26
# 롤백
kubectl rollout undo deployment/nginx-deployment
# 업데이트 상태 확인
kubectl rollout status deployment/nginx-deployment
8. Service와 Ingress
Service 생성
nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: LoadBalancer # ClusterIP, NodePort, LoadBalancer
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
# Service 생성
kubectl apply -f nginx-service.yaml
# Service 확인
kubectl get services
# Minikube에서 서비스 접속
minikube service nginx-service
Service 타입 비교
1. ClusterIP (기본값)
- 클러스터 내부에서만 접근 가능
- 외부 노출 안됨
2. NodePort
- 각 노드의 특정 포트로 접근 가능
- 포트 범위: 30000-32767
3. LoadBalancer
- 클라우드 로드 밸런서 자동 생성
- 외부 IP 할당
9. 실전 예제
예제 1: Node.js 애플리케이션 배포
1) Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
2) deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:1.0
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: "production"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secret
---
key: url
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
type: LoadBalancer
selector:
app: myapp
ports:
- port: 80
targetPort: 3000
3) 배포
# 이미지 빌드
docker build -t myapp:1.0 .
# Minikube에 이미지 로드
minikube image load myapp:1.0
# Secret 생성
kubectl create secret generic db-secret \
--from-literal=url='postgresql://user:pass@db:5432/mydb'
# 배포
kubectl apply -f deployment.yaml
# 확인
kubectl get all
예제 2: ConfigMap과 Secret
configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_NAME: "MyApp"
LOG_LEVEL: "info"
API_URL: "https://api.example.com"
secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
stringData:
DB_PASSWORD: "mypassword"
API_KEY: "secret-key-123"
deployment에서 사용
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
containers:
- name: myapp
image: myapp:1.0
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: app-secret
10. 헬스 체크 및 모니터링
Liveness와 Readiness Probe
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
containers:
- name: myapp
image: myapp:1.0
ports:
- containerPort: 3000
# Liveness Probe (컨테이너 살아있는지 확인)
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 3
# Readiness Probe (트래픽 받을 준비 됐는지 확인)
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
헬스 체크 엔드포인트 구현
// server.js
app.get('/health', (req, res) => {
// 컨테이너가 살아있는지 확인
res.status(200).json({ status: 'ok' });
});
app.get('/ready', (req, res) => {
// DB 연결 등 확인
if (dbConnected) {
res.status(200).json({ status: 'ready' });
} else {
res.status(503).json({ status: 'not ready' });
}
});
11. 볼륨과 영속성
Volume 타입
1) emptyDir (임시 볼륨)
apiVersion: v1
kind: Pod
metadata:
name: cache-pod
spec:
containers:
- name: app
image: myapp
volumeMounts:
- name: cache
mountPath: /app/cache
volumes:
- name: cache
emptyDir: {} # Pod 삭제 시 데이터 삭제
2) PersistentVolume (영구 볼륨)
# PersistentVolume
apiVersion: v1
kind: PersistentVolume
metadata:
name: postgres-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /data/postgres
---
# PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
# Deployment에서 사용
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
template:
spec:
containers:
- name: postgres
image: postgres:15
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-storage
persistentVolumeClaim:
claimName: postgres-pvc
12. 네임스페이스와 리소스 관리
네임스페이스
# 네임스페이스 생성
kubectl create namespace dev
kubectl create namespace prod
# 특정 네임스페이스에 배포
kubectl apply -f deployment.yaml -n dev
# 네임스페이스 목록
kubectl get namespaces
# 특정 네임스페이스의 리소스 확인
kubectl get all -n dev
리소스 쿼터
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-quota
namespace: dev
spec:
hard:
requests.cpu: "10"
requests.memory: 20Gi
limits.cpu: "20"
limits.memory: 40Gi
pods: "50"
13. 실전 배포 전략
롤링 업데이트
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2 # 최대 2개 추가 Pod
maxUnavailable: 1 # 최대 1개 중단 허용
template:
spec:
containers:
- name: myapp
image: myapp:2.0
배포 과정:
초기: [v1] [v1] [v1] [v1] [v1]
1단계: [v1] [v1] [v1] [v1] [v1] [v2] [v2]
(2개 추가)
2단계: [v1] [v1] [v1] [v1] [v2] [v2]
(1개 중단)
3단계: [v1] [v1] [v1] [v2] [v2] [v2]
...
최종: [v2] [v2] [v2] [v2] [v2]
Blue-Green 배포
# Blue (현재 버전)
kubectl apply -f deployment-blue.yaml
# Green (새 버전) 배포
kubectl apply -f deployment-green.yaml
# Service를 Green으로 전환
kubectl patch service myapp -p '{"spec":{"selector":{"version":"green"}}}'
# 문제 발생 시 Blue로 롤백
kubectl patch service myapp -p '{"spec":{"selector":{"version":"blue"}}}'
14. 모니터링 및 로깅
기본 모니터링
# 리소스 사용량 확인
kubectl top nodes
kubectl top pods
# 이벤트 확인
kubectl get events --sort-by='.lastTimestamp'
# Pod 상태 확인
kubectl get pods -o wide
# 특정 Pod 상세 정보
kubectl describe pod <pod-name>
로그 수집
# 실시간 로그
kubectl logs -f <pod-name>
# 이전 컨테이너 로그 (재시작된 경우)
kubectl logs <pod-name> --previous
# 여러 Pod 로그 (label selector)
kubectl logs -l app=myapp --tail=100
15. 트러블슈팅
자주 발생하는 문제
1) ImagePullBackOff
# 증상
kubectl get pods
# NAME READY STATUS RESTARTS
# myapp-x 0/1 ImagePullBackOff 0
# 원인: 이미지를 다운로드할 수 없음
# 해결:
# - 이미지 이름 확인
# - Docker Hub 인증 확인
# - Minikube에 이미지 로드: minikube image load myapp:1.0
2) CrashLoopBackOff
# 증상
kubectl get pods
# NAME READY STATUS RESTARTS
# myapp-x 0/1 CrashLoopBackOff 5
# 원인: 컨테이너가 시작 후 바로 종료
# 해결:
kubectl logs myapp-x # 로그 확인
kubectl describe pod myapp-x # 상세 정보 확인
# 일반적인 원인:
# - 애플리케이션 에러
# - 환경 변수 누락
# - 의존성 서비스 미준비
3) Pending 상태
# 증상
kubectl get pods
# NAME READY STATUS RESTARTS
# myapp-x 0/1 Pending 0
# 원인: 스케줄링 불가
kubectl describe pod myapp-x
# 일반적인 원인:
# - 리소스 부족 (CPU, 메모리)
# - PVC 바인딩 실패
# - Node selector 미매칭
16. Docker vs Kubernetes 비교
| 항목 | Docker | Kubernetes |
|---|---|---|
| 용도 | 컨테이너 실행 | 컨테이너 오케스트레이션 |
| 규모 | 단일 호스트 | 다중 호스트 클러스터 |
| 자동 복구 | 없음 | 자동 재시작 |
| 스케일링 | 수동 | 자동 (HPA) |
| 로드 밸런싱 | 없음 | 내장 |
| 롤링 업데이트 | 없음 | 지원 |
| 학습 곡선 | 낮음 | 높음 |
| 언제 무엇을 사용할까? |
Docker만 사용:
- 개발 환경
- 소규모 프로젝트
- 단일 서버
Docker + Kubernetes:
- 프로덕션 환경
- 대규모 서비스
- 고가용성 필요
- 자동 스케일링 필요
17. 실전 팁
Docker 최적화
1) 이미지 크기 줄이기
# ❌ 큰 이미지 (1GB)
FROM node:18
COPY . .
RUN npm install
# ✅ 작은 이미지 (100MB)
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
2) .dockerignore 활용
# .dockerignore
node_modules
npm-debug.log
.git
.env
*.md
dist
coverage
Kubernetes 최적화
1) 리소스 제한 설정
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
2) Horizontal Pod Autoscaler
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
18. 다음 단계
학습 로드맵
1단계: Docker 기초
✓ 컨테이너 개념 이해
✓ 기본 명령어 숙지
✓ Dockerfile 작성
2단계: Docker 실전
✓ Docker Compose
✓ 멀티 스테이지 빌드
✓ 이미지 최적화
3단계: Kubernetes 기초
✓ Pod, Deployment
✓ Service
✓ kubectl 명령어
4단계: Kubernetes 실전
✓ ConfigMap, Secret
✓ 볼륨 관리
✓ 헬스 체크
5단계: 고급 주제
✓ Helm (패키지 관리)
✓ Ingress Controller
✓ 모니터링 (Prometheus, Grafana)
✓ CI/CD 연동
추천 학습 자료
공식 문서:
- Docker 공식 문서: https://docs.docker.com
- Kubernetes 공식 문서: https://kubernetes.io/ko/docs 실습 환경:
- Play with Docker: https://labs.play-with-docker.com
- Play with Kubernetes: https://labs.play-with-k8s.com 온라인 강의:
- Docker Mastery (Udemy)
- Kubernetes for Developers (Pluralsight)
FAQ
Q1. Docker와 VM의 차이는? VM은 게스트 OS까지 올리는 반면, 컨테이너는 호스트 커널을 공유한다. 그래서 기동·이미지 크기·오버헤드에서 보통 컨테이너가 유리하다. Q2. Kubernetes 없이 Docker만 써도 되나? 개발·스테이징·소규모 서비스는 Compose까지로도 많이 간다. 여러 노드 스케일·셀프 힐링·롤링 배포까지 표준으로 가져가려 할 때 K8s를 본격적으로 고른다. Q3. Minikube와 Docker Desktop의 Kubernetes는? Minikube는 로컬에 클러스터를 올리기 위한 도구로 잘 쓰인다. Docker Desktop에 붙은 K8s는 같은 머신에서 이미지 빌드와 묶어 쓰기 편하다. 둘 다 학습용으로 자주 고른다. Q4. 프로덕션에서 어떤 Kubernetes를 사용하나요?
- AWS: EKS (Elastic Kubernetes Service)
- GCP: GKE (Google Kubernetes Engine)
- Azure: AKS (Azure Kubernetes Service)
- 자체 호스팅: kubeadm, Rancher Q5. Docker Compose vs Kubernetes?
- Docker Compose: 단일 호스트, 개발/테스트
- Kubernetes: 다중 호스트, 프로덕션
요약
핵심 정리
Docker:
- 컨테이너로 애플리케이션 패키징
- “내 컴퓨터에서는 되는데” 문제 해결
- 가볍고 빠른 실행 Kubernetes:
- 컨테이너 오케스트레이션
- 자동 스케일링, 자동 복구
- 프로덕션 환경 필수 학습 순서:
- Docker 기본 명령어
- Dockerfile 작성
- Docker Compose
- Kubernetes 기본 개념
- kubectl 명령어
- 실전 배포
다음 글 추천
- Docker Compose 실전 가이드
- Kubernetes 배포 전략
- CI/CD 파이프라인 구축
키워드: Docker, Kubernetes, Container, k8s, kubectl, Pod, Deployment, DevOps, 컨테이너, 오케스트레이션, 마이크로서비스
심화 부록: 구현·운영 관점
이 부록은 앞선 본문에서 다룬 주제(「Docker & Kubernetes 입문 가이드 | 컨테이너부터 오케스트레이션까지」)를 구현·런타임·운영 관점에서 다시 압축합니다. 도메인별 세부 구현은 글마다 다르지만, 입력 검증 → 핵심 연산 → 부작용(I/O·네트워크·동시성) → 관측의 흐름으로 장애를 나누면 원인 추적이 빨라집니다.
내부 동작과 핵심 메커니즘
flowchart TD A[입력·요청·이벤트] --> B[파싱·검증·디코딩] B --> C[핵심 연산·상태 전이] C --> D[부작용: I/O·네트워크·동시성] D --> E[결과·관측·저장]
sequenceDiagram participant C as 클라이언트/호출자 participant B as 경계(런타임·게이트웨이·프로세스) participant D as 의존성(API·DB·큐·파일) C->>B: 요청/이벤트 B->>D: 조회·쓰기·RPC D-->>B: 지연·부분 실패·재시도 가능 B-->>C: 응답 또는 오류(코드·상관 ID)
- 불변 조건(Invariant): 버퍼 경계, 프로토콜 상태, 트랜잭션 격리, FD 상한 등 단계별로 문장으로 적어 두면 디버깅 비용이 줄어듭니다.
- 결정성: 순수 층과 시간·네트워크·스케줄에 의존하는 층을 분리해야 테스트와 장애 분석이 쉬워집니다.
- 경계 비용: 직렬화, 인코딩, syscall 횟수, 락 경합, 할당·GC, 캐시 미스를 의심 목록에 둡니다.
- 백프레셔: 생산자가 소비자보다 빠를 때 버퍼·큐·스트림에서 속도를 줄이는 신호를 어디에 둘지 정의합니다.
프로덕션 운영 패턴
| 영역 | 운영 관점 질문 |
|---|---|
| 관측성 | 요청 단위 상관 ID, 에러율·지연 p95/p99, 의존성 타임아웃·재시도가 대시보드에 보이는가 |
| 안전성 | 입력 검증·권한·비밀·감사 로그가 코드 경로마다 일관적인가 |
| 신뢰성 | 재시도는 멱등 연산에만 적용되는가, 서킷 브레이커·백오프·DLQ가 있는가 |
| 성능 | 캐시·배치 크기·커넥션 풀·인덱스·백프레셔가 데이터 규모에 맞는가 |
| 배포 | 롤백 룬북, 카나리/블루그린, 마이그레이션·피처 플래그가 문서화되어 있는가 |
| 용량 | 피크 트래픽·디스크·FD·스레드 풀 상한을 주기적으로 검증하는가 |
스테이징은 데이터 양·네트워크 RTT·동시성을 프로덕션에 가깝게 맞출수록 재현율이 올라갑니다.
확장 예시: 엔드투엔드 미니 시나리오
앞선 본문 주제(「Docker & Kubernetes 입문 가이드 | 컨테이너부터 오케스트레이션까지」)를 배포·운영 흐름에 맞춰 옮긴 체크리스트입니다. 도메인에 맞게 단계 이름만 바꿔 적용할 수 있습니다.
- 입력 계약 고정: 스키마·버전·최대 페이로드·타임아웃·에러 코드를 경계에 둔다.
- 핵심 경로 계측: 요청 ID, 단계별 지연, 외부 호출 결과 코드를 로그·메트릭·트레이스에서 한 흐름으로 본다.
- 실패 주입: 의존성 타임아웃·5xx·부분 데이터·락 대기를 스테이징에서 재현한다.
- 호환·롤백: 설정/마이그레이션/클라이언트 버전을 되돌릴 수 있는지 확인한다.
- 부하 후 검증: 피크 대비 p95/p99, 에러율, 리소스 상한, 알림 임계값을 점검한다.
handle(request):
ctx = newCorrelationId()
validated = validateSchema(request)
authorize(validated, ctx)
result = domainCore(validated)
persistOrEmit(result, idempotentKey)
recordMetrics(ctx, latency, outcome)
return result
문제 해결(Troubleshooting)
| 증상 | 가능 원인 | 조치 |
|---|---|---|
| 간헐적 실패 | 레이스, 타임아웃, 외부 의존성, DNS | 최소 재현 스크립트, 분산 트레이스·로그 상관관계, 재시도·서킷 설정 점검 |
| 성능 저하 | N+1, 동기 I/O, 락 경합, 과도한 직렬화, 캐시 미스 | 프로파일러·APM으로 핫스팟 확인 후 한 가지씩 제거 |
| 메모리 증가 | 캐시 무제한, 구독/리스너 누수, 대용량 버퍼, 커넥션 미반납 | 상한·TTL·힙/FD 스냅샷 비교 |
| 빌드·배포만 실패 | 환경 변수, 권한, 플랫폼 차이, lockfile | CI 로그와 로컬 diff, 런타임·이미지 버전 핀 |
| 설정 불일치 | 프로필·시크릿·기본값, 리전 | 스키마 검증된 설정 단일 소스와 배포 매트릭스 표준화 |
| 데이터 불일치 | 비멱등 재시도, 부분 쓰기, 캐시 무효화 누락 | 멱등 키·아웃박스·트랜잭션 경계 재검토 |
권장 순서: (1) 최소 재현 (2) 최근 변경 범위 축소 (3) 환경·의존성 차이 (4) 관측으로 가설 검증 (5) 수정 후 회귀·부하 테스트.
배포 전에는 git add → git commit → git push 후 npm run deploy 순서를 권장합니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- Kubernetes 실전 가이드 | Pod·Deployment
- Kubernetes 완벽 가이드: 컨테이너 오케스트레이션
- Docker Compose 완벽 가이드 | 멀티 컨테이너·네트워크·볼륨·환경 변수
이 글에서 다루는 키워드 (관련 검색어)
Docker, Kubernetes, Container, DevOps, k8s, kubectl, Pod, Deployment, 컨테이너, 오케스트레이션 등으로 검색하시면 이 글이 도움이 됩니다.