본문 바로가기

Kubernetes

쿠버네티스 헬스 체크

쿠버네티스에는 파드가 정상인지를 판단하기 위한 헬스 체크 기능이 있다. 파드에 설정된 spec.restartPolicy에 따라 파드를 재시작한다.

 

쿠버네티스에는 Liveness Probe, Readiness Probe, Startup Probe라는 세 가지 헬스 체크 방법이 있다.

 

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

 

Liveness Probe는 파드 내부의 컨테이너가 정상적으로 동작 중인지 확인하기 위한 헬스 체크이며 한번 실패하면 재시작 없이는 복구가 어려운 컨테이너에 사용한다.

 

반면에 Readiness Probe는 파드가 요청을 받아들일 수 있는지 확인하기 위한 헬스 체크다. 백엔드 데이터베이스에 정상적으로 접속되는지 캐시에 로드가 끝났는지 기동 시간이 오래 걸리는 프로세스가 기동을 완료했는지 등을 체크한다. 

 

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

 

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

 

헬스 체크는 위 3가지 방식으로 확인할 수 있으며 컨테이너별로 이루어져 어느 하나의 컨테이너라도 실패하면 전체 파드가 실패한 것으로 간주한다

 

명령어 기반의 체크(exec)

명령어를 실행하고 종료 코드로 확인한다. 종료 코드가 0이면 성공으로 간주하고 0 이외의 코드면 실패로 간주한다.

 

HTTP 기반의 체크(httpGet)

HTTP GET 요청의 Status Code로 확인한다. 설정 항목은 path, scheme(http, https), host, httpHeaders 등과 같은 세부 설정이 가능하다.

 

livenessProbe:
  httpGet:
    path: /health
    port: 80
    scheme: HTTP
    host: web.example.com
    httpHeaders:
      - name: Authorization
        value: Bearer TOKEN

 

TCP 기반의 체크(tcpSocket)

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

 

livenessProbe:
  tcpSocket:
    port: 80

 

헬스 체크의 체크 간격에 대한 설정 항목은 아래와 같다

 

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

 

Readiness Probe를 무시한 서비스 생성

Readiness Probe가 실패하는 경우에는 서비스(엔드포인트)에서 제외된 상태가 된다. 반면 스테이트풀셋에서 Headless 서비스를 사용할 때는 파드가 Ready 상태가 되지 않아도 클러스터를 구성하기 위해 각 파드의 이름 해석이 필요한 경우가 있다. Readiness Probe가 실패한 경우에도 서비스에 연결되게 하려면 spec.publishNotReadyAddresses를 true로 설정한다.

 

kind: Service
apiVersion: v1
metadata:
  name: sample-publish-notready
spec:
  type: ClusterIP
  publishNotReadyAddresses: true
  ports:
  - name: "http-port"
    protocol: "TCP"
    port: 8080
    targetPort: 80
  selector:
    app: publish-notready

위와 같이 publishNotReadyAddresses를 true로 설정할경우 파드가 Ready 상태가 아니어도 이름 해석이 가능하다.

 

컨테이너 라이프사이클과 재기동(restartPolicy)

컨테이너 프로세스 정지 또는 헬스 체크 실패 시 컨테이너를 재기동할지는 spec.restartPolicy로 지정할 수 있다.

 

restartPolicy 내용
Always 파드가 정지하면 항상 파드를 재기동
OnFailure 예상치 못하게 파드가 정지한 경우(종료 코드 0 이외) 파드 재기동
Never 파드가 정지해도 파드를 재기동하지 않음

 

초기화 컨테이너

초기화 컨테이너(Init Container)란 파드 내부에서 메인이 되는 컨테이너를 기동 하기 전에 별도의 컨테이너를 기동 하기 위한 기능을 말한다. 초기화 컨테이너는 여러 개 지정할 수 있으며 위에서부터 하나씩 순서대로 컨테이너가 기동 된다.

 

사용 사례로는 저장소에서 파일 등을 가져오는 처리, 컨테이너 기동을 지연시키는 처리, 설정 파일을 동적으로 생성하는 처리, 서비스가 생성되어 있는지 확인하는 작업과 그 외 메인 컨테이너를 기동 하기 전의 체크 작업 등이 있다.

 

apiVersion: v1
kind: Pod
metadata:
  name: saple-initcontainer
spec:
  initContainers:
  - name: output-1
    image: nginx:1.16
    command: ["sh", "-c", "sleep 20; echo 1st > /usr/share/nginx/html/index.html"]
    volumeMounts:
      - name: html-volume
        mountPath: /usr/share/nginx/html/
  - name: output-2
    image: nginx:1.16
    command: ["sh", "-c", "sleep 10; echo 2nd > /usr/share/nginx/html/index.html"]
    volumeMounts:
      - name: html-volume
        mountPath: /usr/share/nginx/html/
  containers:
  - name: nginx-container
    image: nginx:1.16
    volumeMounts:
      - name: html-volume
        mountPath: /usr/share/nginx/html/
  volumes:
  - name: html-volume
    emptyDir: {}

 

기동 직후와 종료 직전에 임의의 명령어를 실행(postStart/preStop)

쿠버네티스에서는 컨테이너 기동 후와 정지 직전에 임의의 명령어를 실행할 수 있다.

 

apiVersion: v1
kind: Pod
metadata:
  name: sample-lifecycle-exec
spec:
  containers:
  - name: nginx-container
    image: nginx:1.16
    command: ["/bin/sh", "-c", "touch /tmp/started; sleep 3600"]
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", "sleep 20; touch /tmp/poststart"]
      preStop:
        exec:
          command: ["/bin/sh","-c", "touch /tmp/prestop; sleep 20"]

기동후 tmp 디렉터리를 확인해보면 started 파일이 생성돼있고 20초 후 다시 확인을 해보면 poststart라는 파일이 존재한다. 파드 삭제 요청을 보내고 바로 다시 확인을 해보면 prestop 파일도 존재하는 것을 확인할 수 있다.

 

spec.container.command 와 postStart는 거의 같은 타이밍에 실행된다. 엄밀히 말하면 비동기로 실행되기 때문에 순서가 항상 달라질 수 있다는 점을 유의해야 한다. preStop은 종료 요청이 온 후 실행된다. 또한 exec 말고도 httpGet도 실행할 수 있다. 

 

스케줄링 대상에서 제외와 복귀(cordon/uncordon)

쿠버네티스의 노드는 SchedulingEnabled와 SchedulingDisabled 중 하나의 상태를 가진다. 각 상태로 전환하는 것이 uncordon과 cordon이다.

 

kubectl cordon nodeID -> nodeID is schedulingDisabled

 

상태를 SchedulingDisabled로 변경해도 이후의 스케줄링 대상에서 제외될 뿐이며 노드에서 이미 실행 중인 파드는 정지되지 않는다. 노드상에서 실행 중인 모든 파드를 축출시키는 배출처리(drain)를 하려면 kubectl drain 명령어를 사용한다. 배출 처리에는 이후의 스케줄링 대상에서 제외하는 처리도 포함되어 있어 미리 kubectl cordon을 실행할 필요가 없다.

 

배출 처리를 실행했을 시 다음과 같은 경우 에러가 발생할 수 있는데 문제가 없는지 제대로 확인한 후에 처리해야 한다.

 

  • Pod not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet
    • 에러 발생 상황: 디플로이먼트 등으로 관리되지 않은 파드를 삭제하려고 할 때
    • 이유: 단일 파드가 있으면 파드 삭제 후에 재생성이 되지 않기 때문
    • 해결책: --force 옵션을 사용하여 삭제
  • Pod with local storage
    • 에러 발생 상황: 로컬 스토리지를 사용하고 있는 파드를 삭제하려고 할 때
    • 이유: 로컬 스토리지를 사용하고 있는 경우 데이터가 삭제되기 때문에
    • 해결채: --delete-local-data 옵션을 사용하여 삭제
  • DaemonSet-managed pod
    • 에러 발생 상황: 데몬셋이 관리하는 파드를 삭제하려고 할 때
    • 이유: 데몬셋이 관리하는 파드는 축출되지 않기 때문에
    • 해결책: --ignore-daemonsets 옵션을 사용하여 삭제

 

PodDisruptionBudget(PDB)을 사용한 안전한 축출

PodDisruptionBudget은 노드가 배출 처리를 할 때 파드를 정지할 수 있는 최대 수를 제한하는 리소스다. 해당 리소스를 생성하면 조건에 일치하는 파드의 최소 기동 개수(spec.minAvailable)와 최대 정지 개수(spec.maxUnavailable)를 보면서 노드상에서 파드를 축출할 수 있다.

 

apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: sample-pod-disruption-budget
spec:
  minAvailable: 1
  # maxUnavailable: 1
  selector:
    matchLabels:
      app: sample-app

 

'Kubernetes' 카테고리의 다른 글

쿠버네티스 보안  (0) 2022.01.31
쿠버네티스 노드 스케줄링  (0) 2022.01.28
쿠버네티스 리소스 관리 및 오토 스케일링  (0) 2022.01.08
쿠버네티스 볼륨  (0) 2022.01.02
쿠버네티스 컨피그 API  (0) 2022.01.01