Liveness, Readiness, 그리고 Startup Probes
Kubernetes에는 다양한 유형의 프로브(Probe)가 있습니다:
- Liveness 프로브
- Readiness 프로브
- Startup 프로브
Liveness 프로브
Liveness 프로브는 컨테이너를 언제 재시작해야 하는지를 결정합니다. 예를 들어, 애플리케이션이 실행 중이지만 더 이상 진행할 수 없는 교착 상태(데드락)에 빠진 경우, Liveness 프로브가 이를 감지할 수 있습니다.
컨테이너가 Liveness 프로브에서 반복적으로 실패할 경우, kubelet은 해당 컨테이너를 재시작합니다. Liveness 프로브는 Readiness 프로브의 성공을 기다리지 않으며, Liveness 프로브를 실행하기 전에 대기하려면 initialDelaySeconds
를 정의하거나, Startup 프로브
를 사용할 수 있습니다.
Readiness 프로브
Readiness 프로브는 컨테이너가 트래픽을 수신할 준비가 되었는지를 판단합니다. 이는 네트워크 연결을 설정하거나 파일을 로드하고 캐시를 워밍업하는 등 애플리케이션이 시간 소모적인 초기 작업을 수행할 때 유용합니다.
Readiness 프로브가 실패 상태를 반환하면 Kubernetes는 해당 파드를 모든 일치하는 서비스 엔드포인트에서 제거합니다. Readiness 프로브는 컨테이너의 전체 수명 주기 동안 실행됩니다.
Startup 프로브
Startup 프로브는 컨테이너 내의 애플리케이션이 시작되었는지를 확인합니다. 이 프로브는 느리게 시작되는 컨테이너에서 Liveness 체크를 조정하는 데 사용할 수 있으며, 이로 인해 컨테이너가 완전히 시작되기 전에 kubelet에 의해 종료되는 것을 방지합니다.
이 프로브가 구성된 경우, Liveness와 Readiness 체크는 Startup 프로브가 성공할 때까지 비활성화됩니다. 이 유형의 프로브는 Readiness 프로브와 달리 주기적으로 실행되지 않고, 오직 초기 시작 시에만 실행됩니다.
Liveness 프로브를 잘못 구현하면 연쇄적인 실패로 이어질 수 있습니다. 이로 인해 높은 부하에서 컨테이너가 반복적으로 재시작되고, 애플리케이션의 확장성이 떨어져 클라이언트 요청이 실패하며, 일부 파드의 실패로 인해 남은 파드에 작업 부담이 가중될 수 있습니다. Readiness 프로브와 Liveness 프로브의 차이점을 이해하고, 애플리케이션에 적절하게 적용하는 것이 중요합니다.
Liveness, Readiness, Startup 프로브 설정하기
Liveness 프로브 설정하기
Liveness 프로브는 오랜 시간 실행된 애플리케이션이 고장 상태로 전환되었을 때 이를 감지하고 복구하는 데 유용합니다. 일반적으로 저비용 HTTP 엔드포인트를 사용하며, failureThreshold
값을 높여서 설정하는 패턴이 많이 사용됩니다.
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: registry.k8s.io/busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
periodSeconds 필드는 kubelet이 매 5초마다 Liveness 프로브를 수행하도록 지정합니다. initialDelaySeconds 필드는 첫 번째 프로브를 수행하기 전에 kubelet이 5초 동안 대기하도록 설정합니다. 프로브를 수행하기 위해 kubelet은 대상 컨테이너에서 cat /tmp/healthy 명령을 실행합니다. 이 명령이 성공하면 0을 반환하고, kubelet은 해당 컨테이너가 정상적으로 작동하고 있다고 판단합니다. 만약 명령이 0이 아닌 값을 반환하면, kubelet은 컨테이너를 종료하고 재시작합니다.
컨테이너가 시작된 후 첫 30초 동안 /tmp/healthy 파일이 존재하게 됩니다. 따라서 이 기간 동안 cat /tmp/healthy 명령은 성공 코드를 반환합니다. 그러나 30초 후에는 이 명령이 실패 코드를 반환하게 됩니다.
30초 이내에 파드 이벤트를 확인해보면, 출력 결과는 Liveness 프로브가 아직 실패하지 않았음을 나타냅니다:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 11s default-scheduler Successfully assigned default/liveness-exec to node01
Normal Pulling 9s kubelet, node01 Pulling image "registry.k8s.io/busybox"
Normal Pulled 7s kubelet, node01 Successfully pulled image "registry.k8s.io/busybox"
Normal Created 7s kubelet, node01 Created container liveness
Normal Started 7s kubelet, node01 Started container liveness
35초 후에 파드 이벤트를 다시 확인해보면, 출력의 하단에 Liveness 프로브가 실패했음을 나타내는 메시지가 있으며, 실패한 컨테이너가 종료되고 재생성되었음을 알 수 있습니다:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 57s default-scheduler Successfully assigned default/liveness-exec to node01
Normal Pulling 55s kubelet, node01 Pulling image "registry.k8s.io/busybox"
Normal Pulled 53s kubelet, node01 Successfully pulled image "registry.k8s.io/busybox"
Normal Created 53s kubelet, node01 Created container liveness
Normal Started 53s kubelet, node01 Started container liveness
Warning Unhealthy 10s (x3 over 20s) kubelet, node01 Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
Normal Killing 10s kubelet, node01 Container liveness failed liveness probe, will be restarted
출력 결과에서 RESTARTS 값이 증가한 것을 확인할 수 있습니다. 실패한 컨테이너가 다시 실행 상태로 돌아오자마자 이 카운터가 증가합니다:
NAME READY STATUS RESTARTS AGE
liveness-exec 1/1 Running 1 1m
HTTP Liveness 프로브
HTTP GET 요청을 사용한 Liveness 프로브는 특정 경로의 응답 상태를 확인합니다. 예를 들어, /healthz
경로가 성공(2xx) 또는 실패(5xx) 상태를 반환하도록 설정할 수 있습니다.
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: registry.k8s.io/e2e-test-images/agnhost:2.40
args:
- liveness
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
TCP Liveness 프로브
TCP 소켓을 사용한 Liveness 프로브는 지정된 포트로 소켓을 열 수 있는지를 확인합니다. 성공적으로 연결되면 컨테이너는 정상으로 간주되며, 그렇지 않으면 실패로 간주되어 컨테이너가 재시작됩니다.
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: registry.k8s.io/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
gRPC Liveness 프로브
gRPC Health Checking Protocol을 사용하는 애플리케이션의 경우, gRPC Liveness 프로브를 설정할 수 있습니다. 이 프로브는 지정된 포트에서 gRPC 서버의 상태를 확인합니다.
apiVersion: v1
kind: Pod
metadata:
name: etcd-with-grpc
spec:
containers:
- name: etcd
image: registry.k8s.io/etcd:3.5.1-0
command: [ "/usr/local/bin/etcd", "--data-dir", "/var/lib/etcd", "--listen-client-urls", "http://0.0.0.0:2379", "--advertise-client-urls", "http://127.0.0.1:2379", "--log-level", "debug"]
ports:
- containerPort: 2379
livenessProbe:
grpc:
port: 2379
initialDelaySeconds: 10
Named Port 사용하기
HTTP 및 TCP 프로브에서는 Named Port를 사용할 수 있습니다. 이는 포트 번호 대신에 이름을 사용하여 프로브를 설정하는 방식입니다.
ports:
- name: liveness-port
containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
Startup 프로브
애플리케이션이 처음 초기화될 때 추가적인 시작 시간이 필요한 경우, Startup 프로브를 설정하여 Liveness 프로브가 조기에 실행되어 컨테이너가 재시작되지 않도록 보호할 수 있습니다.
ports:
- name: liveness-port
containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 1
periodSeconds: 10
startupProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 30
periodSeconds: 10
Readiness 프로브 설정하기
애플리케이션이 트래픽을 처리할 준비가 되지 않은 경우, Readiness 프로브를 사용하여 해당 파드에 트래픽이 전달되지 않도록 할 수 있습니다.
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
프로브 설정 필드
initialDelaySeconds
: 컨테이너가 시작된 후 프로브가 시작되기 전까지 대기하는 시간(초)을 설정합니다.periodSeconds
: 프로브를 실행하는 간격(초)을 설정합니다.timeoutSeconds
: 프로브가 타임아웃되기 전까지 대기하는 시간(초)을 설정합니다.successThreshold
: 프로브가 성공으로 간주되기 위해 필요한 연속 성공 횟수를 설정합니다.failureThreshold
: 프로브가 실패로 간주되기 전까지 허용되는 연속 실패 횟수를 설정합니다.