Kubernetes Liveness Readiness
Kubernetes Liveness Readiness
Kubernetes에서 Liveness와 Readiness Probes는 컨테이너의 상태를 모니터링하고, 애플리케이션의 가용성과 안정성을 유지하기 위한 중요한 도구입니다. 이 두 가지 Probes는 각각의 목적에 따라 애플리케이션의 상태를 다르게 관리합니다.
1. Liveness Probe
Liveness Probe
는 컨테이너가 정상적으로 동작하고 있는지를 확인하는 데 사용됩니다. 만약 Liveness Probe가 실패하면 Kubernetes는 해당 컨테이너를 재시작합니다. 이 메커니즘은 컨테이너가 비정상 상태에 빠졌을 때(예: 무한 루프나 중단된 상태) 이를 복구하기 위해 사용됩니다.
1-1. Liveness Probe의 주요 목적:
- 컨테이너가 응답하지 않을 때 이를 감지하고 자동으로 재시작함.
- 애플리케이션이 비정상적으로 멈추거나, 일부 기능이 동작하지 않을 때 복구하는 데 유용.
- hang 걸렸는지 유무 파악도 가능
1-2. Liveness Probe 유형:
- HTTP GET: 특정 HTTP 엔드포인트로 GET 요청을 보내 응답을 확인합니다. 상태 코드 200-399는 성공으로 간주되고, 그 외 상태 코드는 실패로 간주됩니다.
- TCP Socket: 지정된 포트로 TCP 연결을 시도하여 성공 여부를 확인합니다.
- Exec Command: 컨테이너 내에서 특정 명령어를 실행하여 성공 여부를 확인합니다.
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
initialDelaySeconds
: 컨테이너가 시작된 후 첫 번째 검사를 실행하기까지의 대기 시간(초).periodSeconds
: Probe를 주기적으로 실행하는 간격(초).
이 예시에서, /healthz
경로로 8080 포트에 대한 HTTP 요청이 5초 후부터 10초마다 실행됩니다. 만약 요청에 실패하면 컨테이너가 재시작됩니다.
2. Readiness Probe
Readiness Probe
는 컨테이너가 외부 요청을 처리할 준비가 되었는지를 확인하는 데 사용됩니다. 만약 Readiness Probe가 실패하면, Kubernetes는 해당 컨테이너로 트래픽을 전달하지 않습니다. 이는 Liveness Probe와 달리 컨테이너를 재시작하지는 않으며, 트래픽만 차단하여 서비스에 영향을 줄 수 있는 불안정한 상태를 방지합니다.
2-1. Readiness Probe의 주요 목적:
- 애플리케이션이 시작되었지만 준비가 되지 않은 경우, 트래픽을 차단하여 요청이 실패하는 것을 방지.
- 외부 종속성(DB, API 등)이 준비되지 않았을 때 트래픽을 보내지 않음.
- 애플리케이션의 초기화 시간이 긴 경우에도 유용.
2-2. Readiness Probe 유형:
- HTTP GET: 특정 HTTP 엔드포인트로 GET 요청을 보내 준비 상태를 확인합니다.
- TCP Socket: 지정된 포트로 TCP 연결을 시도하여 성공 여부를 확인합니다.
- Exec Command: 컨테이너 내에서 명령어를 실행하여 준비 상태를 확인합니다.
예시:
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
initialDelaySeconds
: 컨테이너가 시작된 후 첫 번째 검사를 실행하기까지 대기하는 시간.periodSeconds
: Probe를 주기적으로 실행하는 간격.
이 예시에서 /ready
경로로 8080 포트에 대한 HTTP 요청이 5초 후부터 5초마다 실행됩니다. 요청이 성공하면 트래픽이 전달되고, 실패하면 해당 Pod로의 트래픽이 차단됩니다.
Liveness와 Readiness의 차이
3. Liveness 및 Readiness 함께 사용하기
두 Probe를 함께 사용하여 애플리케이션의 상태를 더 효율적으로 관리할 수 있습니다. 예를 들어:
- Liveness Probe로는 애플리케이션의 비정상적인 상태를 감지하여 자동으로 재시작하도록 설정합니다.
- Readiness Probe로는 외부 서비스(DB, API 등)나 애플리케이션의 준비 상태를 확인하여 준비가 되기 전에 트래픽이 들어오는 것을 방지할 수 있습니다.
함께 사용하는 예시:
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
위 예시에서:
- Liveness Probe는 10초마다
/healthz
경로를 호출하여, 비정상 상태가 감지되면 컨테이너를 재시작합니다. - Readiness Probe는 5초마다
/ready
경로를 호출하여, DB 연결 같은 외부 종속성의 준비 여부를 확인하고, 준비되지 않았으면 트래픽을 차단합니다.
4. Probe 설정 시 고려할 사항
- 적절한 초기화 시간 설정: 애플리케이션이 부팅되는데 시간이 걸릴 수 있으므로,
initialDelaySeconds
값을 적절히 설정하여 Probe가 너무 일찍 실패하지 않도록 해야 합니다. - 적절한 재시도 간격:
periodSeconds
와timeoutSeconds
값을 적절히 설정하여 Probe가 너무 자주 실패하거나 과도한 재시도가 발생하지 않도록 합니다. - 재시도 허용: Liveness Probe의 경우 애플리케이션의 일시적인 문제로 인해 컨테이너가 너무 자주 재시작되지 않도록 재시도 횟수(
failureThreshold
)를 설정하는 것이 중요합니다.
5. Golang의 Gin 프레임워크를 통한 Readiness와 Liveness 구현
- 아래는 Golang의 Gin 프레임워크를 사용하여 healthz와 ready API 엔드포인트를 구현한 예시입니다.
- healthz 엔드포인트는 서버의 일반 상태를 확인하고, ready 엔드포인트는 MySQL DB 커넥션 상태를 체크하여 커넥션이 실패할 경우 적절한 상태를 반환하도록 구현하였습니다.
- Golang 프로젝트 초기화
먼저, 필요한 패키지를 설치해야 합니다. 프로젝트를 초기화하고 필요한 의존성을 설치합니다.
go mod init my-gin-server
go get -u [github.com/gin-gonic/gin](http://github.com/gin-gonic/gin)
go get -u [github.com/go-sql-driver/mysql](http://github.com/go-sql-driver/mysql)
- Gin 서버 구현 (main.go)
package main
import (
"database/sql"
"fmt"
"log"
"net/http"
"github.com/gin-gonic/gin"
_ "github.com/go-sql-driver/mysql"
)
// MySQL DB 설정
var db *sql.DB
// healthz 핸들러: 서버 상태를 단순히 OK로 응답
func healthz(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "OK",
})
}
// ready 핸들러: MySQL DB 핑을 통해 연결 확인
func ready(c *gin.Context) {
err := db.Ping()
if err != nil {
// DB 연결 실패 시 HTTP 503(Service Unavailable) 반환
c.JSON(http.StatusServiceUnavailable, gin.H{
"status": "FAIL",
"error": "Cannot connect to database",
})
return
}
// DB 연결 성공 시 HTTP 200 반환
c.JSON(http.StatusOK, gin.H{
"status": "READY",
})
}
func main() {
// MySQL DB 연결
var err error
dsn := "user:password@tcp(localhost:3306)/dbname" // 실제 사용자 정보 및 DB 설정
db, err = sql.Open("mysql", dsn)
if err != nil {
log.Fatalf("Error opening database: %s", err)
}
// Gin 라우터 설정
r := gin.Default()
// healthz 및 ready 엔드포인트 정의
r.GET("/healthz", healthz)
r.GET("/ready", ready)
// 서버 시작
if err := r.Run(":8080"); err != nil {
log.Fatalf("Error starting server: %s", err)
}
}
- 코드 설명
- MySQL 연결 설정:
sql.Open("mysql", dsn)
으로 MySQL에 연결합니다. 여기서dsn
은 MySQL 연결 정보를 나타내며, 형식은user:password@tcp(localhost:3306)/dbname
입니다. 실제 사용하는 DB 정보에 맞게user
,password
,host
,port
,dbname
을 수정해야 합니다.
healthz
엔드포인트:- 이 엔드포인트는 서버의 기본 상태를 확인하는 용도로 사용되며, 항상
200 OK
와 함께"status": "OK"
를 반환합니다.
- 이 엔드포인트는 서버의 기본 상태를 확인하는 용도로 사용되며, 항상
ready
엔드포인트:- 이 엔드포인트는 MySQL DB 연결 상태를 체크합니다.
db.Ping()
메소드를 사용하여 MySQL 서버와의 연결이 유지되고 있는지 확인합니다. - 만약 DB 핑이 실패하면
503 Service Unavailable
상태와 함께"status": "FAIL"
메시지를 반환합니다. - DB가 정상적으로 연결되어 있으면
200 OK
상태와"status": "READY"
를 반환합니다.
- 이 엔드포인트는 MySQL DB 연결 상태를 체크합니다.
- MySQL 연결 설정:
- MySQL 테스트 환경 설정
로컬 MySQL DB가 필요하므로, MySQL을 로컬 또는 Docker로 실행할 수 있습니다. Docker로 MySQL을 실행하는 예시는 다음과 같습니다:
docker run --name mysql-test -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=testdb -p 3306:3306 -d mysql:latest
이후 위 코드에서 dsn을 root:root@tcp(localhost:3306)/testdb로 변경하여 테스트할 수 있습니다.
- API 테스트
서버가 실행되면 다음 명령어로 API를 테스트할 수 있습니다.
curl http://localhost:8080/healthz
응답:
{
"status": "OK"
}
- Readiness Check (DB 연결 상태 확인):
curl http://localhost:8080/ready
- DB 연결 성공 시:
{
"status": "READY"
}
DB 연결 실패 시:
{
"status": "FAIL",
"error": "Cannot connect to database"
}
요약
- Gin 서버를 이용해
healthz
와ready
API를 구현했습니다. healthz
는 서버의 기본 상태를 확인하고,ready
는 MySQL DB의 커넥션 상태를 핑을 통해 확인합니다.- MySQL 연결이 실패하면
ready
는503
상태를 반환해 Kubernetes에서 서비스 준비 상태를 알 수 있도록 설정했습니다.
결론
- Liveness Probe는 컨테이너가 정상 동작하고 있는지 확인하며, 실패 시 컨테이너를 재시작합니다.
- Readiness Probe는 컨테이너가 트래픽을 처리할 준비가 되었는지 확인하며, 실패 시 해당 컨테이너로 트래픽을 차단합니다.
- 두 Probe를 함께 사용하면 애플리케이션의 가용성과 안정성을 높이고, 비정상 상태에 빠진 컨테이너를 자동으로 복구할 수 있습니다.