근묵자흑
Kubernetes Pattern: Stateless Service 본문
들어가며
Kubernetes는 서버가 갑자기 다운되었을 때, 자동으로 복구되고 사용자는 서비스 중단을 느끼지 못하도록 설계되었습니다.
(Kubernetes는 self-healing과 high availability를 통해 서버 장애 시에도 사용자는 서비스 중단을 느끼지 못합니다.)
이번장은 그것을 어떻게 가능하게 구현하는지 Stateless Service 패턴에 대해 얘기해보겠습니다.
클라우드 네이티브 환경에서 애플리케이션은 언제든지 죽고, 다시 살아날 수 있어야 합니다.
이것이 바로 Stateless Service 패턴의 핵심입니다.
이 글에서는 Kubernetes Patterns 11장 Stateless Service를 실제 실습 및 테스트한 결과와 함께 어떻게 활용할 수 있는지 알아보겠습니다.
Stateless Service 패턴이란?
정의
Stateless Service는 인스턴스 간 상호작용에서 내부적으로 어떤 상태도 유지하지 않는 서비스입니다. 각 요청은 완전히 독립적으로 처리되며, 과거의 요청이나 세션 정보에 의존하지 않습니다.
Kubernetes 환경에서는 이러한 Stateless 애플리케이션을 여러 개의 동일한 Pod으로 실행하여, 다음과 같은 이점을 얻을 수 있습니다:
- 고가용성: 하나의 Pod이 죽어도 다른 Pod이 즉시 트래픽을 처리
- 확장성: 필요에 따라 Pod 개수를 쉽게 늘리거나 줄임
- 자동 복구: 장애 발생 시 자동으로 새 Pod 생성
- 무중단 배포: 롤링 업데이트로 서비스 중단 없이 배포
핵심 특징: I.R.E
Stateless Service의 모든 인스턴스(Pod)는 다음 세 가지 특징을 가집니다:
1. Identical (동일성)
모든 Pod이 기능적으로 완전히 동일합니다.
- 같은 컨테이너 이미지 사용
- 동일한 설정과 환경 변수
- 같은 코드 실행
2. Replaceable (교체 가능성)
어떤 Pod이든 즉시 삭제하고 교체할 수 있습니다.
- 특정 Pod에 대한 의존성 없음
- 언제든지 새로운 Pod으로 대체 가능
- 사용자는 Pod 교체를 인지하지 못함
3. Ephemeral (일시성)
Pod의 생명주기는 짧고 언제든 사라질 수 있습니다.
- Pod 내부에 중요한 상태 저장 금지
- 영구 데이터는 외부 스토리지나 DB에 저장
- Pod은 "소모품"처럼 취급
12-Factor App과의 관계
Stateless Service 패턴은 12-Factor App 원칙을 따릅니다:
- VI. Processes: 앱을 하나 이상의 무상태 프로세스로 실행
- VIII. Concurrency: 프로세스 모델을 통해 확장
- IX. Disposability: 빠른 시작과 graceful shutdown
Stateless Service 실습
이제 실제로 Stateless Service를 구현하고 테스트해보겠습니다.
우리는 간단한 랜덤 숫자를 반환하는 REST API 서비스를 사용할 것입니다.
환경 준비 (참고)
# 테스트 환경
- Minikube
- 이미지: k8spatterns/random-generator:1.0
실습 1: ReplicaSet으로 Pod 복제하기
3개의 동일한 Pod을 생성하는 ReplicaSet을 만들어보겠습니다.
# replicaset.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: random-generator
spec:
replicas: 3 # 3개의 복제본 유지
selector:
matchLabels:
app: random-generator
template:
metadata:
labels:
app: random-generator
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
ports:
- containerPort: 8080
protocol: TCP
실행:
kubectl apply -f replicaset.yml
kubectl get pods -l app=random-generator
결과:
NAME READY STATUS RESTARTS AGE
random-generator-8948h 1/1 Running 0 9s
random-generator-bnw54 1/1 Running 0 9s
random-generator-xbjkx 1/1 Running 0 9s
확인 포인트:
- 3개의 Pod이 모두
Running상태 - 모든 Pod이 동일한 이름 패턴 (
random-generator-xxxxx) - ReplicaSet이 DESIRED=CURRENT=READY=3으로 일치
kubectl get rs random-generator
NAME DESIRED CURRENT READY AGE
random-generator 3 3 3 17s
실습 2: Self-Healing 확인하기
Stateless Service의 가장 강력한 기능 중 하나는 Self-Healing입니다.
Pod 하나를 강제로 삭제하고, ReplicaSet이 어떻게 수행되는지 확인하겠습니다.
실행:
# 첫 번째 Pod 삭제
kubectl get pods -l app=random-generator -o name | head -1 | xargs kubectl delete
# 즉시 확인
kubectl get pods -l app=random-generator -w
결과:
NAME READY STATUS RESTARTS AGE
random-generator-bnw54 1/1 Running 0 77s
random-generator-p96nl 1/1 Running 0 11s ← 새로 생성됨!
random-generator-xbjkx 1/1 Running 0 77s
무슨 일이 일어났나?
random-generator-8948hPod이 삭제됨- ReplicaSet Controller가 변화를 감지
- 선언된 상태(replicas: 3)와 현재 상태(2개)가 불일치함을 발견
- 즉시 새로운 Pod
random-generator-p96nl생성 - 다시 3개의 Pod이 유지됨
이것이 바로 Kubernetes의 선언적 관리(Declarative Management)입니다.
우리는 "3개의 Pod을 유지하라"고 선언했고, Kubernetes는 이 상태를 지속적으로 유지합니다.
실습 3: Service로 로드밸런싱 구현하기
이제 3개의 Pod에 트래픽을 분산하는 Service를 만들어보겠습니다.
# service.yml
apiVersion: v1
kind: Service
metadata:
name: random-generator
spec:
selector:
app: random-generator # ReplicaSet과 동일한 label
ports:
- port: 8080
protocol: TCP
targetPort: 8080
type: ClusterIP
실행:
kubectl apply -f service.yml
kubectl get svc random-generator
kubectl get endpoints random-generator
결과:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
random-generator ClusterIP None <none> 8080/TCP 1m
NAME ENDPOINTS
random-generator 10.1.0.38:8080,10.1.0.34:8080,10.1.0.37:8080
Service가 3개의 Pod IP를 Endpoint로 자동 등록한걸 확인할 수 있습니다.
로드밸런싱 테스트:
# 5번 요청을 보내봅시다
for i in {1..5}; do
kubectl run test-curl-$i --image=curlimages/curl --rm -i --restart=Never --quiet \
-- -s http://random-generator:8080
done
결과:
Request 1: {"random":1962907337,"id":"516fb2c2-6992-4cb3...","version":"1.0"}
Request 2: {"random":-61271774,"id":"d850fc5c-0913-4108...","version":"1.0"}
Request 3: {"random":328143425,"id":"35996d4b-a1d8-4dd6...","version":"1.0"}
Request 4: {"random":-1387919917,"id":"516fb2c2-6992-4cb3...","version":"1.0"}
Request 5: {"random":-2102010644,"id":"d850fc5c-0913-4108...","version":"1.0"}
분석:
- Request 1, 4: 같은 Pod (
516fb2c2...) - Request 2, 5: 같은 Pod (
d850fc5c...) - Request 3: 다른 Pod (
35996d4b...)
총 3개의 서로 다른 Pod에 요청이 분산되었습니다!
이것이 Kubernetes의 자동 로드밸런싱입니다.
실습 4: PersistentVolume으로 스토리지 공유하기
여러 Pod이 외부 스토리지를 공유할 수 있습니다.
# pv-and-pvc.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: example
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 10Mi
storageClassName: standard
hostPath:
path: /tmp/example
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: random-generator-log
spec:
accessModes:
- ReadWriteOnce
storageClassName: standard
resources:
requests:
storage: 10Mi
volumeName: example
replicaset-with-pv.yml (볼륨 마운트 추가)
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: random-generator
spec:
replicas: 3
selector:
matchLabels:
app: random-generator
template:
metadata:
labels:
app: random-generator
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
env:
- name: POD_ID
valueFrom:
fieldRef:
fieldPath: metadata.uid
- name: LOG_FILE
value: /tmp/logs/random-$(POD_ID).log
volumeMounts:
- mountPath: /tmp/logs
name: log-volume
volumes:
- name: log-volume
persistentVolumeClaim:
claimName: random-generator-log
실행:
# PV/PVC 생성
kubectl apply -f pv-and-pvc.yml
# ReplicaSet 업데이트
kubectl apply -f replicaset-with-pv.yml
# Pod 재시작
kubectl delete pod -l app=random-generator
확인:
kubectl get pv,pvc
결과:
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM
persistentvolume/example 10Mi RWO Retain Bound default/random-generator-log
NAME STATUS VOLUME CAPACITY ACCESS MODES
persistentvolumeclaim/random-generator-log Bound example 10Mi RWO
PVC가 성공적으로 Bound 되었습니다
Pod에서 확인:
POD_NAME=$(kubectl get pods -l app=random-generator -o name | head -1)
kubectl describe $POD_NAME | grep -A 5 "Volumes:"
Volumes:
log-volume:
Type: PersistentVolumeClaim
ClaimName: random-generator-log
ReadOnly: false
핵심 포인트:
- Pod은 Stateless이지만, 외부 스토리지는 사용 가능
- 모든 Pod이 동일한 볼륨을 공유
- 각 Pod은
POD_ID환경 변수로 고유한 로그 파일 생성 - Pod이 재시작되어도 데이터는 보존됨
동작 원리
Service 로드밸런싱 메커니즘
Service가 어떻게 트래픽을 분산하는가?
- Service 생성 시:
- Service는
selector로 Pod들을 찾음 - 일치하는 Pod들의 IP를 Endpoints에 자동 등록
- Service는
- kube-proxy 동작:
- 각 노드의 kube-proxy가 iptables 규칙 생성
- Service IP로 오는 트래픽을 Pod IP로 NAT
- 기본적으로 랜덤 방식으로 분산
- DNS 등록:
- CoreDNS가
random-generator.default.svc.cluster.local등록 - 클러스터 내에서 서비스 이름으로 접근 가능
- CoreDNS가
언제 Stateless Service 패턴을 사용해야 할까?
적합한 사용 사례
- REST API 서버
예: User API, Product API, Order API - 각 요청이 독립적 - 세션 정보는 Redis/DB에 저장
- 웹 애플리케이션 프론트엔드
예: React, Vue, Angular SPA - 정적 파일 서빙 - API 호출만 수행
- 마이크로서비스
예: Payment Service, Notification Service - 서비스 간 독립성 - 수평 확장 필요
- 배치 작업 워커
예: 이미지 처리, 데이터 변환 - 작업 큐에서 작업 가져옴 - 병렬 처리
- 프록시/게이트웨이
예: Nginx, Envoy, API Gateway - 요청 라우팅 - 부하 분산
부적합한 사용 사례
- 데이터베이스
MySQL, PostgreSQL, MongoDB → StatefulSet 사용
- 메시지 큐
RabbitMQ, Kafka → StatefulSet 사용 (순서 보장 필요)
- 분산 캐시
Redis Cluster, Memcached → StatefulSet + Headless Service
- 싱글톤 서비스
Cron Job, Leader Election → Singleton Service 패턴 사용
- 세션 기반 애플리케이션
메모리에 세션 저장하는 레거시 앱 → Session Affinity 또는 외부 세션 스토어 필요
Best Practices
1. 무상태 설계 원칙
# 나쁜 예: 메모리에 상태 저장
class UserService:
def __init__(self):
self.sessions = {} # 메모리에 세션 저장
def login(self, user_id):
self.sessions[user_id] = {...}
# 좋은 예: 외부 저장소 사용
class UserService:
def __init__(self, redis_client):
self.redis = redis_client
def login(self, user_id):
self.redis.set(f"session:{user_id}", {...})
2. Health Checks 설정
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
spec:
template:
spec:
containers:
- name: api
image: myapi:1.0
# Readiness Probe: 트래픽 받을 준비 확인
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
# Liveness Probe: 애플리케이션 살아있는지 확인
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
# Startup Probe: 초기 시작 확인 (느린 시작 대비)
startupProbe:
httpGet:
path: /health/startup
port: 8080
failureThreshold: 30
periodSeconds: 10
3. 리소스 관리
resources:
requests:
memory: "128Mi" # 최소 보장
cpu: "250m" # 0.25 core
limits:
memory: "256Mi" # 최대 사용량
cpu: "500m" # 0.5 core
리소스 설정 가이드:
requests: 스케줄링 기준, Pod이 반드시 확보할 리소스limits: 최대 사용량, 초과 시 Throttling(CPU) 또는 OOMKilled(Memory)- CPU는 압축 가능(compressible), Memory는 비압축(incompressible)
4. Horizontal Pod Autoscaler (HPA)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-server-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-server
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # 5분간 안정화
policies:
- type: Percent
value: 50
periodSeconds: 60
5. Rolling Update 전략
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 최대 1개 추가 Pod 생성 가능
maxUnavailable: 1 # 최대 1개 Pod 중단 가능
template:
spec:
containers:
- name: api
image: myapi:2.0
# Graceful Shutdown
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 15"]
Rolling Update 동작:
- 새 버전 Pod 1개 생성 (maxSurge: 1)
- 새 Pod이 Ready 상태 확인
- 기존 Pod 1개 종료 (maxUnavailable: 1)
- 모든 Pod이 교체될 때까지 반복
6. Pod Disruption Budget (PDB)
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-server-pdb
spec:
minAvailable: 2 # 최소 2개는 항상 실행 중이어야 함
selector:
matchLabels:
app: api-server
PDB는 자발적 중단(voluntary disruption) 시 최소 가용성을 보장합니다:
- 노드 드레인(drain)
- 클러스터 업그레이드
- 수동 Pod 삭제
7. Anti-Affinity 설정
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
spec:
template:
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- api-server
topologyKey: kubernetes.io/hostname
이렇게 하면 Pod들이 서로 다른 노드에 분산 배치되어 단일 노드 장애에도 서비스 가능합니다.
트러블슈팅
문제 1: Pod이 계속 재시작됨
증상:
kubectl get pods
NAME READY STATUS RESTARTS AGE
api-server-abc123 0/1 CrashLoopBackOff 5 3m
원인 및 해결:
# 로그 확인
kubectl logs api-server-abc123
# 이전 컨테이너 로그 확인
kubectl logs api-server-abc123 --previous
# Pod 이벤트 확인
kubectl describe pod api-server-abc123
일반적인 원인:
- 애플리케이션 에러 → 코드 수정
- Health Check 실패 → Probe 설정 조정
- 리소스 부족 (OOMKilled) → Memory Limit 증가
- 환경 변수 누락 → ConfigMap/Secret 확인
문제 2: Service로 접근 불가
확인 절차:
# 1. Pod이 실행 중인지 확인
kubectl get pods -l app=api-server
# 2. Service의 Selector가 맞는지 확인
kubectl describe svc api-server
# 3. Endpoints가 생성되었는지 확인
kubectl get endpoints api-server
# 4. Pod의 라벨 확인
kubectl get pods --show-labels
해결 방법:
# Service의 selector와 Pod의 labels가 일치해야 함
Service:
selector:
app: api-server # ← 이것과
Pod:
labels:
app: api-server # ← 이것이 일치
문제 3: HPA가 스케일하지 않음
확인:
kubectl get hpa
kubectl describe hpa api-server-hpa
# Metrics Server 확인
kubectl top nodes
kubectl top pods
일반적인 원인:
- Metrics Server 미설치
resources.requests미설정
- 메트릭 수집 지연
좀 더 들어가서: VPA (Vertical Pod Autoscaler)
VPA란?
Vertical Pod Autoscaler (VPA)는 Pod의 CPU와 Memory 리소스를 자동으로 조정하는 Kubernetes 컴포넌트입니다.
HPA가 Pod의 개수를 조정한다면, VPA는 각 Pod의 크기를 조정합니다.
VPA의 3가지 핵심 기능
1. 리소스 자동 조정
VPA는 실제 사용량을 분석하여 최적의 CPU/Memory 값을 자동으로 적용합니다.
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: vpa-test-app-auto
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: my-app
updatePolicy:
updateMode: "Auto" # 자동으로 리소스 조정
2. 과다/과소 할당 감지
실제 테스트 결과:
# 의도적으로 매우 작은 리소스 설정
resources:
requests:
memory: "10Mi" # ← 너무 작음!
cpu: "10m"
# VPA 추천값
kubectl get vpa
NAME MODE CPU MEM PROVIDED
my-app-vpa Off 25m 250Mi True
결과:
- 현재 설정: Memory 10Mi → OOMKilled 발생!
- VPA 추천: Memory 250Mi → 25배 증가 필요
이것이 바로 과소 할당 감지입니다.
3. 최적 값 추천
VPA는 4가지 추천값을 제공합니다:
recommendation:
containerRecommendations:
- containerName: app
lowerBound: # 최소 필요량
cpu: 25m
memory: 250Mi
target: # 권장값 (이 값 사용 권장)
cpu: 25m
memory: 250Mi
upperBound: # 피크 시 안전 마진 포함
cpu: 25m
memory: 1Gi
uncappedTarget: # 제한 없는 이상적 값
cpu: 25m
memory: 250Mi
VPA 실습
1. VPA 설치
# VPA 저장소 클론
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler
# VPA 설치
./hack/vpa-up.sh
# 설치 확인
kubectl get pods -n kube-system | grep vpa
결과:
vpa-admission-controller 1/1 Running
vpa-recommender 1/1 Running
vpa-updater 1/1 Running
2. VPA 추천 모드 테스트
# vpa-recommender-only.yml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: my-app
updatePolicy:
updateMode: "Off" # 추천만 제공, 자동 적용 안 함
resourcePolicy:
containerPolicies:
- containerName: app
minAllowed:
cpu: 10m
memory: 10Mi
maxAllowed:
cpu: 1000m
memory: 1Gi
적용 및 확인:
kubectl apply -f vpa-recommender-only.yml
# 추천값 확인 (수 분 후)
kubectl describe vpa my-app-vpa
3. VPA Auto 모드 (자동 적용)
# vpa-auto-mode.yml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa-auto
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: my-app
updatePolicy:
updateMode: "Auto" # 자동으로 적용!
resourcePolicy:
containerPolicies:
- containerName: app
controlledResources: ["cpu", "memory"]
동작 과정:
- VPA Recommender가 메트릭 수집 및 분석
- 현재 리소스와 추천값 비교
- 차이가 크면 VPA Updater가 Pod을 evict
- 새 Pod이 생성될 때 VPA Admission Controller가 추천값 주입
VPA vs HPA 비교
| 특징 | VPA | HPA |
|---|---|---|
| 조정 대상 | Pod 리소스 (CPU/Memory) | Pod 개수 |
| 방향 | Vertical (수직) | Horizontal (수평) |
| Pod 재시작 | ✅ 필요 | ❌ 불필요 |
| 적용 시점 | 분 단위 | 초 단위 |
| 적합한 경우 | 리소스 최적화 | 부하 분산 |
| 비용 영향 | 개별 Pod 비용 감소 | Pod 수 증가 |
VPA의 장단점
장점
- 자동 리소스 최적화
수동: 개발자가 추측으로 설정 → 비효율VPA: 실제 사용량 기반 최적값 → 효율적
- 비용 절감
과다 할당: 1000Mi → 실제 사용 250MiVPA 적용: 300Mi (여유 포함)절감: 700Mi × Pod 수 × 시간당 요금
- OOMKilled 예방
- 메모리 부족 미리 감지
- 자동으로 리소스 증가
단점 및 제한사항
- Pod 재시작 필요
VPA는 리소스 변경을 위해 Pod을 재시작합니다! → 서비스 중단 가능성 → PodDisruptionBudget 필수
- HPA와 동시 사용 불가 (CPU/Memory 기준)
❌ 불가: - VPA: CPU requests 조정 - HPA: CPU 사용률 기준 스케일링 → 충돌 발생!✅ 가능: - VPA: CPU/Memory requests 조정 - HPA: Custom Metrics (RPS, Queue) 기준
- 초기 데이터 필요
- 최소 8시간의 메트릭 데이터 필요
- 새 앱은 추천값 불안정
VPA 사용 권장 사례
적합한 경우
- Stateless 애플리케이션
- 재시작 가능한 워커
- 리소스 사용량이 변동적인 경우
- 리소스 설정이 어려운 새 애플리케이션
부적합한 경우
- Stateful 애플리케이션 (DB, 메시지 큐)
- 재시작에 민감한 서비스 (WebSocket)
- HPA를 CPU/Memory 기준으로 사용 중
실무 적용 팁
1. 단계적 적용
# 1단계: Off 모드로 시작 (추천만)
updateMode: "Off"
→ 추천값 확인 후 수동 적용
# 2단계: Initial 모드 (새 Pod만)
updateMode: "Initial"
→ 새 Pod 생성 시에만 적용
# 3단계: Auto 모드 (안정화 후)
updateMode: "Auto"
→ 실시간 자동 조정
2. PodDisruptionBudget 설정
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
spec:
minAvailable: 1 # VPA가 Pod 재시작 시에도 최소 1개 유지
selector:
matchLabels:
app: my-app
3. 리소스 정책 설정
resourcePolicy:
containerPolicies:
- containerName: app
minAllowed:
cpu: 100m # 최소값 제한
memory: 128Mi
maxAllowed:
cpu: 2000m # 최대값 제한
memory: 4Gi
controlledResources: ["cpu", "memory"]
테스트 결과 요약
- 과소 할당 정확히 감지
- 설정: 10Mi → 실패 (OOMKilled)
- VPA 추천: 250Mi → 성공!
- 추천값의 정확성
- Spring Boot 앱의 실제 필요량을 정확히 파악
- 25배 메모리 증가 필요성 식별
- 자동 업데이트 동작
- VPA Updater가 Pod 자동 evict
- 새 Pod에 추천 리소스 적용
Stateless vs Stateful 비교
| 특징 | Stateless Service | Stateful Service |
|---|---|---|
| 상태 저장 | ❌ 내부 상태 없음 | ✅ 내부 상태 유지 |
| Pod 교체 | ✅ 자유롭게 가능 | ⚠️ 신중히 처리 |
| 확장성 | ✅ 쉬운 수평 확장 | ⚠️ 복잡한 확장 |
| 사용 리소스 | ReplicaSet/Deployment | StatefulSet |
| 네트워크 ID | 불안정 (IP 변경됨) | 안정적 (고정 DNS) |
| 스토리지 | 선택적 (PV) | 필수 (PVC per Pod) |
| 배포 순서 | 병렬 배포 | 순차 배포 |
| 예시 | REST API, 웹서버 | DB, 메시지큐 |
참고 자료
- Kubernetes Patterns 책
- 12-Factor App
- Kubernetes 공식 문서
- GitHub 예제 코드
'k8s > kubernetes-pattern' 카테고리의 다른 글
| Service Discovery 심화: Knative (2) | 2025.11.01 |
|---|---|
| Kubernetes Pattern: Service Discovery (4) | 2025.10.25 |
| Kubernetes Pattern: Stateful Service (0) | 2025.10.11 |
| Kubernetes Pattern: Singleton Service (2) | 2025.09.27 |
| Kubernetest Pattern: DaemonService (4) | 2025.09.20 |