Kubernetes

Kubernetes Liveness Readiness

김 정출 2024. 10. 13. 20:12

Kubernetes Liveness Readiness

Kubernetes에서 LivenessReadiness 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의 차이

image.png


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가 너무 일찍 실패하지 않도록 해야 합니다.
  • 적절한 재시도 간격: periodSecondstimeoutSeconds 값을 적절히 설정하여 Probe가 너무 자주 실패하거나 과도한 재시도가 발생하지 않도록 합니다.
  • 재시도 허용: Liveness Probe의 경우 애플리케이션의 일시적인 문제로 인해 컨테이너가 너무 자주 재시작되지 않도록 재시도 횟수(failureThreshold)를 설정하는 것이 중요합니다.

5. Golang의 Gin 프레임워크를 통한 Readiness와 Liveness 구현

  • 아래는 Golang의 Gin 프레임워크를 사용하여 healthz와 ready API 엔드포인트를 구현한 예시입니다.
  • healthz 엔드포인트는 서버의 일반 상태를 확인하고, ready 엔드포인트는 MySQL DB 커넥션 상태를 체크하여 커넥션이 실패할 경우 적절한 상태를 반환하도록 구현하였습니다.
  1. 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)
  1. 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)
    }
}
  1. 코드 설명
    • 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"를 반환합니다.
  2. 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로 변경하여 테스트할 수 있습니다.

  1. API 테스트

서버가 실행되면 다음 명령어로 API를 테스트할 수 있습니다.

curl http://localhost:8080/healthz

응답:

{
  "status": "OK"
}
  1. Readiness Check (DB 연결 상태 확인):
curl http://localhost:8080/ready
  • DB 연결 성공 시:
{
  "status": "READY"
}

DB 연결 실패 시:

{
  "status": "FAIL",
  "error": "Cannot connect to database"
}

요약

  • Gin 서버를 이용해 healthzready API를 구현했습니다.
  • healthz는 서버의 기본 상태를 확인하고, ready는 MySQL DB의 커넥션 상태를 핑을 통해 확인합니다.
  • MySQL 연결이 실패하면 ready503 상태를 반환해 Kubernetes에서 서비스 준비 상태를 알 수 있도록 설정했습니다.

결론

  • Liveness Probe는 컨테이너가 정상 동작하고 있는지 확인하며, 실패 시 컨테이너를 재시작합니다.
  • Readiness Probe는 컨테이너가 트래픽을 처리할 준비가 되었는지 확인하며, 실패 시 해당 컨테이너로 트래픽을 차단합니다.
  • 두 Probe를 함께 사용하면 애플리케이션의 가용성과 안정성을 높이고, 비정상 상태에 빠진 컨테이너를 자동으로 복구할 수 있습니다.