Skip to main content

파드 Readiness & Probe

· 17 min read
Jinwoong Kim

Kubernetes에서 파드의 Readiness 및 프로브는 파드의 상태를 모니터링하고 트래픽을 효율적으로 관리하기 위한 중요한 메커니즘이다. 프로브는 파드가 요청을 처리할 준비가 되었는지를 판단하는 데 사용되며, Kubernetes가 파드를 관리하고 업데이트하는 데 중요한 역할을 한다.

파드 Readiness 및 프로브

파드 Readiness는 따라 파드가 트래픽을 처리할 준비가 되었는지를 나타내는 추가적인 지표이다. 파드 Readiness는 외부 소스에서 파드 주소가 Endpoints 객체에 표시되는지를 결정한다. Kubernetes에서 파드를 관리하는 다른 리소스들, 예를 들어 Deployment 같은 것들은 파드 Readiness를 고려하여 롤링 업데이트 시 의사 결정을 한다. 롤링 배포 중에 새 파드가 준비되었지만 서비스, 네트워크 정책 또는 로드 밸런서가 어떤 이유로 인해 아직 새 파드에 대해 준비되지 않은 경우가 있을 수 있다. 만약 파드의 Readiness 프로브가 실패하면, 해당 파드의 IP 주소는 Endpoints 객체에서 제거되어 서비스가 그 파드로 트래픽을 라우팅하지 않는다. 이는 서비스 중단을 방지하기 위한 메커니즘이다. Readiness 프로브는 파드 .Status.Phase 에 영향을 줄 수 있으며, Kubelet이 이를 실행하여 성공 또는 실패에 따라 파드 상태를 업데이트한다.

파드에 프로브가 명시되어 있지 않으면 Kubernetes가 기본적으로 해당 프로브의 상태를 성공으로 간주한다. 이런 경우 Kubernetes가 컨테이너를 Ready 상태로 간주하여 서비스의 Endpoints에 포함시키고 트래픽을 받을 수 있도록 한다. 그러나 이는 실제로 컨테이너가 준비되지 않았을 때도 트래픽을 받을 수 있어 사용자 경험에 부정적인 영향을 미칠 수 있다. 따라서, 애플리케이션의 상태를 정확히 반영하기 위해 적절한 프로브를 설정하는 것이 중요하다.

다음은 파드 단계별 설명이다.

  • Pending: 클러스터에서 파드를 수락했지만 하나 이상의 컨테이너가 설정되어 실행할 준비가 되지 않은 것을 말함. 파드가 스케줄을 기다리는 시간과 네트워크를 통해 컨테이너 이미지를 다운로드하는 데 소요되는 시간이 포함된다.
  • Running: 파드가 노드에 스케줄되었고 모든 컨테이너가 생성된 경우이다. 하나 이상의 컨테이너가 여전히 실행 중이거나 시작 또는 재시작 중인 경우가 있다. 일부 컨테이너는 CrashLoopBackoff 와 같이 실패한 상태일 수 있다.
  • Succeeded: 파드의 모든 컨테이너가 성공적으로 종료되었으며 다시 시작되지 않는다.
  • Failed: 파드의 모든 컨테이너가 종료되었고 하나 이상의 컨테이너가 실패로 종료되었을 경우이다. 컨테이너가 nonzero 상태로 종료되었거나 시스템에 의해 종료된 경우이다.
  • Unknown: 특정 이유로 파드의 상태를 확인할 수 없는 경우다. 이 단계는 일반적으로 파드가 실행되어야 하는 Kubelet과의 통신 오류로 인해 발생한다.

Kubelet은 Kubernetes 노드에서 실행되는 에이전트로, 파드의 개별 컨테이너에 대해 다양한 헬스 체크를 수행한다. 이 헬스 체크는 livenessProbe, readinessProbe, startupProbe 세 가지 유형으로 나뉜다. 각 프로브는 특정 진단을 수행하며, 그 결과는 다음 세 가지 중 하나로 나타난다.

  • Success: 컨테이너가 진단을 통과했음
  • Failure: 컨테이너가 진단을 통과하지 못했음
  • Unknown: 진단 자체가 실패하여 아무런 조치를 취할 수 없는 상태

이러한 프로브는 HTTP 요청, 바이너리 명령 실행, TCP 연결을 통해 수행될 수 있다. 예를 들어, HTTP 프로브는 특정 엔드포인트에 HTTP GET 요청을 보내 응답 코드가 성공(예: 200 OK)인지를 확인한다. TCP 프로브는 특정 포트가 열려 있는지를 확인하며, 명령 프로브는 컨테이너 내에서 명령을 실행하여 성공 여부를 판단한다. 프로브가 failureThreshold보다 더 많이 실패하면, 검사에 실패한 것으로 간주한다.

Liveness 프로브

Liveness 프로브는 잘못 사용하거나 잘못 구성하면 예기치 않은 장애를 쉽게 일으킬 수 있다. Liveness 프로브를 주로 사용하는 경우는 컨테이너를 다시 시작해야 할 시기를 Kubelet에 알려주는 것이다. 애플리케이션이 살아있고 응답 가능한 상태인지를 확인한다. 만약 이 프로브가 실패하면, 컨테이너는 재시작된다. 이는 애플리케이션이 데드락 상태에 빠졌을 때에도 유용하다.

하지만 잘못 사용하면 위험한 전략이 될 수 있다. 예를 들어, 웹 메인 페이지를 로드하는 Liveness 프로브를 생성한 상태에서 외부의 시스템 변경으로 인해 메인 페이지가 404 또는 500 에러를 반환한다고 가정해 보자. 이러한 시나리오에서 Liveness 프로브는 컨테이너를 재시작한다. 컨테이너를 다시 시작한다고 해서 시스템의 다른 곳에서 문제가 해결되지 않기 때문에 오히려 장애를 악화시킬 수 있다. 컨테이너 CrashLoopBackoff가 발생하게 되는데 있는데, 이는 실패한 컨테이너를 재시작하는 데 시간을 계속 증가시킨다.

  • HTTP probe: 컨테이너 IP 주소로 HTTP GET 요청을 수행하며 200에서 399 사이의 성공적인 HTTP 응답 코드를 기대
  • TCP Socket probe: TCP 연결이 성공했다고 가정
  • Exec probe: 컨테이너 커널 네임스페이스에서 임의의 명령을 실행하고 성공적인 종료 코드(0)를 기대
  • gRPC probe: 상태 확인을 위해 gRPC의 자체 기능 활용

프로브 동작 외에도 다음 매개변수를 사용하여 상태 확인 동작에 영향을 줄 수 있다.

  • initialDelaySeconds: 첫 번째 liveness probe가 확인될 때까지 대기할 시간(초)을 지정
  • periodSeconds: liveness probe 검사 간격(초)
  • timeoutSeconds:프로브 검사가 실패로 간주되기 전에 반환될 때까지 허용되는 최대 시간
  • failureThreshold: 컨테이너가 정상이 아닌 것으로 간주되어 다시 시작해야 할 때까지 프로브 검사가 연속으로 실패해야 하는 빈도를 지정

Readiness 프로브

Readiness 프로브는 정상이 아닌 컨테이너를 삭제하고 새 컨테이너로 교체하여 애플리케이션을 건강하게 유지하는 데 도움이 될 수 있다. 그러나 때로 컨테이너가 비정상적인 경우 다시 시작해도 문제가 해결되지 않는 경우가 있다. 대표적인 예로 애플리케이션이 데이터베이스와 같은 종속성을 사용할 수 있기를 기다리는 경우이다. 컨테이너에 과부하가 걸려 latency가 증가하는 경우 잠시 동안 추가 부하로부터 스스로를 보호하고 부하가 감소할 때까지 준비가 되지 않았다는 것을 표시해야 한다.

https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/ 에서 readinessGates 를 통해 추가적인 AWS ALB 상태를 체크하고 정상일때 Readiness Probe 체크가 되도록 아래와 같이 추가 피드백이나 신호를 파드 상태에 주입할 수 있다.

Custom Pod Readiness Gates for AWS Load Balancer controller

https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.8/deploy/pod_readiness_gate/

Startup 프로브

애플리케이션을 시작하는 데 오랜시간(몇 분이상)이 걸리는 상황에서 Kubernetes는 Startup 프로브를 제공한다. Liveness 프로브와 동일한 형식으로 구성되지만 프로브 동작과 타이밍 파라미터에 대해 다른 값을 허용한다. periodSecondsfailureThreshold 설정을 통해 오래 걸리는 애플리케이션 시작을 고려하기 위해 해당 Liveness 프로브에 비해 훨씬 더 큰 값으로 구성된다. startupProbe가 성공한 이후에만 livenessProbereadinessProbe를 구성할 수 있다.

apiVersion: v1
kind: Pod
metadata:
name: pod-startup-check
spec:
containers:
- image: quay.io/wildfly/wildfly
name: wildfly
startupProbe:
exec:
command: [ "stat", "/opt/jboss/wildfly/standalone/tmp/startup-marker" ]
initialDelaySeconds: 60
periodSeconds: 60
failureThreshold: 15
livenessProbe:
httpGet:
path: /health
port: 9990
periodSeconds: 10
failureThreshold: 3
  • exec: /opt/jboss/wildfly/standalone/tmp/startup-marker 파일의 존재 여부를 확인한다. 이 파일이 존재하면 컨테이너가 시작된 것으로 간주
  • initialDelaySeconds: 컨테이너가 15분 후(60초 x 15회, 최초 딜레이 60초) 에도 startupProbe를 통과하지 못했을 때 컨테이너를 다시 시작하도록 지정하는 매개변수
  • periodSeconds: 프로브가 실행되는 주기로, 60초마다 프로브가 실행
  • failureThreshold: 실패 허용 횟수로, 15번 실패하면 컨테이너가 비정상으로 간주

위 예시는 startupProbe가 미들웨어인 Wildfly 컨테이너가 시작되었는지 확인한다. 컨테이너가 시작되기 전까지 다른 프로브(liveness, readiness)는 실행되지 않는다. 예시와 같이 컨테이너를 시작하는 데 몇 분이 걸리지만 시작 후 컨테이너가 상태가 좋지 않으면 빠르게 종료하는 케이스로 주로 사용한다. 이후에 livenessProbe는 컨테이너의 지속적인 실행 상태를 확인한다. /health 엔드포인트에 대한 HTTP 요청을 통해 Wildfly 서버가 정상적으로 작동 중인지 확인한다.

아래 예시는 Golang 웹 서버에는 8080 포트에서 /healthz 경로로 HTTP GET을 수행하는 livenessProbe 프로브가 있고, readinessProbe 프로브는 동일한 포트에서 /를 체크한다.

apiVersion: v1
kind: Pod
metadata:
name: go-web
labels:
test: liveness
spec:
containers:
- name: go-web
image: go-web:v0.0.1
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
readinessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 5
periodSeconds: 5

readiness gates

Readiness gates를 사용하면 파드 내부의 애플리케이션이 언제 준비되었는지 확인할 수 있다. Kubernetes 1.14부터 사용 가능했고, Readiness gates를 사용하기 위해 Kubelet이 파드 Readiness를 평가하는 추가 조건으로 파드의 스펙에 readinessGates를 추가한다.Readiness 게이트는 파드의 status.condition 필드의 현재 상태에 의해 제어되며, Kubelet이 파드의 status.conditions 필드에서 해당 조건을 찾을 수 없는 경우 조건의 상태는 기본값이 False로 설정된다.

아래 예에서 볼 수 있듯이, feature-1 Readiness gates는 False이고 feature-2True이므로 파드의 상태는 False가 된다.

kind: Pod
...
spec:
readinessGates:
- conditionType: www.example.com/feature-1
- conditionType: www.example.com/feature-2
...
status:
conditions:
- lastProbeTime: null
lastTransitionTime: 2024-08-25T00:00:00Z
status: "False"
type: Ready
- lastProbeTime: null
lastTransitionTime: 2024-08-25T00:00:00Z
status: "False"
type: www.example.com/feature-1
- lastProbeTime: null
lastTransitionTime: 2024-08-25T00:00:00Z
status: "True"
type: www.example.com/feature-2
containerStatuses:
- containerID: docker://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ready: true

사용자 정의 조건을 사용하는 파드의 경우, 해당 파드는 다음 문이 모두 적용되는 경우에만 준비된 것으로 평가된다.

  • 파드의 모든 컨테이너가 준비 상태
  • readinessGates에 지정된 모든 조건이 True

파드 Network Readiness

파드 Network Readiness는 Kubernetes v1.29에서 beta가 된 readiness로 Kubernetes에서 파드가 네트워크 요청을 처리할 준비가 되었는지를 확인하는 중요한 조건이다. 파드가 클러스터 내에서 트래픽을 수신할 수 있는 상태인지 판단하는 데 사용되고 파드가 네트워크 준비 상태가 되면, 해당 파드는 서비스의 로드 밸런싱 풀에 추가되어 트래픽을 처리할 수 있게 된다.

PodReadyToStartContainersConditionfeature gate가 활성화되면(1.31 버전 부터는 기본으로 탑재될 예정) 파드의 status.conditionsPodReadyToStartContainers 조건이 추가된다.

apiVersion: v1
kind: Pod
metadata:
name: example-pod
spec:
containers:
- name: example-container
image: example-image
status:
conditions:
- type: PodReadyToStartContainers
status: "True"

위 예시에서 PodReadyToStartContainers 조건이 True로 되어 있으면, kubelet은 컨테이너 이미지를 풀링하고 컨테이너를 생성할 준비가 되었음을 의미한다.

결론

Kubernetes의 Readiness 및 프로브는 파드의 상태를 모니터링하고 트래픽을 효율적으로 관리하는 데 필수적이다. 적절한 프로브 설정을 통해 애플리케이션의 가용성과 안정성을 높일 수 있다. 프로브를 설정할 때는 애플리케이션의 특성과 요구 사항에 맞게 구성하는 것이 중요하다.