코알못

[kubernetes] Probe(liveness,readiness) 소개 및 실습 본문

ETC

[kubernetes] Probe(liveness,readiness) 소개 및 실습

코린이s 2023. 6. 3. 16:13
728x90

기본적으로 쿠버네티스 컨테이너가 죽었을때 컨네이너를 재기동 해주나 컨테이너에 띄운 내부 서비스 장애가 났을 경우에는 컨테이너를 재기동 해주지 않는다.

이를 위해서 이용하는것이 livenessProbe(생동감 조사) 이다!

설정은 아래와 같이 7개이며 설명을 참고한다.

livenessProbe:
  httpGet:
    path: / # probe 엔드포인트
    port: 8080 # probe 대상 컨테이너 포트
  initialDelaySeconds: 60 # 해당 설정 만큼 대기후 probe 시작 (서비스 기동시간 전에 호출하게 되면 무조건 오류이므로 무한 루프에 빠질 수 있기 때문)
  periodSeconds: 5 # probe 실행 주기
  successThreshold: 1 # 몇개 성공하면 실패 횟수 초기화 할지
  failureThreshold: 1 # 해당 횟수만큼 실패시 컨테이너 재기동 진행 
  timeoutSeconds: 10 # 응답값 받는데 해당 초이상 소요될시 실패 카운트 증가

 

실습을 위해 비정상적으로 '/' 호출시 http status code 500을 리턴하는 unhealthy 파드를 띄우며 비교군을 위해 정상적인 파드 healthy도 띄우도록 한다.

# liveness-probe.yaml

apiVersion: v1 
kind: Pod
metadata:
  name: unhealthy
  labels:
    app: myapp
spec:
  containers:
  - name: unhealthy
    image: yoonjeong/unhealthy-app:1.0
    ports:
    - containerPort: 8080
    resources:
      limits:
        memory: "64Mi"
        cpu: "50m"
    livenessProbe:
      httpGet:
        path: /
        port: 8080
      initialDelaySeconds: 60
      periodSeconds: 5
      successThreshold: 1
      failureThreshold: 1
      timeoutSeconds: 10
---
apiVersion: v1 
kind: Pod
metadata:
  name: healthy
  labels:
    app: myapp
spec:
  containers:
  - name: healthy
    image: yoonjeong/healthy-app:1.0
    ports:
    - containerPort: 8080
    resources:
      limits:
        memory: "64Mi"
        cpu: "50m"
    livenessProbe:
      httpGet:
        path: /
        port: 8080
      initialDelaySeconds: 60
      periodSeconds: 5
      successThreshold: 1
      failureThreshold: 1
      timeoutSeconds: 10

클러스터에 적용한다.

$ kubectl apply -f liveness-probe.yaml
pod/unhealthy created
pod/healthy created

watch 모드로 파드 상태를 관찰하면 아래와 같이 RESTARTS를 보면 계속적으로 unhealthy가 재기동 되는것을 볼 수 있다.

$ kubectl get pod -w
NAME        READY   STATUS    RESTARTS   AGE
healthy     1/1     Running   0          20s
unhealthy   1/1     Running   0          21s
unhealthy   1/1     Running   1 (1s ago)   77s
unhealthy   1/1     Running   2 (1s ago)   2m22s
unhealthy   1/1     Running   3 (2s ago)   3m28s

상세 확인을 위해 파드의 정보를 descrbe 명령어로 확인하고 Exit Code를 보고 143 코드에 해당하는 오류를 보고 대응 하면 된다.

$ kubectl describe pod unhealthy
Containers:
  unhealthy:
    Container ID:   containerd://....
    Image:          yoonjeong/unhealthy-app:1.0
    Image ID:       docker.io/yoonjeong/unhealthy-app@sha256:...
    Port:           8080/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sat, 03 Jun 2023 16:16:18 +0900
    Last State:     Terminated
      Reason:       Error
      Exit Code:    143
Events:
  Type     Reason     Age                 From               Message
  ----     ------     ----                ----               -------
  Normal   Scheduled  2m27s               default-scheduler  Successfully assigned default/unhealthy to gke-corin-cluster-default-pool-d2d86113-xq03
  Warning  Unhealthy  7s (x2 over 72s)    kubelet            Liveness probe failed: HTTP probe failed with statuscode: 500
  Normal   Killing    7s (x2 over 72s)    kubelet            Container unhealthy failed liveness probe, will be restarted
  Normal   Pulled     6s (x3 over 2m14s)  kubelet            Container image "yoonjeong/unhealthy-app:1.0" already present on machine
  Normal   Created    6s (x3 over 2m14s)  kubelet            Created container unhealthy
  Normal   Started    5s (x3 over 2m14s)  kubelet            Started container unhealthy

Events 를 해석하면 아래와 같다.

Reason Message 설명
Unhealthy Liveness probe failed: HTTP probe failed with statuscode: 500 probe 했으나 500 코드를 받았고 unhealthy 로 판단하였다.
Killing Container unhealthy failed liveness probe, will be restarted unhealthy 이므로  liveness probe 가 실패 했으며 컨테이너를 죽인다.
Pulled  Container image "yoonjeong/unhealthy-app:1.0" already present on machine 머신에 이미 컨테이너 이미지가 있으니 따로 가져오지 않는다.
Created Created container unhealthy 컨테이너를 생성한다.
Started Started container unhealthy 컨테이너를 시작한다.

이제 실습을 종료하며 생성한 파드를 삭제한다.

$ kubectl delete all -l app=myapp
pod "healthy" deleted
pod "unhealthy" deleted

이제 readinessProbe 에 대해 알아보자!

readinessProbe는 서비스가 요청을 받을 준비된 파드만 서비스를 하기 위해 사용하는 기능이다.

정의한 조건에 맞지 않다면 서비스 엔드 포인트에서 파드를 제거하며 준비가 다시 된다면 다시 엔드포인트에 추가하는 방식으로 동작한다.

아래 yaml 파일 예제이며  '/var/ready' 디렉토리가 있다면 정상으로 판단하고 없다면 실패 카운트에 추가 하도록 하여 서비스 되지 않도록 한다.

readinessProbe:
  exec:
    command: # 컨테이너에서 실행할 명령어
    - ls
    - /var/ready
  initialDelaySeconds: 3 # 해당 설정 만큼 대기후 probe 시작 (서비스 기동시간 전에 호출하게 되면 무조건 오류이므로 무한 루프에 빠질 수 있기 때문)
  periodSeconds: 1 # probe 실행 주기
  successThreshold: 1 # 몇개 성공하면 실패 횟수 초기화 할지
  failureThreshold: 1 # 해당 횟수만큼 실패시 컨테이너 재기동 진행 
  timeoutSeconds: 3 # 응답값 받는데 해당 초이상 소요될시 실패 카운트 증가

이제 실습을 진행해보자!

서비스를 만들며 Pod 부분에 Probe 를 정의 하도록 한다. 실패 조건은 /var/ready 디렉토리가 없다면 실패 카운트 증가 하도록 한다.

apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  type: LoadBalancer
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 8080
---
apiVersion: v1
kind: Pod
metadata:
  name: unhealthy
  labels:
    app: myapp
spec:
  containers:
  - name: unhealthy
    image: yoonjeong/unhealthy-app:1.0
    ports:
    - containerPort: 8080
    readinessProbe:
      exec:
        command:
        - ls
        - /var/ready
      initialDelaySeconds: 60
      periodSeconds: 5
      successThreshold: 1
      failureThreshold: 1
      timeoutSeconds: 3
    resources:
      limits:
        memory: "64Mi"
        cpu: "50m"
---
apiVersion: v1
kind: Pod
metadata:
  name: healthy
  labels:
    app: myapp
spec:
  containers:
  - name: healthy
    image: yoonjeong/healthy-app:1.0
    ports:
    - containerPort: 8080
    resources:
      limits:
        memory: "64Mi"
        cpu: "50m"

클러스터에 적용 한다.

$ kubectl apply -f readiness-probe.yaml

이제 service 가 정상적으로 생성 되었는지 확인 하면 정상적으로 생성 되었다.

$ kubectl get svc myapp
NAME    TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)        AGE
myapp   LoadBalancer   10.104.13.177   34.133.238.223   80:31726/TCP   6m21s

파드 Running 상태를 보면 unhealthy의 경우 준비된 파드가 없다.

$ kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
healthy     1/1     Running   0          61s
unhealthy   0/1     Running   0          4m10s

준비 안된 이유는 readiness 부분에 정의한 실패 조건에 해당 하기 때문인데 pod 정보를 상세하게 보면 '/var/ready' 디렉토리에 대해 No such file 이라고 나온다.

$ kubectl describe pod/unhealthy
...
..
Events:
  Type     Reason     Age                   From               Message
  ----     ------     ----                  ----               -------
  Normal   Scheduled  7m14s                 default-scheduler  Successfully assigned default/unhealthy to gke-corin-cluster-default-pool-d2d86113-xq03
  Normal   Pulled     7m5s                  kubelet            Container image "yoonjeong/unhealthy-app:1.0" already present on machine
  Normal   Created    7m5s                  kubelet            Created container unhealthy
  Normal   Started    7m5s                  kubelet            Started container unhealthy
  Warning  Unhealthy  2m4s (x53 over 6m4s)  kubelet            Readiness probe failed: ls: /var/ready: No such file or directory

디렉토리가 실제로 없는지 확인하면 실제로 없다.

$ kubectl exec -it pod/unhealthy -- ls /var/ready
ls: /var/ready: No such file or directory
command terminated with exit code 1

그렇기에 서비스 엔드 포인트를 확인하면 준비 상태인 healthy 파드만 매핑 된것을 확인할 수 있다,

$ kubectl get endpoints myapp
NAME    ENDPOINTS          AGE
myapp   10.100.2.60:8080   6m47s

준비안된 ubhealthy 파드에 대해 준비된 상태로 만들기 위해 준비 성공을 위한 디렉토리를 생성하며

$ kubectl exec -it pod/unhealthy -- mkdir /var/ready

파드를 다시 확인하면 정상적으로 준비 되었다.

$ kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
healthy     1/1     Running   0          2m53s
unhealthy   1/1     Running   0          6m2s

서비스 엔드 포인트도 정상적으로 두개가 매핑 된것을 확인할 수 있다.

$ kubectl get endpoints myapp
NAME    ENDPOINTS                           AGE
myapp   10.100.2.60:8080,10.100.3.81:8080   10m

이제 실습을 마치며 모든 오브젝트를 제거한다.

$ kubectl delete all -l app=myapp
pod "healthy" deleted
pod "unhealthy" deleted

끝!

728x90
Comments