Docker Compose → EKS Multi-AZ HA 구성 실무 가이드
v06: 기본 구조 설계 - ALB 배치 문제 발견
사용자 → CloudFront → ALB → EKS Pods
→ S3 (정적 콘텐츠)
v07: VPC 내부/외부 서비스 구분 - 핵심 깨달음
핵심 깨달음: VPC 내부/외부 서비스를 명확히 구분해야 함
트래픽 라우팅 경로:
정적 콘텐츠: 사용자 → WAF → CloudFront → S3
동적 API: 사용자 → WAF → CloudFront → VPC → ALB → EKS Pods
v08: ALB 정확한 표현 - 논리/물리적 개념 구분
ALB 정확한 표현: 논리적 개념과 물리적 배치를 명확히 구분
v09: HA 구성 완성 - 단일 장애점 제거
AZ-1: FastAPI + PostgreSQL
AZ-2: FastAPI + Redis
→ 각각 단일 장애점
각 AZ: FastAPI + PostgreSQL + Redis
→ 완전한 분산
v10: 범례 크기 조정 - 가독성 개선
HA 설계 원칙:
🎉 최종 완성! VPC 내부/외부 서비스가 명확히 구분된 HA 아키텍처
🌐 VPC 외부: S3, CloudFront, WAF
🏠 VPC 내부: ALB (Multi-AZ), NAT Gateway, EKS (HA 구성)
현재 문제 상황:
# 현재 상태 확인
kubectl get pods -o wide
# 결과: 모든 Pod가 같은 노드에 몰려있음
장애 시나리오: AZ-2a 장애 발생 → 모든 PostgreSQL Pod 다운 → 서비스 전체 중단 💥
용어 분해:
📱 FastAPI (웹 서버) → Deployment (Stateless)
"요청 처리만 하고 끝, 메모리에 저장 안 함"
💾 PostgreSQL (데이터베이스) → StatefulSet (Stateful)
"데이터 파일 저장, 순서대로 시작/종료 필요"
🗄️ Redis (캐시) → StatefulSet (Stateful)
"메모리 데이터 보존 필요"
Anti-Affinity: "절대 같은 곳에 있으면 안 돼!" (엄격함)
Topology Spread: "가능하면 고르게 분산해줘" (유연함)
클러스터 내부에서만 접근 가능
postgres:5432 ← FastAPI에서만 접근
외부 인터넷에서 접근 가능
https://your-domain.com/api → FastAPI로 라우팅
/api/* → FastAPI, /static/* → S3infrastructure/k8s/
├── namespace.yaml
├── postgres-deployment.yaml # ❌ Deployment, replicas: 1
└── backend-deployment.yaml # ❌ 분산 정책 없음
infrastructure/k8s/
├── namespace.yaml # 네임스페이스 분리
├── postgres-deployment.yaml # ✅ StatefulSet + Anti-Affinity
├── redis-statefulset.yaml # ✅ 새로 생성 (HA 구성)
├── backend-deployment.yaml # ✅ Topology Spread 추가
├── backend-service.yaml # LoadBalancer Service
└── ingress.yaml # ✅ 새로 생성 (ALB Ingress)
infrastructure/k8s/postgres-deployment.yaml
kind: Deployment # ❌ Stateless
spec:
replicas: 1 # ❌ 단일 인스턴스
template:
spec:
# ❌ Anti-Affinity 없음
containers:
- name: postgres
# ❌ 영구 스토리지 없음
apiVersion: apps/v1
kind: StatefulSet # ✅ Stateful - 상태를 기억하는 Pod 집합
metadata:
name: postgres
spec:
serviceName: postgres # ✅ StatefulSet 필수 - 안정적인 네트워크 ID
replicas: 2 # ✅ HA 구성 - 2개 인스턴스로 가용성 확보
template:
spec:
affinity: # ✅ Anti-Affinity 추가
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 엄격한 규칙
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- postgres
topologyKey: topology.kubernetes.io/zone # AZ 단위로 분산
containers:
- name: postgres
image: postgres:15
volumeMounts: # ✅ 영구 스토리지 - 데이터 보존
- name: postgres-storage
mountPath: /var/lib/postgresql/data # PostgreSQL 데이터 디렉토리
volumeClaimTemplates: # ✅ 각 Pod마다 독립 스토리지
- metadata:
name: postgres-storage
spec:
accessModes: ["ReadWriteOnce"] # 하나의 노드에서만 읽기/쓰기
resources:
requests:
storage: 10Gi # 10GB 영구 스토리지 할당
postgres-0redis-0edustack-backend-1postgres-1redis-1edustack-backend-2Docker Compose → 기본 K8s 매니페스트 (3개 파일)
단일 인스턴스 → Multi-AZ 분산 (Anti-Affinity)
Deployment → StatefulSet (영구 스토리지)
ClusterIP → ALB Ingress (외부 접근)
| 단계 | 파일 수 | 가용성 | 확장성 | 관리 난이도 |
|---|---|---|---|---|
| Docker Compose | 1개 | 낮음 ❌ | 낮음 ❌ | 쉬움 😊 |
| 기본 K8s | 3개 | 중간 ⚠️ | 중간 ⚠️ | 보통 😐 |
| HA K8s | 6개 | 높음 ✅ | 높음 ✅ | 어려움 😅 |
잘못된 인식: ALB는 VPC 외부 서비스
올바른 이해: ALB는 VPC 내부, 퍼블릭 서브넷에 배치
위험한 구성: 모든 Pod를 하나의 AZ에 배치
안전한 구성: Multi-AZ에 균등 분산
퍼블릭 서브넷: ALB, NAT Gateway
프라이빗 서브넷: EKS 워커 노드, 애플리케이션
ALB SG: 80, 443 포트만 인터넷에서 허용
Worker SG: ALB에서만 트래픽 허용
# ALB 헬스체크 확인
kubectl get ingress
kubectl describe ingress edustack-ingress
# Pod 간 통신 테스트
kubectl exec -it fastapi-pod -- curl postgres:5432
kubectl exec -it fastapi-pod -- redis-cli -h redis ping
# 서비스 DNS 해상도 테스트
kubectl exec -it fastapi-pod -- nslookup postgres
kubectl exec -it fastapi-pod -- nslookup redis
# 현재 Pod 분산 상태 확인
kubectl get pods -o wide --show-labels
# 하나의 AZ 장애 시뮬레이션
kubectl cordon node-in-az-2a # 노드 스케줄링 중단
kubectl delete pod postgres-0 # Pod 강제 삭제
# 복구 과정 관찰
kubectl get pods -o wide -w # 실시간 상태 변화 관찰
kubectl logs postgres-1 # 남은 Pod 로그 확인
# 복구 후 정리
kubectl uncordon node-in-az-2a # 노드 스케줄링 재개
# 트래픽 분산 확인
for i in {1..10}; do
curl -s https://your-domain.com/api/edustack/health | jq .hostname
done
# ALB 타겟 그룹 상태 확인
aws elbv2 describe-target-health \
--target-group-arn arn:aws:elasticloadbalancing:... \
--profile shared-service
# Pod 리소스 사용량 모니터링
kubectl top pods
kubectl top nodes
# Pod가 Pending 상태로 멈춤
kubectl describe pod postgres-0
# 원인: 리소스 부족, Anti-Affinity 조건 불만족
# Service 연결 안됨
kubectl get endpoints postgres
# 원인: 라벨 셀렉터 불일치
# Ingress 접근 안됨
kubectl describe ingress edustack-ingress
# 원인: ALB 생성 실패, 서브넷 설정 오류
# CloudWatch 메트릭 확인
aws cloudwatch get-metric-statistics \
--namespace AWS/ApplicationELB \
--metric-name RequestCount \
--dimensions Name=LoadBalancer,Value=app/edustack-alb/... \
--start-time 2025-10-04T00:00:00Z \
--end-time 2025-10-04T23:59:59Z \
--period 3600 \
--statistics Sum
# Kubernetes 메트릭
kubectl top pods --sort-by=cpu
kubectl top pods --sort-by=memory
# HPA 설정 (Auto Scaling)
kubectl autoscale deployment edustack-backend \
--cpu-percent=70 --min=2 --max=10