IT Knowledge/DevOps/images/docker-kubernetes-기초-venn.svg
Docker & Kubernetes 기초
📌 핵심 개념
- Docker: 애플리케이션을 컨테이너로 패키징
- Kubernetes: 컨테이너 오케스트레이션 플랫폼
🎯 Docker 실전 사례
사례 1: “내 컴퓨터에서는 되는데요?” 문제 해결
Before: 환경 차이로 인한 문제
# 개발자 A (Mac)
node app.js # ✅ 잘 동작
# 개발자 B (Windows)
node app.js # ❌ 파일 경로 오류
# 운영 서버 (Linux)
node app.js # ❌ Node 버전 불일치After: Docker 사용
# Dockerfile
FROM node:18-alpine
WORKDIR /app
# 의존성 설치
COPY package*.json ./
RUN npm ci --only=production
# 애플리케이션 코드 복사
COPY . .
EXPOSE 3000
CMD ["node", "app.js"]# 모든 환경에서 동일하게 실행
docker build -t myapp .
docker run -p 3000:3000 myapp
# 개발, 스테이징, 프로덕션 모두 같은 이미지 사용사례 2: 멀티 스테이지 빌드로 이미지 크기 최적화
Before: 큰 이미지 (800MB)
FROM node:18
WORKDIR /app
COPY . .
RUN npm install # 개발 의존성도 포함
RUN npm run build
CMD ["npm", "start"]After: 멀티 스테이지 빌드 (150MB)
# 빌드 스테이지
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/package*.json ./
# 프로덕션 의존성만 설치
RUN npm ci --only=production
EXPOSE 3000
CMD ["node", "dist/index.js"]사례 3: Docker Compose로 개발 환경 구성
# docker-compose.yml
version: '3.8'
services:
# Node.js 애플리케이션
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
- REDIS_URL=redis://redis:6379
volumes:
- ./src:/app/src # 코드 수정 시 자동 반영
depends_on:
- db
- redis
# PostgreSQL 데이터베이스
db:
image: postgres:14
environment:
- POSTGRES_PASSWORD=password
- POSTGRES_DB=myapp
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
# Redis
redis:
image: redis:7-alpine
ports:
- "6379:6379"
# Nginx (리버스 프록시)
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- app
volumes:
postgres_data:# 한 명령어로 전체 스택 실행
docker-compose up -d
# 로그 확인
docker-compose logs -f app
# 종료
docker-compose down☸️ Kubernetes 실전 사례
사례 1: 트래픽 급증 시 자동 스케일링
문제: 블랙프라이데이 트래픽 폭증
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: shopping-app
spec:
replicas: 3 # 기본 3개 Pod
selector:
matchLabels:
app: shopping-app
template:
metadata:
labels:
app: shopping-app
spec:
containers:
- name: app
image: myapp:v1.0
ports:
- containerPort: 3000
resources:
requests: # 최소 리소스
memory: "128Mi"
cpu: "250m"
limits: # 최대 리소스
memory: "256Mi"
cpu: "500m"
---
# HPA (Horizontal Pod Autoscaler)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: shopping-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: shopping-app
minReplicas: 3
maxReplicas: 50 # 최대 50개까지 자동 확장
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # CPU 70% 이상이면 스케일 아웃결과:
- 평소: Pod 3개 (비용 절감)
- 트래픽 급증: 자동으로 50개까지 확장
- 트래픽 감소: 다시 3개로 축소
사례 2: 무중단 배포 (Rolling Update)
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2 # 추가로 2개까지 생성 가능
maxUnavailable: 1 # 최대 1개까지 중단 가능
template:
metadata:
labels:
app: myapp
version: v2.0 # 새 버전
spec:
containers:
- name: app
image: myapp:v2.0
readinessProbe: # 준비 상태 확인
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe: # 생존 확인
httpGet:
path: /health
port: 3000
initialDelaySeconds: 15
periodSeconds: 10# 배포 실행
kubectl apply -f deployment.yaml
# 배포 상태 확인
kubectl rollout status deployment/myapp
# 문제 발생 시 롤백
kubectl rollout undo deployment/myapp배포 과정:
- 새 Pod 2개 생성 (총 12개)
- 준비 완료되면 구 Pod 1개 제거
- 다시 새 Pod 2개 생성…
- 모든 Pod가 v2.0으로 교체될 때까지 반복
- 서비스 중단 없음!
사례 3: ConfigMap & Secret으로 설정 관리
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: "production"
LOG_LEVEL: "info"
API_URL: "https://api.example.com"
---
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
DATABASE_PASSWORD: cGFzc3dvcmQxMjM= # base64 인코딩
JWT_SECRET: c2VjcmV0a2V5 # base64 인코딩
---
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
containers:
- name: app
image: myapp:v1.0
env:
# ConfigMap에서 환경 변수 주입
- name: APP_ENV
valueFrom:
configMapKeyRef:
name: app-config
key: APP_ENV
# Secret에서 환경 변수 주입
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: DATABASE_PASSWORD
# 전체 ConfigMap을 환경 변수로
envFrom:
- configMapRef:
name: app-config# 설정 변경 (애플리케이션 코드 수정 없이)
kubectl edit configmap app-config
# Pod 재시작하여 변경사항 적용
kubectl rollout restart deployment/myapp사례 4: Ingress로 도메인 라우팅
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: "letsencrypt" # 자동 SSL
spec:
tls:
- hosts:
- www.example.com
- api.example.com
secretName: tls-secret
rules:
# www.example.com -> frontend
- host: www.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
# api.example.com -> backend
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend-service
port:
number: 3000
# api.example.com/v2 -> backend-v2
- host: api.example.com
http:
paths:
- path: /v2
pathType: Prefix
backend:
service:
name: backend-v2-service
port:
number: 3000💡 실전 팁
Docker 최적화
# ✅ 레이어 캐싱 활용
COPY package*.json ./
RUN npm install
COPY . . # 코드는 나중에 복사 (캐시 활용)
# ✅ .dockerignore 사용
# .dockerignore
node_modules
.git
*.md
.envKubernetes 디버깅
# Pod 로그 확인
kubectl logs -f pod-name
# Pod 내부 접속
kubectl exec -it pod-name -- /bin/sh
# 이벤트 확인
kubectl get events --sort-by='.lastTimestamp'
# 리소스 사용량 확인
kubectl top pods