개요
쿠버네티스는 파드가 노드에 스케줄링 되는 즉시 해당 노드의 kubelet에 의해 파드를 생성하고, 파드가 존재하는한 컨테이너가 실행 상태를 유지하도록 합니다. 즉, 실행되는 컨테이너에 문제(Crash, bug, etc...)가 발생하여 중지 상태가 되면 이를 감지하고 새로운 컨테이너를 실행하도록 합니다. 이로써 문제가 발생하는 컨테이너를 정상화 시킬 수 있습니다.
그러나 쿠버네티스는 문제가 발생하는 파드를 감지하지 못하는 경우도 있습니다. 자바 애플리케이션의 OutofMemoryErrors, 교착상태, 무한 루프 등 이죠 이는 컨테이너 상태는 정상이지만 애플리케이션의 정상 작동이 불가한 경우 이며 정상적인 서비스 운영에 문제를 발생시킵니다.
컨테이너의 오류를 넘어서 애플리케이션의 오류를 감지하기 위한 쿠버네티스의 liveness probe 기능에 대해 알아보고자 합니다.
Liveness probe
쿠버네티스의 liveness probe를 통해 애플리케이션이 정상 작동중인지 확인할 수 있습니다. liveness는 배포될 파드의 스펙에 정의할 수 있으며, 크게 4가지 종류(`HTTP GET`, `TCP Socket`, `EXEC`, `gRPC`)의 메커니즘을 통해 확인 합니다. 그 중 HTTP Get probe를 통해 liveness probe를 확인해보겠습니다.
HTTP Get probe
HTTP GET을 통해 애플리케이션의 상태를 확인합니다. 지정된 URL을 통해 애플리케이션 상태를 모니터링 하며, 200~400 미만의 값이 반환된다면 정상, 다른 코드값을 반환받으면 실패로 간주합니다.
HTTP Get probe에 대해 간단히 실습해보겠습니다. 아래 코드는 컨테이너가 활성화된 처음 10초 동안 /healthz 상태 200을 반환합니다. 그 후 핸들러는 상태 500을 반환합니다.
#main.go
package main
import (
"fmt"
"net/http"
"time"
)
var started time.Time
func main() {
started = time.Now()
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
duration := time.Now().Sub(started)
if duration.Seconds() > 10 {
w.WriteHeader(500)
w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
} else {
w.WriteHeader(200)
w.Write([]byte("ok"))
}
})
port := "8080"
fmt.Printf("Server is running on :%s\n", port)
if err := http.ListenAndServe(":"+port, nil); err != nil {
fmt.Printf("Server error: %v", err)
}
}
위 코드로 작성된 컨테이너를 배포해보고, 어떤일이 발생하는지 확인해보겠습니다.
#liveness.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: my-go-app:1.2
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 3
periodSeconds: 3
---
apiVersion: v1
kind: Service
metadata:
name: liveness-service
spec:
selector:
test: liveness
ports:
- protocol: TCP
port: 8080
targetPort: 8080
type: NodePort
`initialDelaySeconds: 3` : 첫 번째 probe 검사까지 3초의 유예기간을 부여합니다. 컨테이너가 구동되더라도 애플리케이션의 running을 보장하지 않기 때문에 일정기간의 유예기간을 두어 최초 검사가 성공할 수 있도록 하는데 사용합니다.
`periodSeconds: 3` : kubelet이 3초의 간격으로 liveness 검사를 진행하도록 합니다.
위 yaml을 kubectl을 통해 배포 후 kubectl get pod를 통해 상태를 확인해보겠습니다.
`kubectl get pod`
NAME READY STATUS RESTARTS AGE
liveness-http 1/1 Running 2 (7s ago) 43s
최초 배포로부터 43초가 지났지만, 총 2번의 재시작이 진행된 것을 확인할 수 있습니다.
`kubectl describe pods liveness-http`를 통해 자세한 정보를 확인해보겠습니다.
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m10s default-scheduler Successfully assigned default/liveness-http to minikube
Normal Pulled 77s (x4 over 2m10s) kubelet Container image "my-go-app:1.2" already present on machine
Normal Created 77s (x4 over 2m10s) kubelet Created container liveness
Normal Killing 77s (x3 over 113s) kubelet Container liveness failed liveness probe, will be restarted
Normal Started 76s (x4 over 2m10s) kubelet Started container liveness
Warning Unhealthy 65s (x10 over 119s) kubelet Liveness probe failed: HTTP probe failed with statuscode: 500
`Killing` : 컨테이너 livenessProbe에 실패하였으므로 컨테이너가 종료되고 재시작될 것임을 나타냅니다.
`Started`: kubelet이 컨테이너를 재기동 하였습니다.
`Unhealthy` : HTTP probe 요청이 상태 코드 500을 반환하였으므로 컨테이너의 liveness probe가 실패한 것으로 확인되어 컨테이너가 재기동 됨을 나타냅니다.
이로써 liveness probe를 사용하여 Pod의 상태를 주기적으로 모니터링하여 문제가 발생할 경우 Pod를 재기동하는 동작을 확인해 볼 수 있었습니다.
결론
쿠버네티스의 liveness probe는 Pod위에서 구동되는 애플리케이션의 상태를 확인하고 정상 상태를 유지하는데 쓰이며, 애플리케이션의 상태를 HTTP GET, TCP Socket, Exec, gRPC등 다양한 메커니즘의 상세한 조건값을 통해 모니터링 할 수 있습니다.
liveness는 애플리케이션의 근본적인 오류를 해결해주는 것이아니라 단순히 Pod를 재기동하여 문제를 회피(?)하는 것을 알 수 있었습니다.
'클라우드' 카테고리의 다른 글
[EKS] Networking (0) | 2024.03.14 |
---|---|
[EKS] Amzaon EKS 설치 및 기본 사용 (0) | 2024.03.09 |
[devops] Argo project로 CI/CD Pipeline 구현하기 (0) | 2023.07.26 |
[Docker] Docker-Compose (0) | 2023.07.14 |
[Docker] Centos이미지 기반 httpd 서비스 구성하기 (0) | 2023.07.14 |