Docker & Kubernetes

파드(Pod)의 동작 확인과 헬스 체크(health check)

beekei 2022. 2. 4. 01:26
반응형

파드의 동작 확인

이 전 블로그 글에서 생성한 nginx 파드가 정상적으로 동작하는지 확인해 보겠다.

 

이 nginx 파드는 백그라운드로 돌면서 클러스터 네트워크의 TCP 80번 포트에서 요청을 대기한다.

클러스터 네트워크는 K8s 클러스터를 구성하는 노드 간의 통신을 위한 폐쇄형 네트워크다. 다른 말로는 파드 네트워크라고 불린다.

클러스터 네트워크에서 오픈한 포트는 K8s 클러스터를 호스팅하는 컴퓨터에서도 접근할 수 없다.

이 말은 외부에서 접속할 수 없다는 뜻이다. 그렇기 때문에 대화형 파드를 기동해 접속해야 한다.

 

파드의 클러스터 네트워크의 IP 주소를 확인하고 싶은 경우에는 -o wide 옵션을 추가하면 된다.

여기서 얻은 IP에 curl로 접속을 시도해보면 다음과 같이 타임아웃이 될 뿐이다.

K8s 클러스터 외부에서 클러스터 네트워크에 있는 파드에 접근하기 위해서 busybox 파드에 접속해 wget 커맨드를 실행하여 접속을 시도해보면 정상적으로 동작되는 것을 확인할 수 있다.

정리하자면, 파드는 클러스터 네트워크 상에 IP 주소를 가지며 이 주소를 바탕으로 파드와 파드가 서로 통신할 수 있다.

BusyBox는 도커허브에 등록된 공식 이미지 중 하나다. 약 1MB밖에 되지 않는 이미지 안에 유용한 명령어들이 다수 포함되어 있어 임베디드 리눅스의 맥가이버 칼이라고도 불린다.

 

파드의 헬스 체크 기능

파드의 컨테이너에는 애플리케이션이 정상적으로 기동 중인지 확인하는 기능, 즉 헬스 체크 기능을 설정할 수 잇어, 이상이 감지되면 컨테이너를 강제 종료를 하고 재시작시킬 수 있다.

여러 개의 웹 서버의 앞단에서 요청을 받아들이는 로드밸런서는 주기적으로 요청을 보내서 각 서버의 애플리케이션이 정상적으로 동작 중인지를 확인한다. 이때 내부 에러(HTTP STATUS 500)가 반복해서 반환되면 해당 서버로의 전송을 중지하고, 나머지 서버들에게만 요청을 전송하게 된다. 

이렇게 하여 서버 장애가 유저에 미치는 영향을 줄인다. 한편, K8s에서는 노드에 상주하는 kubelet이 이 컨테이너의 헬스 체크를 담당한다.

기존의 로드밸런서와 쿠버네티스의 헬스 체크 비교

kubelet의 헬스 체크는 다음 두 종류의 프로브를 사용하여 실행 중인 파드의 컨테이너를 검사한다.

  • 활성 프로브(Liveness Probe)
    컨테이너의 애플리케이션이 정상적으로 실행 중인 것을 검사 한다. 검사에 실패하면 파드상의 컨테이너를 강제로 종료하고 재시작한다. 이 기능을 사용하기 위해서는 매니페스트에 명시적으로 설정해야 한다.

  • 준비상태 프로브(Readiness Probe)
    컨테이너의 애플리케이션이 요청을 받을 준비가 되있는지 아닌지를 검사한다. 검사에 실패하면 서비스에 의한 요청 트래픽 전송을 중지한다. 파드가 기동하고 나서 준비가 될 때까지 요청이 전송되지 않기 위해 사용한다. 이 기능을 사용하기 위해서는 매니페스트에 명시적으로 설정해야 한다.

로드밸런서와 마찬가지로 HTTP로 헬스 체크를 하는 경우에는 정기적으로 확인할 수 있도록 API를 구현해야 한다.

그리고 파드의 컨테이너에는 프로브에 대응하는 핸들러를 구현해야 한다. 이 핸들러는 컨테이너의 특성에 따라 다음 세 가지 중 하나를 선택할 수 있다.

핸들러 명칭 설명
exec 컨테이너 내 커맨드를 실행, Exit 코드 0으로 종료하면 진단 결과는 성공으로 간주되며, 그 외의 값은 실패로 간주
tcpSocket 지정한 TCP 포트번호로 연결할 수 있다면, 진단 결과는 성공으로 간주
httpGet 지정한 포트와 경로로 HTTP GET 요청이 장기적으로 실행, HTTP 상태 코드가 200이상 400 미만이면 성공으로 간주되고, 그 외에는 실패로 간주, 지정 포트가 열려 있지 않은 경우도 실패로 간주

 

헬스 체크 설정

webapl-pod.yml

apiVersion: v1
kind: Pod
metadata:
  name: webapl
spec:
  containers:
  - name: webapl
    image: maho/webapl:0.1 # 프로브에 대응하는 핸들러가 구현되어있는 이미지
    livenessProbe: # 활성 프로브에 대한 핸들러 설정
      httpGet: # HTTP 핸들러
        path: /healthz
        port: 3000
      initialDelaySeconds: 3 # 처음으로 검사를 수행하기 전의 대기 시간
      periodSeconds: 5 # 검사 간격
    readinessProbe: # 준비 상태 프로브에 대한 핸들러 설정
      httpGet:
        path: /ready
        port: 3000
      initialDelaySeconds: 15
      periodSeconds: 6

 

기본 설정으로는 활성 프로브가 연속해서 3번 실패하면 kubelet이 컨에티너를 강제 종료하고 재기동한다.

컨테이너가 재시작되면 컨테이너에 있어던 정보들은 별도로 저장하지 않은 이상 지워진다.

주요 항목 설정
httpGet HTTP 핸들러
httpGet: path, port 핸들러의 경로, HTTP 서버의 포트번호

예)
readinessProbe:
  httpGet:
    path: /ready
    port: 3000
tcpSocket TCP 포트 접속 핸들러
tcpSocket: port 감시 대상의 포트번호

예)
readinessProbe:
  tcpSocket:
    port: 80
exec 컨테이너 내의 커맨드 실행 핸들러
exec: comman 컨테이너의 커맨드를 배열로 기술

예)
livenessProbe:
  exec:
    command:
    - cat
    - /tmp/healthy
initialDelaySeconds 프로브 검사 시작 전 대기 시간
periodSeconds 검사 간격

구체적인 파라미터는 API 레퍼런스에 기재되어 있다.

 

헬스 체크는 파드가 스케줄된 노드에 있는 kubelet이 수행하는데, 노드의 하드웨어 장애 시에는 kubelet도 정지되기 때문에 노드의 장애 대책으로는 적합하지 않다.

컨트롤러의 관리 대상은 파드이므로 노드의 장애 대책을 위해서는 헬스 체크가 아닌 컨트롤러를 사용해야 한다. 이러한 용도로 자주 사용되는 컨트롤러가 디플로이먼트와 스테이트풀셋이다.

 

그러면 이제 실제 컨테이너를 기동하여 프로브의 동작을 확인해보자.

아래와 같은 폴더 구조로 파일을 생성한다. (webapl-pod.yml은 위에 작성한 매니페스트)

Dockerfile

FROM alpine:latest

RUN apk update && apk add --no-cache nodejs npm

# 의존 라이브러리 설치
WORKDIR /
ADD ./package.json /
RUN npm install
ADD ./webapl.js /

CMD node /webapl.js

package.json

{
    "name": "webapl",
    "version": "1.0.0",
    "description": "",
    "main": "webapl.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "author": "",
    "license": "ISC",
    "dependencies": {
        "express": "^4.16.3"
    }
}

webapl.js

// 프로브 동작 확인 애플리케이션
const express = require('express')
const app = express()
var start = Date.now()

// 활성 프로브 핸들러
app.get('/healthz', function(request, response) {
    var msec = Date.now() - start
    var code = 200
    if (msec < 40000) { // 기동 40초 이후에는 code 500
        code = 500
    }
    console.log('GET /healthz ' + code)
    response.status(code).send('OK')
})

// 준비 상태 프로브 핸들러
app.get('/ready', function(request, response) {
    var msec = Date.now() - start
    var code = 500
    if (msec > 20000) { // 기동 후 20초 이후에는 code 200
        code = 200
    }
    console.log('GET /ready ' + code)
    response.status(code).send('OK')
})

app.get('/', function(request, response) {
    console.log('GET /')
    response.send('Hello from Node.js')
})

app.listen(3000); // 3000번 포트 요청 대기

 

Dockerfile을 빌드한다.

 

매니페스트로 적용하고 파드 상태를 조회한다.

 

webapl 파드의 readinessProbe가 아직 성공하지 못하여 READY 값이 0/1에서 일정 시간이 지나면 1/1로 변경된다.

 

로그를 확인해보면 LivenessProbe에서 5초 간격으로 요청을하고 6초 간격으로 ReadinessProbe에 요청한다.

ReadinessProbe에서는 20초 이내에는 500, 이후에는 200을 반환하므로 20초가 지난 후 200이 반환했을때 READY 값이 1/1로 준비가 완료된다.

 

그 후 LivenessProbe가 3회 실패 시 kubelet이 컨테이너를 교체한다.

실제 운영 환경에서는 컨트롤러를 사용하지 않고 파드만을 배포하는 경우는 거의 없다. 여기서는 프로브의 동작을 확인하기 위해서 컨트롤러를 사용하지 않았다.

반응형