본문 바로가기
IT/Kubernetes

[Kubernetes] Liveness & Readiness Probe

by 물통꿀꿀이 2019. 4. 26.

이번 포스팅에서는 Pod의 Liveness Probe와 Readiness Probe에 대해 알아보겠다.


Liveness Probe

Liveness Probe는 Pod 내의 Container가 살아있는지 죽어있는지 확인 하기 위한 k8s의 방안이다. 

Pod에 대해 생각해보면, Node에서 실행되는 Pod는 Node의 Kubelet에 의해 정상적으로 수행된다. 즉, Pod가 종료되거나 내부 Container에서 크리티컬한 문제가 생겨 작업이 중단되면 Node의 Kubelet에 의해 다시 실행된다. 그런데 내부 스케줄링에 의해 잘 동작하지만 문제는 Container에서 DeadLock과 같은 무한 대기 상태가 벌어졌을 때는 아무도 알 수 없다는 것이다. (Crash 같은 경우는 프로세스가 강제로 종료되기 때문에)

그래서 k8s에서는 Liveness Probe를 사용하여 각 Container의 살아있는지 여부를 확인 할 수 있다. 


k8s에서는 3가지 방법의 Liveness Probe 있으며 실패시 해당 Container를 재시작한다.

1) HTTP Request

지정된 IP, Port, Path에 HTTP Get 요청을 한다. Probe가 응답에 대한 에러(2xx, 3xx가 아닌 모든 HTTP 상태 코드) 또는 응답을 하지 않으면 실패로 간주한다.

apiVersion: v1

kind: Pod

metadata:

  labels:

    test: liveness

  name: liveness-http

spec:

  containers:

  - name: liveness

    image: k8s.gcr.io/liveness // 내부 서버 코드를 포함하는 image

    args:

    - /server

    livenessProbe:

      httpGet: // Liveness HTTP Get Probe 

        path: /healthz // HTTP로 요청 할 경로

        port: 8080 // Probe Port

        httpHeaders:

        - name: Custom-Header

          value: Awesome

      initialDelaySeconds: 3

      periodSeconds: 3 

위의 매니페스트 파일은 일반적인 Pod 매니페스트 파일에 LivenessProbe를 추가한 것이다. 파일에서 내부 속성 중 중요한 2개를 먼저 살펴보자.

- initialDelaySeconds : kubelet에게 Application이 실행되고 initialDelaySeconds 이후에 시작하겠다고 통보한다. 때문에 애플리케이션의 초기화 시간을 파악하고 값을 설정해야 한다. (그렇지 않으면 초기화 과정 도중에 Container가 재시작 된다.)

- periodSeconds : periodSeconds 마다 Liveness Probe를 실행한다. 

그림 1. Liveness Probe in Pod


매니페스트 파일이 단일 Container를 사용하다는 것을 고려하고 그림 1을 확인해보면 Liveness Probe에 대한 상세 값을 확인 할 수 있다.

State는 현재 Container의 상태에 대한 확인 및 이유에 대해 알 수 있으며 Last State는 지난 번 Container의 상태를 확인 할 수 있다. (내부를 보면 에러 이슈와 같은 관련 정보를 좀 더 자세히 얻을 수 있다.)

그런데 이중 보다 중요한 것은 아래와 같은 Liveness 정보이다.

http-get http://:8080/healthz delay=3s timeout=1s period=3s #success=1 #failure=3 

여기서는 Container가 실행된 이후 delay(3s) 시간 이후 Probe를 시작하며, 요청시 timeout(1s) 이내에 응답을 해야한다. (그렇지 않으면 실패) 또한 period(3s) 마다 HTTP Get를 요청하며 연속 failure(3) 후에는 kubelet이 해당 Container를 내린뒤에 다시 시작시킨다.


매니페스트 파일에서 사용하는 서버 Image의 내부 코드는 간략히 아래와 같다.

(/healthz로 들어온 Probe 요청에 대해 HTTP 상태 코드를 반환한다.)

http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {

    duration := time.Now().Sub(started)

    if duration.Seconds() > 10 {

        w.WriteHeader(500)

        w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))

    } else {

        w.WriteHeader(200)

        w.Write([]byte("ok"))

    }

}) 

자세한 서버 코드는 https://github.com/kubernetes/kubernetes/blob/master/test/images/liveness/server.go 에서 확인 할 수 있다.


2) TCP Socket

지정된 Port와 Connection 맺기 위한 요청을 한다. Connection이 Establish가 된다면 살아있고 그렇지 않으면 실패로 간주한다.

apiVersion: v1

kind: Pod

metadata:

  name: goproxy

  labels:

    app: goproxy

spec:

  containers:

  - name: goproxy

    image: k8s.gcr.io/goproxy:0.1

    ports:

    - containerPort: 8080

    readinessProbe:

      tcpSocket:

        port: 8080

      initialDelaySeconds: 5

      periodSeconds: 10

    livenessProbe:

      tcpSocket:

        port: 8080

      initialDelaySeconds: 15

      periodSeconds: 20 

TCP Socket을 통한 Probe는 HTTP와 매우 비슷하다. (OSI Layer의 차이 정도?) 그런데 7 Layer 까지 올라가진 않고 TCP에서 Connection 여부만 확인한다. 


3) Exec Command

내부에 임의 명령을 실행하고 해당 명령의 종료 상태 코드를 확인한다. (0이 아니면 실패)

apiVersion: v1

kind: Pod

metadata:

  labels:

    test: liveness

  name: liveness-exec

spec:

  containers:

  - name: liveness

    image: k8s.gcr.io/busybox

    args:

    - /bin/sh

    - -c

    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600

    livenessProbe:

      exec:

        command:

        - cat

        - /tmp/healthy

      initialDelaySeconds: 5

      periodSeconds: 5 

kubelet이 initialDelaySeconds, periodSeconds를 고려하여 cat /tmp/healthy 명령어를 수행한다. Container의 args를 보면 내부적으로 해당 빈파일을 만들고 삭제하기 때문에 만일 삭제가 되면 Liveness Probe는 실패를 의미한다. (즉, kubelet이 재시작한다.)

그림 2. Exec Command Events


그림 2의 가장 하단을 보면 확인 할 수 있듯이, kubelet은 지속적으로 Command를 보내는데 파일이 없으면 해당 Container가 비정상적이라는 것으로 판단한다.


Readiness Probe

Readiness Probe는 Liveness Probe와 비슷하게 Container의 살아있는지 죽어있는지 여부를 확인한다. 하지만 Readliness Probe는 Liveness Probe와 다른점은 클라이언트의 요청 수락 여부를 결정한다는 것이다. 

그림 3. Readiness Probe


그림 3을 보면 확인 할 수 있다. (왼쪽이 Readiness Probe 성공, 오른쪽이 실패), 그런데 조금 의아한 점은 Container 단위가 아니라 Pod 단위로 그림이 구성되어 있다. Liveness Proble가 정상적인 응답을 보내지 않는 Container에 대해 재시작을 한다는 것을 되짚어 볼 때 조금 다르다.

이는 Readiness Probe는 Pod에 외부 요청을 정상적으로 받을 수 있는 Container가 유지 되지 않으면 해당 Pod을 제외시킨다. 그래서 그림 3의 오른쪽이 정상적으로 응답을 받을 수 없는 상태의 Container가 있기 때문에 Pod가 제외된 것이다.

이와 같은 Readilness Probe의 방식은 Liveness Proble와 마찬가지로 3가지가 존재한다.

1) HTTP Request

2) TCP Socket

3) Exec Command


사용하는 방식은 거의 흡사하다.

readinessProbe:

  exec:

    command:

    - cat

    - /tmp/healthy

  initialDelaySeconds: 5

  periodSeconds: 5 

다만, 위의 매니페스트 파일에서 볼 수 있듯이 readlinessProbe를 쓴다는 점을 제외하고는


Reference

https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/

https://blog.colinbreck.com/kubernetes-liveness-and-readiness-probes-looking-for-more-feet/

'IT > Kubernetes' 카테고리의 다른 글

[Kubernetes] Networking - Pods  (0) 2019.04.27
[Kubernetes] Networking - Kube Proxy  (0) 2019.04.26
[Kubernetes] Storage - StorageClass  (0) 2019.04.21
[Kubernetes] Storage - PersistentVolume  (0) 2019.04.21
[Kubernetes] Storage - Volume  (0) 2019.04.21

댓글