들어가며
probe
오랜 시간 동안 실행되는 많은 애플리케이션은 종종 오류가 날 수 있습니다. 오류가 발생하였을 때에는 재 기동이 필요하거나, 트래픽 유입을 막을 필요가 있습니다.
하지만, 분산 시스템 및 마이크로서비스 아키텍처 환경의 수십 에서 수백 개가 되는 애플리케이션들을 관리하는 것은 매우 어려운 일입니다. 특히 애플리케이션을 일일이 체크하고, 장애가 발생한 시스템을 찾아 재 시간에 재 기동 시키는 것은 더더욱 어려운 일입니다.
이를 해결해 준 Platform 이 Kubernetes 입니다.
Kubernetes는 컨테이너 오케스트레이션 도구로써, 대규모 분산 애플리케이션을 관리하기 위한 오픈소스 플랫폼입니다. Google에서 개발하고 오픈소스화된 이후, 현재는 Linux Foundation의 Cloud Native Computing Foundation(CNCF)에서 관리하고 있습니다.
Kubernetes는 애플리케이션을 클러스터링하고, 배포하며, 관리하는 일련의 프로세스를 자동화하는 데 사용됩니다. 이를 통해 애플리케이션을 쉽게 스케일링하고, 높은 가용성 및 신뢰성을 보장할 수 있습니다.
또한 Kubernetes는 컨테이너와 관련된 여러 기능을 제공합니다. 예를 들어, 컨테이너의 생명주기 관리, 네트워킹, 스토리지 관리, 로깅, 모니터링 등을 자동화할 수 있습니다. 이를 통해 애플리케이션 운영자는 애플리케이션 자체에만 집중할 수 있으며, 인프라스트럭처 관리를 대부분 Kubernetes에 맡길 수 있습니다.
본 글에서는 여러 기능 중 서비스의 가용성, 신뢰성을 보장해 주는 헬스체크 (Probe) 의 개념, 유형 및 관련된 개념에 대해 알아보고, Probe를 실제로 테스트한 것에 대한 결과를 보도록 하겠습니다.
Kubernetes Probe 는 무엇이며, 왜 이용하는가 ?
그림 1] Kubernetes Probe Diagram
Kubernetes Probe는 컨테이너의 상태를 지속적으로 모니터링하고, 문제가 발생하면 자동으로 조치를 취하는 Kubernetes 기능입니다. 이런 기능으로 서비스의 가용성, 신뢰성을 유지할 수 있습니다.
Kubernetes Probe는 크게 Liveness Probe, Readiness Probe, Startup Probe 세 가지 유형으로 나눌 수 있습니다.
- Liveness Probe: Liveness Probe를 사용하여 Container 가 활성화되어 올바르게 작동하는지 확인합니다. Kubernetes 는 주기적으로 Container 에 Health Check 요청을 Container 로 보내고 지정된 Timeout 시간 내에 응답을 받지 못하면 Container를 재기동 시킵니다. 이를 통해 Pod의 상태를 실시간으로 모니터링하고, 문제가 발생한 경우 적시에 대응할 수 있습니다. 이는 Container 가 제대로 작동하지 않는 상황을 방지하여 신뢰성 확보에 기여합니다.
- Readiness Probe : Readiness Probe 는 Container 가 트래픽을 수신할 준비가 되었는지 확인하는 데 사용됩니다. Kubernetes 는 주기적으로 Health Check 요청을 Container 로 보내고, 준비가 되었다는 응답 코드를 수신하면 트래픽을 수신할 준비가 된 컨테이너로 간주합니다. 그 외에 다른 코드를 받으면 Kubernetes 는 트래픽을 수신할 준비가 될 때까지 로드 밸런서 풀에서 해당 Container 를 제거합니다. 이를 통해, Container 가 사용 가능한 상태인지를 실시간으로 확인하고, 사용 가능하지 않은 Pod에 대한 요청을 차단하여 가용성 확보에 기여합니다.
- Startup Probe : Startup Probe는 Container 가 올바르게 시작되었는지 확인하는 데 사용됩니다. Kubernetes는 시작 단계 동안 주기적으로 Health Check 요청을 Container 로 보냅니다. 준비가 되었다는 응답 코드를 수신하면 Kubernetes는 해당 Container 가 정상적으로 기동되었다고 판단합니다. 지정된 시간 초과 내에 응답을 수신하지 못하면 Kubernetes가 컨테이너를 다시 시작합니다. 이를 통해 Liveness Probe 와 마찬가지로, 신뢰성 확보에 기여합니다. 해당 Probe는 컨테이너 생성 시 동작하며, 헬스체크에 성공하면 더 이상 동작하지 않습니다.
이처럼 Kubernetes Probe를 이용하면, 시스템의 가용성, 신뢰성을 유지할 수 있습니다.
다음은 Kubernetes Probe의 자세한 설명 및 적용 시 설정 가능한 옵션에 대해 알아보도록 하겠습니다.
Kubernetes Probe 유형 별 비교 설명 및 설정 시 조절 가능한 옵션
아래는 Probe별 실패 시 동작, 헬스체크 방식, Probe가 실행되는 타이밍을 기술한 표 입니다.
크게는 실패 시 동작과 Probe가 실행되는 타이밍을 중점으로 비교하면 좋을 것 같습니다.
Liveness Probe | Readiness Probe | Startup Probe | |
On failure |
|
|
|
Check types |
|
|
|
Execute Timing |
|
|
|
표 1] Kubernetes Probe Description Table
다음은 Probe 적용 시 설정 가능한 옵션들에 대한 설명입니다.
Value |
Default |
Description |
---|---|---|
failureThreshold |
3 |
Probe 시도가 해당 옵션에 설정된 수 만큼 연속으로 실패하면, Probe가 실패하였다고 판단합니다. Kubelet 은 Pod의 Ready 조건을 false 로 설정하고, Probe 유형 별 실패 시 동작을 수행합니다. 기본 값은 3 입니다. |
initialDelaySeconds |
0s |
Container 가 시작된 후 부터 Startup, Liveness, Readiness Probe가 실행되기 전의 Delay 시간(초) 입니다. 기본 값은 0초이며, 최소 값은 0초 입니다. |
periodSeconds |
10s |
Probe를 수행하는 빈도(초) 입니다. 기본 값은 10초 입니다. |
successThreshold |
1 |
Probe 시도가 실패 후부터 Probe가 성공했다고 판단하는 최소 연속 성공 횟수입니다. 기본 값 및 최소 값은 1입니다. Startup 및 Liveness Probe는 반드시 1 이어야 합니다. |
terminationGracePeriodSeconds (Probe-level) [Kubernetes v1.25 Beta] |
30s |
Kubelet 이 Probe에 실패한 Container 의 종료를 트리거한 다음, Container Runtime 이 해당 Container 를 강제로 중지하는 사이에 대기하도록 설정한 유예 기간(초) 입니다.기본 값은 30 초 이며, 최소 값은 1초 입니다. |
timeutSeconds |
1s |
Probe 시도 후 실패라고 간주하는 Timeout 시간입니다. 기본 값은 1초 입니다. |
표 2] Kubernetes Probes Configureable Options
출처 : Configure Liveness, Readiness and Startup Probes . (2023). https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-startup-probes.
여기서 Startup Probe가 나온 이유가 궁금할 수 있습니다. Liveness Probe와 거의 같으나, 실행되는 타이밍만 다른 것으로 보입니다. 다음 단락에서 이에 대해 자세히 알아보도록 하겠습니다.
Startup Probe는 왜 필요한가?
Startup Probe는 기동에 오랜 시간이 걸리는 애플리케이션들을 위해 만들어 졌습니다. 이 한마디 만으로는 아직도 왜 만들어 졌는지 느낌이 잘 오지 않습니다.
예를 들면, Liveness Probe를 설정할 때에 initialDelaySeconds 설정 값을 길게 잡으면 되는 것이 아닌지 의문이 듭니다.
이에 대한 궁금증을 풀기 위한 그림 2장을 준비하였습니다.
아래는 Startup Probe를 이용하였을 때와, Liveness Probe의 initalDelaySeconds 값을 길게 설정하였을 때의 비교 그림 입니다.
그림 2] Probing with Startup and Liveness Probe
그림 3] Probing with Liveness Probe only
위 그림 2와 3을 비교하였을 때에 Startup Probe를 함께 사용하였을 때에 2가지 이점이 있는 것을 확인할 수 있습니다.
- 애플리케이션 기동이 먼저 되면, 설정된 최대 시간보다 빨리 서비스를 할 수 있다. (Readiness Probe가 설정되어 있을 시, 유입이 되기 시작)
- Liveness Probe의 설정을 조금 더 유연하게 할 수 있다. (Probe 주기, 최대 실패 횟수 등을 다르게 설정 가능)
Probe에 대한 설명은 충분히 들은 것 같습니다. 이제 구체적으로 어떻게 설정하고, 어떻게 동작하는 지에 대해 알고 싶을 수 있습니다.
그러나 구체적인 동작을 알기 위해선 Probe를 설정하는 대상인 Pod 에 대해 조금 더 알아볼 필요가 있습니다.
다음 단락에선 Pod 에 대한 간략한 설명과 Pod 의 Lifecycle 에 대해 알아보도록 하겠습니다.
Pod 는 무엇이고 Lifecycle 은 어떻게 되는가?
Kubernetes 에서 Pod는 하나 이상의 애플리케이션 컨테이너(예: Docker) 그룹과 해당 컨테이너에 대한 일부 공유 리소스를 나타내는 추상화된 Kubernetes Object 입니다. Pod 에 포함된 리소스는 다음이 있습니다.
- 볼륨으로 공유 스토리지
- 고유한 클러스터 IP 주소로서의 네트워킹
- 컨테이너 이미지 버전 또는 사용할 특정 포트와 같은 각 컨테이너를 실행하는 방법에 대한 정보
그림 4] Pod Diagram
출처 : kubernetes-basics . (2023). https://kubernetes.io/docs/tutorials/kubernetes-basics/explore/explore-intro/.
이러한 Pod 는 정의된 Lifecycle 을 따르며, Pending phase 를 시작으로, Running phase를 지나, Pod 의 컨테이너의 종료 상태에 따라 Succeeded 혹은 Failed phase 로 넘어갑니다.
아래는 Pod Phase 에 대해 자세한 설명이 있는 표 입니다.
Value
|
Description
|
---|---|
Failed | Pod 내부의 모든 Container 가 종료되었으며, 하나 이상의 Container 가 실패 상태로 Terminated 된 상태입니다. 즉, Container 가 0이 아닌 상태 로 끝났거나, 시스템에 의해 종료된 것을 뜻합니다. |
Pending | Pod 가 Kubernetes Cluster 에 Accept 되어 Node 에 할당 되었으나, 하나 이상의 Container 가 설정 되지 않았거나 실행할 준비가 되지 않은 상태입니다.
아래와 같은 이유 등으로 발생할 수 있습니다.
|
Running | Pod 내부의 Container 가 잘 생성 되었고, 하나 이상의 Container 가 실행 중이거나, 실행 되고 있는 상태입니다. |
Succeeded | Pod 내부의 모든 Container 가 성공적으로 잘 Terminated 된 상태입니다. 해당 Phase 의 Pod 는 재 기동 되지 않습니다. |
Unknown | 어떠한 이유로 Pod 의 상태를 가져올 수 없습니다. 해당 Phase 는 일반적으로 Pod 와 Node 간 통신 오류로 인해 발생합니다. |
표 3] Pod Lifecycle Description Table
출처 : Pod Lifecycle . (2023). https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase.
이러한 Pod 를 대상으로 한 Probe는 Pod 의 Running Phase 에서 동작합니다. 그러나 위 “표 1” 에서는 Kubernetes Probe는 Container 의 상태가 Running 일때 동작한다고 기술하였습니다. 그 말은 Container 별로 Probe가 동작한다는 말로도 들립니다.
실제로 Kubernetes Probe는 Pod 내부의 각 Container 별로 설정이 가능합니다.
아래는 OpenShift 에서 여러 Container 를 포함한 Pod 에 Probe(Health Check)를 설정할 때의 Web Console 화면입니다.
*OpenShift 는 Kubernetes 기반으로 Redhat 이 만든 Enterprise PaaS Platform 입니다.
그림 5] Config Probe in OpenShift with Web Console
그렇다면 Kubernetes 가 Container 또한 status 를 확인하고 있다는 생각으로 이어집니다. 이 또한 맞는 말로, Container 의 상태를 Kubernetes 공식 홈페이지에서 아래와 같이 확인 가능합니다.
Value
|
Description
|
---|---|
Running | Running 상태는 Container 가 문제 없이 실행되고 있음을 의미합니다. Hook 이 설정되어 있다면, postStart Hook 이 실행 완료 되었다는 것을 의미합니다. |
Terminated | Terminated 상태는 Container 가 성공적으로 실행이 완료 되었거나, 어떠한 이유로 실행에 실패하였을 때를 나타냅니다. Container 에 preStop Hook 이 설정되어 있다면, Terminated 상태로 들어가기 전에 Hook 이 실행 됩니다. |
Wating | Container 가 Running 혹은 Terminated 가 아닐 때의 상태를 나타냅니다. Wating 상태의 Container 는 Container 를 시작하는 데에 필요한 작업 (예: Container Image Registry 에서 이미지를 가져오는 등) 의 작업을 실행하고 있습니다. |
표 4] Container Status Description Table
출처 : Pod Lifecycle . (2023). https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase.
이제 Kubernetes 에서의 Container, Pod, Probe에 대한 개념이 조금은 이해가 되는 것 같습니다.
다음 단락에선 테스트 전 Probe 동작 시점을 간단한 Diagram 으로 확인하고, 연관된 개념인 Hook 에 대해 간단히 알아보도록 하겠습니다.
Kubernetes Probe가 실행되는 타이밍과 Container Lifecycle Hook 에 대한 설명
다음은 각 Probe별 동작 시점에 대한 간단한 Diagram 입니다.
그림 6] Kubernetes Probe Diagram with Pod Lifecycle
그림을 보면 Probe는 PostStart Hook 동작이 완료된 후 동작하기 시작하는 것을 알 수 있습니다. 여기서 Hook은 Container Lifecycle 동안 특정 지점에서 특정 작업을 수행할 수 있도록 하는 메커니즘입니다.
자세한 설명은 다음과 같습니다.
Value
|
Description
|
---|---|
PostStart | 해당 Hook 는 Container 가 생성된 직후에 실행 됩니다. 그러나 Hook 가 Container 의 ENTRYPOINT 이전에 실행된다는 보장은 없습니다. |
PreStop | 해당 Hook 는 Startup 및 Liveness Probe 의 실패, 선점, 리소스 경합 등과 같은 API 요청 또는 관리 이벤트로 인해 컨테이너가 종료되기 직전에 호출됩니다.
해당 Hook 은 Container 가 이미 종료된 상태면 실패합니다. 때문에 Container 가 종료되기 전 (TERM 신호를 받기 전) 에 완료되어야 합니다. Pod 의 terminationGracePeriodSeconds 시간은 PreStop Hook 이 실행 되기 전에 카운트 되므로, Hook 실행 결과에 관계 없이 Container 는 Pod 에 설정된 terminationGracePeriodSeconds 시간 후에 종료 됩니다. |
표 5] Container Lifecycle Hook Description
출처 : Container Lifecycle Hooks . (2023). https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/.
본 단락의 마지막으로 Probe 동작 시점을 정리하면 다음과 같습니다.
- Container 생성
- Init Container 기동
- PostStart Hook 동작 및 Delay time counting
- Probe에 설정된 initialDelaySeconds 시간 동안 대기
- Probe실행
이제 해당 과정이 맞는지 테스트를 진행해 보도록 하겠습니다.
Kubernetes Probe 테스트
테스트 환경은 다음과 같습니다
- OpenShift 4.11
- CRIO
테스트 시나리오는 다음과 같습니다.
InitialDelaySeconds 값을 조정하여 각 Probe의 실행 시점이 어떻게 바뀌는지 확인하는 시나리오 입니다.
- 시나리오1 (Default)
- Startup Probe : 0s
- Readiness Probe : 0s
- 시나리오 2 (Startup Probe 에 Delay 적용)
- Startup Probe : 30s
- Readiness Probe : 0s
- 시나리오 3 (Readiness Probe 에 Delay 적용)
- Startup Probe : 0s
- Readiness Probe : 30s
테스트 용으로 만든 deployment Object 는 다음과 같습니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: probe-hook
namespace: test
spec:
selector:
matchLabels:
app: probe-hook
replicas: 1
template:
metadata:
labels:
app: probe-hook
spec:
initContainers:
- name: init
image: busybox
command: ['sh', '-c', 'echo $(date): INIT >> /probe-hook-empty-dir/timing']
volumeMounts:
- mountPath: /probe-hook-empty-dir
name: probe-hook-empty-dir
containers:
- name: probe-hook
image: busybox
command: ['sh', '-c', 'while true; do echo $(date): START >> /probe-hook-empty-dir/timing; sleep 10; echo $(date): END >> /probe-hook-empty-dir/timing; done']
volumeMounts:
- mountPath: /probe-hook-empty-dir
name: probe-hook-empty-dir
readinessProbe:
exec:
command: ['sh', '-c', 'echo $(date): READINESS PROBE >> /probe-hook-empty-dir/timing']
initialDelaySeconds: 0
lifecycle:
postStart:
exec:
command: ['sh', '-c', 'echo $(date): POST-START >> /probe-hook-empty-dir/timing; sleep 15; echo $(date): POST-START-END >> /probe-hook-empty-dir/timing']
preStop:
exec:
command: ['sh', '-c', 'echo $(date): PRE-HOOK >> /probe-hook-empty-dir/timing']
startupProbe:
exec:
command: ['sh', '-c', 'echo $(date): STARTUP PROBE>> /probe-hook-empty-dir/timing']
initialDelaySeconds: 0
volumes:
- name: probe-hook-empty-dir
emptyDir: {}
이제 테스트를 진행해 보도록 하겠습니다.
시나리오1 (Default)
- Startup Probe : 0s
- Readiness Probe : 0s
Pod 생성 후, “/probe-hook-empty-dir/timing” 파일의 내용물을 확인해 보면 다음과 같이 찍혀 있는 것을 확인할 수 있습니다.
- init container 생성 후 명령어 실행
- main container 생성 후 명령어 실행
- main container 에 설정되어 있는 PostStart Hook 에 걸린 명령어 실행
- 15초 sleep 후 PostStart 명령어 종료
- Startup Probe 실행 및 Readiness Probe 실행
~ $ cat /probe-hook-empty-dir/timing
Thu Mar 9 15:22:14 UTC 2023: INIT
Thu Mar 9 15:22:16 UTC 2023: START
Thu Mar 9 15:22:16 UTC 2023: POST-START
Thu Mar 9 15:22:26 UTC 2023: END
Thu Mar 9 15:22:26 UTC 2023: START
Thu Mar 9 15:22:31 UTC 2023: POST-START-END
Thu Mar 9 15:22:32 UTC 2023: STARTUP PROBE
Thu Mar 9 15:22:32 UTC 2023: READINESS PROBE
Thu Mar 9 15:22:36 UTC 2023: END
하지만, 이런 결과만으론 Startup Probe 와 Readiness Probe의 순서가 지켜지는 지 확인이 어렵습니다.
다음 시나리오는 이를 명확히 하기 위한 시나리오 입니다.
시나리오 2 (Startup Probe 에 Delay 적용)
- Startup Probe : 30s
- Readiness Probe : 0s
Pod 생성 후, “/probe-hook-empty-dir/timing” 파일의 내용물을 확인해 보면 다음과 같이 찍혀 있는 것을 확인할 수 있습니다.
- init container 생성 후 명령어 실행
- main container 생성 후 명령어 실행
- main container 에 설정되어 있는 PostStart Hook 에 걸린 명령어 실행
- 15초 sleep 후 PostStart 명령어 종료
- PostStart 명령 시작 36초 후 Startup Probe 실행 및 Readiness Probe 실행
~ $ cat /probe-hook-empty-dir/timing
Thu Mar 9 15:32:05 UTC 2023: INIT
Thu Mar 9 15:32:06 UTC 2023: START
Thu Mar 9 15:32:06 UTC 2023: POST-START
Thu Mar 9 15:32:16 UTC 2023: END
Thu Mar 9 15:32:16 UTC 2023: START
Thu Mar 9 15:32:21 UTC 2023: POST-START-END
Thu Mar 9 15:32:26 UTC 2023: END
Thu Mar 9 15:32:26 UTC 2023: START
Thu Mar 9 15:32:36 UTC 2023: END
Thu Mar 9 15:32:36 UTC 2023: START
Thu Mar 9 15:32:42 UTC 2023: STARTUP PROBE
Thu Mar 9 15:32:42 UTC 2023: READINESS PROBE
Thu Mar 9 15:32:46 UTC 2023: END
PostStart 스크립트가 실행된 후, Probe가 동작하는 시간이 약간 어긋나 있습니다. 이는 Default 로 설정된 Period 의 영향으로 시간이 약간 어긋난 것으로 예상 됩니다.
시나리오 3 (Readiness Probe 에 Delay 적용)
- Startup Probe : 0s
- Readiness Probe : 30s
Pod 생성 후, “/probe-hook-empty-dir/timing” 파일의 내용물을 확인해 보면 다음과 같이 찍혀 있는 것을 확인할 수 있습니다.
- init container 생성 후 명령어 실행
- main container 생성 후 명령어 실행
- main container 에 설정되어 있는 PostStart Hook 에 걸린 명령어 실행
- 15초 sleep 후 PostStart 명령어 종료
- PostStart 명령 종료 후 Startup Probe 실행
- PostStart 명령 시작 37 초 후 Readiness Probe 실행
~ $ cat /probe-hook-empty-dir/timing
Fri Mar 10 04:46:34 UTC 2023: INIT
Fri Mar 10 04:46:35 UTC 2023: START
Fri Mar 10 04:46:35 UTC 2023: POST-START
Fri Mar 10 04:46:45 UTC 2023: END
Fri Mar 10 04:46:45 UTC 2023: START
Fri Mar 10 04:46:50 UTC 2023: POST-START-END
Fri Mar 10 04:46:52 UTC 2023: STARTUP PROBE
Fri Mar 10 04:46:55 UTC 2023: END
Fri Mar 10 04:46:55 UTC 2023: START
Fri Mar 10 04:47:05 UTC 2023: END
Fri Mar 10 04:47:05 UTC 2023: START
Fri Mar 10 04:47:12 UTC 2023: READINESS PROBE
PostStart 스크립트가 실행된 후, Probe가 동작하는 시간이 약간 어긋나 있습니다. 이도 Default 로 설정된 Period 의 영향으로 시간이 약간 어긋난 것으로 예상 됩니다.
마치며 Concluding
이렇게 본 포스트에서는 Kubernetes Probe 에 대해 알아보았습니다. 이처럼 중요한 Kubernetes Probe를 적절하게 설정하면, 애플리케이션의 가용성, 신뢰성을 확보할 수 있다는 것을 확인하였습니다.
이는, Container 기동 시에 설정할 수 있는 옵션들로, Container 가 종료될 때에 Graceful 하게 종료하기 위한 설정은 따로 있습니다.
다음 포스트에서는 Graceful 하게 종료하게 설정할 수 있는 옵션인 terminationGracePeriodSeconds, PreStop Hook 에 대해 정리하도록 하겠습니다.
감사합니다.
서영은 (sye010@openmaru.io)
R&D Center
Pro
WAS, Java Servlet(서블릿) 동작 방식 한눈에 알아보기_chapter 2
/in Cloud, OpenShift, 발표자료/by 주하 원애플리케이션의 비동기 스레드가 느릴때 OPENMARU APM을 이용한 원인분석 방법_chapter 2
/in Kubernetes, OpenShift, Red Hat, 발표자료/by 주하 원WAS, Java Servlet 동작 방식 한눈에 알아보기_chapter 1
/in JBoss, OpenShift, Red Hat, 발표자료, 오픈소스/by 주하 원