근묵자흑
Kubernetes Pattern: Health Probe Pattern(정상상태 점검 패턴) 본문
Kubernetes Pattern: Health Probe Pattern(정상상태 점검 패턴)
Luuuuu 2025. 8. 16. 20:17
운영 환경에서 Kubernetes 애플리케이션을 실행할 때 가장 중요한 것 중 하나는 애플리케이션의 건강 상태를 정확히 파악하는 것입니다. 단순히 컨테이너가 실행 중이라고 해서 애플리케이션이 정상적으로 작동한다고 볼 수 없죠. 메모리 누수, 데드락, 무한 루프 등 다양한 문제가 발생할 수 있기 때문입니다.
📚 Health Probe가 필요한 이유
실제 장애 시나리오
제가 경험한 실제 사례를 하나 공유하겠습니다. Java 애플리케이션이 OutOfMemoryError를 발생시켰지만, JVM 프로세스는 여전히 실행 중이었습니다. Kubernetes는 프로세스가 살아있다고 판단해 재시작하지 않았고, 결과적으로 서비스는 완전히 중단되었죠.
이런 문제를 해결하기 위해 Kubernetes는 세 가지 Health Probe를 제공합니다:
- Liveness Probe: 애플리케이션이 살아있는가?
- Readiness Probe: 트래픽을 받을 준비가 되었는가?
- Startup Probe: 애플리케이션 시작이 완료되었는가?
실습을 통한 Health Probe 분석
- 이번장의 실습 코드는 GitHub 저장소에서 확인할 수 있습니다.
Liveness Probe 깊이 이해하기
1. HTTP Liveness Probe
가장 일반적인 형태의 liveness 체크입니다. Spring Boot Actuator와 같은 health 엔드포인트를 활용합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: liveness-http-test
spec:
replicas: 1
selector:
matchLabels:
app: liveness-http-test
template:
metadata:
labels:
app: liveness-http-test
spec:
containers:
- name: random-generator
image: k8spatterns/random-generator:1.0
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 15 # 컨테이너 시작 후 대기 시간
periodSeconds: 10 # 체크 주기
timeoutSeconds: 5 # 응답 대기 시간
failureThreshold: 3 # 실패 허용 횟수
주요 파라미터 설명:
initialDelaySeconds
: 애플리케이션 초기화 시간 고려failureThreshold
: 너무 낮으면 불필요한 재시작, 너무 높으면 장애 감지 지연
2. Exec Liveness Probe - 실패 시뮬레이션
이 예제는 의도적으로 실패를 발생시켜 재시작 메커니즘을 관찰합니다:
apiVersion: apps/v1
kind: Deployment
metadata:
name: liveness-exec-test
spec:
template:
spec:
containers:
- name: busybox
image: busybox:latest
command: ["/bin/sh"]
args:
- -c
- |
touch /tmp/healthy # 건강 상태 파일 생성
sleep 30
rm -f /tmp/healthy # 30초 후 파일 삭제 (실패 유발)
sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3
실제 테스트 결과:
# 테스트 실행
kubectl apply -f manifests/03-liveness-exec.yaml -n health-probe-test
# 50초 후 확인
kubectl get pods -n health-probe-test
NAME READY STATUS RESTARTS AGE
liveness-exec-test-58b9c4969f-8tnkv 1/1 Running 2 (117s ago) 4m27s
30초 후 health 파일이 삭제되고, 3번의 실패 후(15초) 컨테이너가 재시작됩니다!
Readiness Probe 실전 활용
Readiness vs Liveness의 차이
- Liveness 실패: 컨테이너 재시작
- Readiness 실패: Service 엔드포인트에서 제거 (재시작 없음)
점진적 배포 시나리오
apiVersion: apps/v1
kind: Deployment
metadata:
name: readiness-exec-test
spec:
replicas: 3 # 3개 레플리카
template:
spec:
containers:
- name: random-generator
image: k8spatterns/random-generator:1.0
env:
- name: DELAY_STARTUP
value: "20" # 20초 지연 시작
readinessProbe:
exec:
command:
- stat
- /tmp/random-generator-ready
periodSeconds: 5
failureThreshold: 1
엔드포인트 모니터링:
# 실행 후 엔드포인트 관찰
for i in {1..6}; do
kubectl get endpoints readiness-exec-test -n health-probe-test
sleep 5
done
# 결과: Pod가 하나씩 Ready 상태가 되면서 엔드포인트에 추가됨
# 0/3 → 1/3 → 2/3 → 3/3
이는 무중단 배포에서 매우 중요합니다. 새 버전의 Pod가 완전히 준비되기 전까지 트래픽을 받지 않습니다.
Startup Probe로 느린 시작 해결하기
Spring Boot 같은 무거운 애플리케이션의 문제
일부 엔터프라이즈 애플리케이션은 시작에 수 분이 걸릴 수 있습니다. Liveness Probe만 사용하면:
initialDelaySeconds
를 매우 크게 설정 → 실제 장애 감지 지연- 작게 설정 → 시작 중 불필요한 재시작
Startup Probe 솔루션
apiVersion: apps/v1
kind: Deployment
metadata:
name: startup-probe-test
spec:
template:
spec:
containers:
- name: random-generator
image: k8spatterns/random-generator:2.0
env:
- name: DELAY_STARTUP
value: "90" # 90초 시작 지연
startupProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 12 # 최대 120초 대기
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
periodSeconds: 10
failureThreshold: 3 # 시작 후에는 빠른 장애 감지
실제 테스트 결과:
# 시작 진행 상황 모니터링
Time: 0s | Status: Pending | Ready: false
Time: 10s | Status: Running | Ready: false
Time: 20s | Status: Running | Ready: false
...
Time: 101s | Status: Running | Ready: true
✅ Container ready after 101 seconds
Startup Probe가 성공할 때까지 Liveness/Readiness Probe는 실행되지 않습니다!
모든 프로브 조합하기
실제 프로덕션 환경에서는 세 가지 프로브를 적절히 조합해 사용합니다:
apiVersion: apps/v1
kind: Deployment
metadata:
name: combined-probes-test
spec:
template:
spec:
containers:
- name: random-generator
image: k8spatterns/random-generator:2.0
startupProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 10 # 시작용
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
periodSeconds: 10
failureThreshold: 3 # 런타임용
readinessProbe:
exec:
command:
- stat
- /tmp/random-generator-ready
periodSeconds: 5
failureThreshold: 2 # 트래픽 제어용
각 프로브의 역할:
- Startup: 초기 시작 완료 확인
- Liveness: 지속적인 생존 상태 확인
- Readiness: 트래픽 수신 가능 여부 확인
💡 실전 팁과 베스트 프랙티스
1. 적절한 타이밍 설정
# 나쁜 예: 너무 공격적인 설정
livenessProbe:
periodSeconds: 1
failureThreshold: 1
timeoutSeconds: 1
# 좋은 예: 여유있는 설정
livenessProbe:
periodSeconds: 10
failureThreshold: 3
timeoutSeconds: 5
2. 의존성 체크 주의사항
# 나쁜 예: 외부 의존성을 liveness에 포함
livenessProbe:
exec:
command: ["check-database-connection.sh"]
# 좋은 예: 외부 의존성은 readiness에만
readinessProbe:
exec:
command: ["check-database-connection.sh"]
livenessProbe:
httpGet:
path: /health/ping # 애플리케이션 자체만 체크
3. 헬스체크 엔드포인트 구현
// Go 예제
func healthHandler(w http.ResponseWriter, r *http.Request) {
// 간단한 self-check만 수행
if isApplicationHealthy() {
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{
"status": "UP",
"timestamp": time.Now().Format(time.RFC3339),
})
} else {
w.WriteHeader(http.StatusServiceUnavailable)
json.NewEncoder(w).Encode(map[string]string{
"status": "DOWN",
})
}
}
직접 테스트해보기
전체 테스트 실행
# 프로젝트 클론
git clone <repository-url>
cd health-probe
# Minikube 시작
minikube start
# 전체 테스트 실행
./run-test.sh
실시간 모니터링
# Pod 상태 관찰
kubectl get pods -n health-probe-test -w
# 이벤트 모니터링
kubectl get events -n health-probe-test --watch | grep probe
# 엔드포인트 변화 관찰
kubectl get endpoints -n health-probe-test -w
테스트 결과 분석
실제 Minikube에서 실행한 결과:
프로브 타입 | 테스트 결과 | 재시작 횟수 | 소요 시간 |
---|---|---|---|
HTTP Liveness | 정상 작동 | 0 | - |
TCP Liveness | 정상 작동 | 0 | - |
Exec Liveness | 예상대로 실패 | 2 | 45초 |
Exec Readiness | 점진적 Ready | 0 | 30초 |
HTTP Readiness | 정상 작동 | 0 | - |
Startup Probe | 느린 시작 성공 | 0 | 101초 |
- 프로브는 보험이다: 설정하지 않으면 언젠가 후회합니다
- 각 프로브의 목적을 명확히: Liveness는 재시작, Readiness는 트래픽 제어
- 타이밍이 중요: 너무 공격적이면 불안정, 너무 느슨하면 무용지물
- 실패를 계획하라: 프로브는 실패를 가정하고 설계
- 모니터링과 함께: 프로브 메트릭을 Prometheus로 수집하여 분석
다음으로 필요한 설정들
- 프로덕션 적용: 실제 애플리케이션에 적절한 프로브 설정
- 메트릭 수집: Prometheus + Grafana로 프로브 메트릭 시각화
- CI/CD 통합: 배포 파이프라인에 프로브 검증 추가
- Service Mesh 연동: Istio/Linkerd와 함께 고급 헬스체크 구현
'k8s > kubernetes-pattern' 카테고리의 다른 글
Kubernetes Pattern: Managed Lifecycle (0) | 2025.08.23 |
---|---|
Kubernetes Pattern: 선언적 배포(Declarative Deployment) + FluxCD (3) | 2025.08.09 |
Kubernetes Pattern: 예측 가능한 요구사항(Predictable Demands) (7) | 2025.08.02 |