K8s 운영 심화 — 면접 대비 정리
HPA, PodDisruptionBudget, Resource Request/Limit, 헬스체크, 롤링 업데이트 전략, 실무 운영 경험까지. K8s를 실제로 운영한 관점에서 정리한다.
K8s 핵심 오브젝트 복습
Cluster
└── Node (물리/가상 서버)
└── Pod (컨테이너 실행 단위)
└── Container
Deployment → ReplicaSet → Pod 관리
Service → Pod 그룹에 안정적인 네트워크 엔드포인트
Ingress → 외부 HTTP 트래픽 라우팅
ConfigMap → 설정값 저장
Secret → 민감 정보 저장
Resource Request / Limit
containers:
- name: app
resources:
requests:
cpu: "250m" # 0.25 코어 보장
memory: "256Mi" # 256MB 보장
limits:
cpu: "500m" # 최대 0.5 코어
memory: "512Mi" # 최대 512MB
Request: 스케줄링 기준. 노드에 이 만큼의 여유가 있어야 Pod가 배치된다.
Limit: 초과 방지. CPU는 초과 시 스로틀링, 메모리는 초과 시 OOMKill.
Request가 없으면: 스케줄러가 자원 계획 없이 아무 노드에 배치 → 한 노드에 몰릴 수 있음.
Limit이 없으면: 하나의 Pod가 노드 자원을 전부 먹어 다른 Pod에 영향.
실무 권장: Request = Limit으로 설정 (Guaranteed QoS). 예측 가능한 성능.
HPA (Horizontal Pod Autoscaler)
CPU/메모리 사용률에 따라 Pod 수를 자동으로 조절한다.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # CPU 70% 초과 시 스케일 아웃
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
주의사항:
- HPA가 동작하려면
resources.requests가 반드시 설정되어야 한다. - 스케일 아웃은 빠르게, 스케일 인은 천천히 (기본 5분 안정화 기간).
- Spring Boot 같이 시작 시간이 긴 앱은
startupProbe를 추가해 준비 전에 트래픽이 안 들어오게.
헬스체크 3종류
containers:
- name: app
# 시작 완료 여부 (시작 중에는 다른 프로브 비활성화)
startupProbe:
httpGet:
path: /actuator/health
port: 8080
failureThreshold: 30 # 30번 실패하면 재시작 (30 * periodSeconds)
periodSeconds: 10 # 최대 300초 대기
# 트래픽 받을 준비가 됐는지
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 0
periodSeconds: 5
failureThreshold: 3 # 3번 실패하면 Service 엔드포인트에서 제외
# 컨테이너가 살아있는지
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 3 # 3번 실패하면 컨테이너 재시작
Spring Boot Actuator:
management:
endpoint:
health:
probes:
enabled: true # /actuator/health/readiness, /actuator/health/liveness 활성화
health:
livenessstate:
enabled: true
readinessstate:
enabled: true
PodDisruptionBudget (PDB)
노드 유지보수, kubectl drain 같은 자발적 중단(Voluntary Disruption) 시 최소 가용 Pod 수를 보장한다.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: app-pdb
spec:
minAvailable: 2 # 항상 최소 2개 유지
# 또는
maxUnavailable: 1 # 최대 1개까지 동시에 중단 허용
selector:
matchLabels:
app: my-app
노드 업그레이드 시 PDB가 없으면 모든 Pod가 동시에 제거될 수 있다. PDB를 설정하면 순차적으로 제거되어 서비스가 유지된다.
배포 전략 상세
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 최대 1개 추가 생성 (기존 + 1)
maxUnavailable: 0 # 항상 desired 수 유지 (무중단)
무중단 배포 조건:
maxUnavailable: 0설정readinessProbe설정 (준비 완료 전 트래픽 차단)- 충분한
terminationGracePeriodSeconds(기본 30초)
spec:
template:
spec:
terminationGracePeriodSeconds: 60 # 60초 안에 정상 종료
containers:
- name: app
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"]
# Service 엔드포인트에서 제거되기 전 5초 대기
# 이 시간 동안 새 요청은 안 들어옴
ConfigMap & Secret
# ConfigMap: 일반 설정
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: "production"
LOG_LEVEL: "INFO"
DB_MAX_POOL_SIZE: "10"
# Secret: 민감 정보 (Base64 인코딩)
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
data:
DB_PASSWORD: cGFzc3dvcmQxMjM= # base64("password123")
JWT_SECRET: c2VjcmV0a2V5MTIz
# Pod에서 사용
spec:
containers:
- name: app
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: app-secret
실무에서는 Secret을 YAML 파일에 직접 저장하지 않는다. Helm + .Values, ExternalSecrets Operator (AWS Secrets Manager 연동), Vault 등을 사용한다.
Namespace로 환경 분리
namespace: dev (개발)
namespace: staging (스테이징)
namespace: prod (운영)
kubectl get pods -n prod
kubectl apply -f deployment.yaml -n prod
ResourceQuota로 namespace별 자원 제한:
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-quota
namespace: dev
spec:
hard:
requests.cpu: "4"
requests.memory: 4Gi
limits.cpu: "8"
limits.memory: 8Gi
pods: "20"
실무 운영 경험: 레플리카 10개+ 운영
기존에는 Pod를 고정 수로 운영했다. 트래픽이 적은 새벽에도 10개가 떠있었다.
개선 내용:
1. HPA 도입
minReplicas: 2 # 최소 2개 (새벽)
maxReplicas: 12 # 최대 12개 (트래픽 피크)
피크 타임에는 자동으로 늘고, 새벽에는 2개로 줄어 인프라 비용 60% 절감.
2. readinessProbe + PDB
배포 중 트래픽 끊김 없도록 readinessProbe로 준비 완료 확인, PDB로 최소 2개 유지.
3. Resource Limit 설정
OOMKill이 간헐적으로 발생하던 문제를 Memory Limit을 적절히 올리고 Request를 맞춰 해결.
면접에서 자주 나오는 질문
Q. HPA가 동작하지 않을 때 원인은?
resources.requests가 설정되지 않음 (HPA는 request 기준으로 사용률 계산).- Metrics Server가 설치되지 않음.
minReplicas와 현재 Pod 수가 이미 동일.
Q. readinessProbe와 livenessProbe를 다르게 설정하는 이유는?
readinessProbe 실패 시 Service에서 제외되고, 자연히 로드밸런서 대상에서도 제외된다. 컨테이너는 살아있지만 트래픽만 안 받는다. livenessProbe 실패 시 컨테이너가 재시작된다. readinessProbe를 먼저 엄격하게 설정하면 livenessProbe가 불필요하게 재시작하는 것을 방지한다.
Q. Pod가 Pending 상태일 때 원인은?
- 요청한 CPU/메모리를 가진 노드가 없음.
- 노드에 taint가 있고 Pod에 toleration이 없음.
- PVC가 바인딩되지 않음.
- 이미지 Pull 실패.
kubectl describe pod <name>으로 Events 섹션에서 원인을 확인한다.
Q. 무중단 배포를 위해 반드시 필요한 설정은?
readinessProbe (준비 완료 전 트래픽 차단), maxUnavailable: 0 (항상 desired 수 유지), preStop hook 또는 적절한 graceful shutdown (진행 중인 요청 처리 완료), 충분한 terminationGracePeriodSeconds.