티스토리 뷰

Kubernetes에는 세가지 헬스 체크 방법이 있습니다. Liveness Probe, Readiness Probe, Startup Probe 라는 세 가지 헬스 체크 방법이 있습니다. 모두 역할이 다를 뿐 설정 가능한 내용은 똑같고 spec.containers에 설정하게 됩니다.

 

Probe 종류 역할 실패 시 동작
Liveness Probe 파드 내부의 컨테이너가 정상 동작중인지 확인 컨테이너 재기동
Readiness Probe 파드가 요청을 받아들일 수 있는지 확인 트래픽 차단 (파드를 재기동 하지 않음)
Startup Probe 파드의 첫 번째 기동이 완료되었는지 확인 다른 Probe 실행을 시작하지 않음

Liveness Probe

파드 내부의 컨테이너가 정상적으로 동작 중인지 확인하기 위한 헬스 체크입니다. 컨테이너 내부에서 프로세스에 버그가 있을 경우 장기간 실행하고 있으면 메모리 누수 등에 의해 응답하지 않는 경우가 있습니다. 이럴 경우 컨테이너를 재시작 할 수 있도록 설정합니다. 따라서 헬스 체크가 실패하면 재시작없이 복구가 어려울경우 해당 Probe를 사용하면 좋을것 같습니다.

다만, 사실 컨테이너 속 프로세스가 어떠한 이슈에 직면하거나 unhealty 상태가 되어 프로세스가 중단된다면 원래는 kubelet이 파드의 restartPolicy에 따라서 자동으로 수행합니다. 그래도 서비스의 데드락 상태에 머무르는 것을 감지하여 재시작시킬 때 유용 합니다.

 

Readiness Probe

파드가 요청을 받아드릴 수 있는지 확인하기 위한 헬스 체크입니다. 백엔드 데이터베이스에 정상적으로 접속이 되는지, 기동 시간이 오래 걸리는 프로세스가 기동을 완료했는지 등을 체크합니다. Pod 기동이 끝나고 헬스 체크에 실패하게되면 서비스를 통한 트래픽을 파드에 전송하지 않습니다. 

 

하지만 예를들어 Liveness Probe를 사용하려면 보통 첫 번째 체크 시작 시간을 60초 후 등으로 설정하면, 최초 기동이 바로 끝나는 경우 60초간 체크가 없는 상태가 되거나, 처음 기동에 60초 이상 걸리는 경우 체크에 실패하기 되므로 컨테이너가 재시작되어 이것이 반복되면 결국 Pod가 전혀 기동하지 않는 경우도 있습니다. 그래서 등장한것이 Startup Probe 입니다.

 

Startup Probe

파드가 처음 기동이 완료되었는지 확인하기 위한 헬스 체크입니다. Startup Probe가 끝날 때까지는 Liveness Probe, Readiness Probe가 시작되지 않으며, 해당 Pod가 서비스가 정지되지 않습니다.

 

또한 Probe는 다음 세 가지 결과 중 하나를 가집니다.

 

Success: 컨테이너가 진단을 통과함

Failure: 컨테이너가 진단에 실패함

Unknown: 진단 자체가 실패하였으므로 아무런 액션도 수행되면 안됨

 

 

이제 3가지 헬스체크 방법에 대해 어떤 방식을 통해 헬스 체크를 할 수 있는지 알아보겠습니다.

 

헬스체크 방식

Liveness Probe / Readiness Probe / Startup Probe 모두 아래 헬스 체크 방식을 사용할 수 있습니다.

헬스 체크 방식 내용
exec 명령어를 실행하고 종료 코드가 0이 아니면 실패
httpGet HTTP GET 요청을 실행하고 status 200~399가 아니면 실패
tcpSocket TCP 세션이 연결되지 않으면 실패

* 명령어 기반의 체크(exec)

성공: 종료 코드가 0

실패: 종료 코드가 0 이외

livenessProbe:
  exec:
    command: ["test", "-e", "/ok.txt"]

 

* HTTP 기반의 체크(httpGet)

HTTP GET 요청의 status code로 확인합니다. 설정 항목으로는 path, scheme(http/https)

성공: status code가 200 ~ 399

실패: status code가 200 ~ 399 이외 

livenessProbe:
  httpGet:
    path: /
    port: 8080

 

* TCP 기반의 체크(tcpSocket)

TCP 세션 활성화를 검증하여 확인합니다. 

성공: TCP 세션 활성화 기능

실패: TCP 세션 활성화 불가능

livenessProbe
  tcpSocket:
    port: 80

헬스체크 간격

 

Liveness Probe / Readiness Probe / Startup Probe 모두 아래 다섯 가지 헬스 체크 간격에 대해 파라미터 설정이 가능합니다. 

설정 항목 내용
initialDelaySeconds 첫 번째 헬스 체크 시작까지의 지연(최대 failureTreshold 만큼 연장)
periodSeconds 헬스 체크 간격 시간(초)
timeoutSecondds 타임아웃까지의 시간(초)
successThreshold 성공이라고 판단하기까지의 체크 횟수
failureThreshold 실패라고 판단하기까지의 체크 횟수

 

아래 예시를 보고 LivenessProbe, ReadinessProbe 설정값을 보고 설명해보겠습니다.

 

LivenessProbe는 컨테이너가 정상적으로 작동하고 있는지 체크합니다. Pod가 배포되게 되면 initialDelaySeconds에 지정한 40초에 값 만큼 기다렸다가 periodSeconds의 값만큼 한번씩 httpGet에 세팅한 path와 port로 health check를 위한 HTTP Get 요청을 날립니다. successThreshold가 1이므로 status code가 200~399 안에 있고 헬스체크가 성공하면 성공으로 간주합니다. 만약 200~399 이외의 코드로 반환하면 헬스체크 실패로 간주합니다.

 

ReadinessProbe는 컨테이너가 요청을 처리할 준비가 되었는지 여부를 확인해줍니다. LivenessProbe와 똑같이 initialDelaySeconds에 지정한 30초만큼 기다렸다가 periodSeconds의 값만큼 한번씩 httpGet에 세팅한 path와 port로 health check를 위한 HTTP Get 요청을 날립니다. 여기서는 요청이 실패하더라도 failureThreshold를 3으로 지정했기 때문에 해당 값만큼 실패한 경우에는 Pod에 트래픽을 차단하게 됩니다.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: h-devops
  namespace: dev-service
  labels:
    app: h-devops
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
  selector:
    matchLabels:
      app: h-devops
  template:
    metadata:
      labels:
        app: h-devops
    spec:
      containers:
      - name: h-devops
        image: h-devops:1111
        ports:
          - name: http
            containerPort: 8080
        livenessProbe:
          httpGet:
            path: /
            port: 8080
          initialDelaySeconds: 40
          periodSeconds: 30
          successThreshold: 1
          timeoutSeconds: 10
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 20
          successThreshold: 1
          timeoutSeconds: 10

 

지금까지는 컨테이너가 기동될때 정상적인지 비정상적인지 판별하고 확인할 수 있는 방법을 살펴보았는데,

이제 컨테이너 기동 후와 정지 직전에 임의의 명령어를 실행할 수 있는 방법에 대해 알아보겠습니다.


postStart: 실행과 거의 같은 타이밍에 실행됩니다. 엄밀히말하면 비동기로 실행되기 때문에 Entrypoint가 실행되기 전에 postStart가 실행될 가능성도 있습니다. 따라서, 기동 시에 필요한 파일을 배치하는 등의 작업은 초기화 컨테이너를 사용하는것이 좋습니다.

 

preStop: 종료 요청이 온 후에 실행됩니다. 보통 Pod에 안전한 정지와 타이밍을 위해 설정합니다.

 

아래 yaml 파일을 예시로 preStop에 대해 자세히 알아보겠습니다.

알아보기 전에 SIGTERM 과 SIGKILL에 대해 조금 알아보겠습니다.

 

SIGTERM: 컨테이너가 속한 Pod가 종료 중이기 때문에 단순히 Probe 점검이 실패해 컨테이너가 재시작되든 kubernetes 컨테이너를 멈추기로 결정할때 해당 신호를 보냄 (kubernetes 갑자기 SIGKILL 신호를 보내기 전에 Pod(컨테이너)가 깨끗하고 안전하게 종료될 수 있도록 컨테이너를 종료하는 것)

 

SIGKILL: SIGTERM 신호 수신 후에도 컨테이너 프로세스가 종료되지 않는다면 SIGKILL 신호에 의해 강제로 죵료됩니다. kubernetes는 SIGKILL 명령어를 바로 보내지 않고 SIGTERM 신호가 발생 후 처리하게 됩니다. SIGTERM 신호가 발생 후 기본적으로 대기하는 시간 terminationGracePeriodSeconds(30) 기다리게 됩니다.

 

그렇다면 여기서 terminationGracePeriodSeconds이란 kubelet에서 pod에 SIGTERM을 보낸후(즉, 서비스에서 제외처리)에 일정시간동안은 graceful shutdown이 되지 않는다면 강제로 SIGKILL을 보내서 Pod를 종료하게 하는데 바로 이 graceful shutdown이 발생하기 까지 얼마나 대기를 시킬것인지를 설정하는 것이라고 설명할 수 있겠습니다. (default 30)

 

다시 돌아와서 yaml 파일 예시로 preStop에 대해 자세히 알아보겠습니다.

 

기동 중인 Pod의 삭제 요청이 kubernetes api 서버에 도착하면 비동기로 'preStop 처리' + 'SIGTERM 처리' 와 '서비스에서 제외 설정'이 이루어집니다. 따라서 '서비스에서 제외 설정'이 끝나기 전에 'preStop 처리 + SIGTERM 처리'에서 프로세스를 정지해 버리면 일부 요청에서 에러가 발생하고 서비스 이용중에 커넥션이 맺어진 상태의 사람들은 에러를 직면하게 될 것입니다. 서비스 제외 처리가 끝나기 몇 초간은 'preStop 처리 + SIGTERM 처리'에서 대기하는것이 효과적입니다.

 

따라서, preStop은 Pod에 SIGTERM을 보내기 전에 실행되기 때문에 preStop을 이용해서 서비스와 별개로 graceful shutdown(어플리케이션 서버 종료시 새로운 요청은 받지 않고 기존 요청을 완전히 처리한 이후 서버를 종료) 효과를 내게 할 수 있습니다. preStop의 실행이 완료되기 전까지는 Pod에 SIGTERM을 보내지 않게 대기시간을 아래처럼 40초를 주게 되면 40초동안은 preStop을 처리하게 됩니다. 하지만 terminationGracePeriodSeconds 시간 60초를 초과한다면 프로세스 종료가 이루어질 수 있으니 적당한 시간을 지정해 사용해야합니다.

 

preStop이 terminationGracePeriodSeconds 시간보다 오래걸리는 경우에는 2초의 임의시간을 더 부여하고 SIGKILL 처리를 하므로 preStop 소요시간이 terminationGracePeriodSeconds 설정시간을 넘지 않도록 값을 적절하게 조정해야합니다.

 

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: h-devops
  namespace: dev-service
  labels:
    app: h-devops
spec:
  selector:
    matchLabels:
      app: h-devops
  template:
    metadata:
      labels:
        app: h-devops
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: h-devops
        image: h-devops:1111
        lifecycle:
          preStop:
            exec:
              command: [ "sh", "-c", "sleep 40" ]
댓글
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31