본문 바로가기
WIKI 기술 지식 베이스

Postgres 인스턴스 매니저

원문 보기 위키 갱신

Postgres 인스턴스 매니저 (Postgres Instance Manager)

CloudNativePG는 페일오버 관리에 외부 도구에 의존하지 않아요. 단순히 Kubernetes API 서버와 Postgres 인스턴스 매니저라는 네이티브 핵심 컴포넌트에 의존해요.

인스턴스 매니저는 PostgreSQL 서버 프로세스(postmaster라고도 함)의 전체 수명 주기를 담당해요.

새 클러스터를 만들면 연산자가 인스턴스마다 Pod 하나를 만들어요. .spec.instances 필드가 만들 인스턴스 수를 지정해요.

각 Pod는 메인 컨테이너의 부모 프로세스(PID 1)로 인스턴스 매니저를 시작하며, 이는 차례로 PostgreSQL 인스턴스를 실행해요. Pod의 수명 동안 인스턴스 매니저는 시작·liveness·readiness 프로브를 처리하는 백엔드로 작동해요.

출처: 문서

본문

Startup 프로브 (Startup Probe)

startup 프로브는 프라이머리든 스탠바이든 PostgreSQL 인스턴스가 시작됐는지 보장해요.

:::info 기본적으로 startup 프로브는 pg_isready를 사용해요. 그러나 다른 startup 전략을 지정해 동작을 커스터마이징할 수 있어요. :::

기본 pg_isready 전략에서 인스턴스는 PostgreSQL이 살아 있는 즉시 시작된 것으로 간주돼요. 시작 시퀀스를 완료하는 동안(예: 크래시 복구나 WAL 재생을 수행하는 스탠바이) 아직 연결을 거부하고 있어도 그렇죠. 이는 kubelet이 정당하게 복구 중인 인스턴스를 반복적으로 재시작하는 것을 방지해요. 인스턴스는 readiness 프로브가 연결을 수락한다고 보고할 때까지 준비 안 됨(unready) 상태로 남으며, 따라서 서비스의 ready 엔드포인트에서 제외돼요.

startup 프로브가 실행되는 동안 liveness와 readiness 프로브는 비활성화돼요. Kubernetes 표준을 따라, startup 프로브가 실패하면 kubelet이 컨테이너를 종료하고, 그다음 재시작돼요.

.spec.startDelay 파라미터는 startup 프로브가 성공하도록 허용되는 최대 시간(초)을 지정해요.

기본적으로 startDelay는 3600초로 설정돼요. 특정 환경에서 PostgreSQL이 시작하는 데 필요한 시간을 기준으로 이 설정을 조정할 것을 권장해요. 기본 pg_isready 전략에서는 이 값이 postmaster가 살아나는 데 필요한 시간만 다루면 되지만, query와 streaming 전략에서는 복구 완료와 연결 수락에 필요한 시간도 포함해야 해요.

:::warning .spec.startDelay를 너무 낮게 설정하면 PostgreSQL이 시작되기도 전에 startup 프로브가 실패할 수 있고, 결과적으로 불필요한 Pod 재시작이 발생해요. :::

CloudNativePG는 startup 프로브를 다음 기본 파라미터로 구성해요:

failureThreshold: FAILURE_THRESHOLD
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5

failureThreshold 값은 startDelay를 periodSeconds로 나눠 자동 계산돼요.

구성의 .spec.probes.startup 섹션에서 프로브 설정 중 어떤 것이든 커스터마이징할 수 있어요.

:::warning 의도하지 않은 중단을 피하려면 커스텀 프로브 설정이 클러스터의 운영 요구사항에 맞춰졌는지 확인하세요. :::

:::info 프로브 구성에 대한 자세한 내용은 프로브 API 문서를 참조하세요. :::

.spec.probes.startup.failureThreshold를 수동으로 지정하면 기본 동작을 오버라이드하고 startDelay의 자동 사용을 비활성화해요.

예를 들어 다음 구성은 startDelay를 우회해 커스텀 프로브 파라미터를 명시적으로 설정해요:

# ... snip
spec:
  probes:
    startup:
      periodSeconds: 3
      timeoutSeconds: 3
      failureThreshold: 10

Startup 프로브 전략 (Startup Probe Strategy)

특정 시나리오에서는 PostgreSQL 클러스터의 startup 전략을 커스터마이징해야 할 수 있어요. 예를 들어 레플리카가 프라이머리에서 스트리밍을 시작할 때까지 시작으로 표시하는 것을 지연시키거나, 레플리카를 준비됨으로 간주하기 전에 충족해야 하는 복제 지연 임계값을 정의할 수 있어요.

이러한 요구사항을 수용하기 위해 CloudNativePG는 .spec.probes.startup 스탠자를 두 개의 선택 파라미터로 확장해요:

  • type: 프로브가 성공한 것으로 간주하는 기준을 지정. 수용 가능한 값은 복잡도/깊이가 증가하는 순서로 다음을 포함해요:

    • pg_isready: pg_isready 명령의 종료 코드에 의존. 서버가 연결을 수락하거나 살아 있지만 연결을 거부하면 startup 프로브가 성공해요 (위에서 설명한 대로). readiness 프로브는 서버가 연결을 수락할 때만 성공해요. 이는 프라이머리 인스턴스와 레플리카의 기본값이에요.
    • query: 로컬 postgres 데이터베이스에서 기본 쿼리가 실행되면 프로브를 성공으로 표시.
    • streaming: 레플리카가 소스에서 스트리밍을 시작하고 지정된 지연 요구사항(아래 세부 사항)을 충족하면 프로브를 성공으로 표시.
  • maximumLag: 수용 가능한 최대 복제 지연 정의, 바이트 단위(Kubernetes quantities로 표현). 이 파라미터는 type이 streaming으로 설정된 경우에만 적용돼요. maximumLag를 지정하지 않으면 레플리카는 스트리밍을 시작하는 즉시 성공적으로 시작된 것으로 간주돼요.

:::info[Important] .spec.probes.startup.maximumLag 옵션은 pod의 startup 단계 동안에만 검증되고 강제돼요. 즉 레플리카가 시작 중일 때만 적용돼요. :::

:::warning maximumLag 옵션의 잘못된 구성은 startup 프로브의 지속적인 실패를 일으켜 반복적인 레플리카 재시작을 초래할 수 있어요. 이 옵션이 어떻게 동작하는지 이해하고, 레플리카가 소스를 따라잡을 충분한 시간을 주도록 failureThreshold와 periodSeconds에 적절한 값을 구성했는지 확인하세요. :::

다음 예시는 레플리카가 시작된 것으로 간주되려면 소스로부터 최대 지연 16Mi를 요구해요:

# <snip>
probes:
  startup:
    type: streaming
    maximumLag: 16Mi

:::info query와 streaming 전략은 PostgreSQL이 연결을 수락해야 하므로, 이를 사용하는 startup 프로브는 인스턴스가 크래시 후 WAL을 재생하는 동안 계속 실패해요. 이 전략을 사용할 때는 복구가 완료될 충분한 시간을 startDelay(또는 커스텀 failureThreshold)가 허용하는지 확인하세요. :::

Liveness 프로브 (Liveness Probe)

liveness 프로브는 startup 프로브가 성공적으로 완료된 후 시작돼요. 주요 역할은 PostgreSQL 인스턴스 매니저가 올바르게 작동하는지 보장하는 것이에요.

Kubernetes 표준을 따라, liveness 프로브가 실패하면 kubelet이 컨테이너를 종료하고, 그다음 재시작돼요.

Pod가 살아 있지 않은 것으로 분류되기 전의 시간은 .spec.livenessProbeTimeout 파라미터로 구성할 수 있어요.

CloudNativePG는 liveness 프로브를 다음 기본 파라미터로 구성해요:

failureThreshold: FAILURE_THRESHOLD
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5

failureThreshold 값은 livenessProbeTimeout을 periodSeconds로 나눠 자동 계산돼요.

기본적으로 .spec.livenessProbeTimeout은 30초로 설정돼요. 이는 liveness 프로브가 10초 간격으로 3번 연속 프로브 실패를 감지하면 실패를 보고한다는 뜻이에요.

구성의 .spec.probes.liveness 섹션에서 프로브 설정 중 어떤 것이든 커스터마이징할 수 있어요.

:::warning 의도하지 않은 중단을 피하려면 커스텀 프로브 설정이 클러스터의 운영 요구사항에 맞춰졌는지 확인하세요. :::

:::info 프로브 구성에 대한 자세한 내용은 프로브 API 문서를 참조하세요. :::

.spec.probes.liveness.failureThreshold를 수동으로 지정하면 기본 동작을 오버라이드하고 livenessProbeTimeout의 자동 사용을 비활성화해요.

예를 들어 다음 구성은 livenessProbeTimeout을 우회해 커스텀 프로브 파라미터를 명시적으로 설정해요:

# ... snip
spec:
  probes:
    liveness:
      periodSeconds: 3
      timeoutSeconds: 3
      failureThreshold: 10

프라이머리 격리 (Primary Isolation)

CloudNativePG 1.27은 PostgreSQL 프라이머리의 liveness 프로브에 추가 동작을 도입하며, 다음 두 조건이 모두 충족되면 실패를 보고해요:

  1. 인스턴스 매니저가 Kubernetes API 서버에 도달할 수 없음
  2. 인스턴스 매니저가 인스턴스 매니저의 REST API를 통해 어떤 다른 인스턴스에도 도달할 수 없음

이 동작의 효과는 격리된 프라이머리를 살아 있지 않은 것으로 간주하는 것이에요: liveness 프로브가 실패하고, kubelet이 정상 종료 경로를 통해 컨테이너를 재시작해요. 그 경로는 스마트 종료예요: 새 연결을 거부하지만 이미 열려 있는 세션은 .spec.smartShutdownTimeout(기본 180초)이 경과할 때까지 계속 커밋하도록 허용해요. 그 창을 기다리는 대신 재시작이 바로 fast shutdown으로 가게 하려면 .spec.smartShutdownTimeout: 0을 설정하세요.

이는 기본으로 활성화되어 있으며, 다음을 추가해 비활성화할 수 있어요:

spec:
  probes:
    liveness:
      isolationCheck:
        enabled: false

:::info[Important] 기본 liveness 프로브 설정—livenessProbeTimeout에서 자동 파생된 값—이 공격적(30초)일 수 있다는 점을 알아두세요. 따라서 환경에 맞게 liveness 프로브 구성을 명시적으로 설정할 것을 권장해요. :::

스펙은 또한 두 개의 선택 네트워크 설정을 받아들여요: requestTimeout과 connectionTimeout, 둘 다 기본값은 1000(밀리초)이에요. 클라우드 환경에서는 이 값을 늘려야 할 수 있어요. 예를 들어:

spec:
  probes:
    liveness:
      isolationCheck:
        enabled: true
        requestTimeout: "2000"
        connectionTimeout: "2000"

:::info 프라이머리 격리는 안전한 프라이머리 선출 메커니즘과 구별돼요. 격리 검사는 API 서버와 다른 인스턴스 모두에 대한 연결을 잃은 프라이머리를 비정상으로 보고해, kubelet이 위에서 설명한 정상 컨테이너 종료 경로로 재시작하게 하고, 프라이머리 리스는 어떤 인스턴스가 승격하도록 허용되는지를 조정해요. 두 메커니즘은 상호 보완적이에요. :::

Readiness 프로브 (Readiness Probe)

readiness 프로브는 startup 프로브가 성공적으로 완료되면 시작돼요. 주요 목적은 pod의 수명 주기의 어느 순간에 PostgreSQL 인스턴스가 트래픽을 받아들이고 요청을 서비스할 준비가 됐는지 확인하는 것이에요.

:::info 기본적으로 readiness 프로브는 pg_isready를 사용해요. 그러나 다른 readiness 전략을 지정해 동작을 커스터마이징할 수 있어요. :::

Kubernetes 표준을 따라, readiness 프로브가 실패하면 pod가 준비 안 됨으로 표시되고 어떤 서비스로부터도 트래픽을 받지 않아요. 준비 안 된 pod는 자동 페일오버 시나리오에서도 승격 자격이 없어요.

CloudNativePG는 readiness 프로브에 다음 기본 구성을 사용해요:

failureThreshold: 3
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5

기본 설정이 요구사항에 맞지 않으면 .spec.probes.readiness 스탠자에 파라미터를 지정해 readiness 프로브를 완전히 커스터마이징할 수 있어요. 예를 들어:

# ... snip
spec:
  probes:
    readiness:
      periodSeconds: 3
      timeoutSeconds: 3
      failureThreshold: 10

:::warning 의도하지 않은 중단을 방지하려면 커스텀 프로브 설정이 클러스터의 운영 요구사항과 정렬되는지 확인하세요. :::

:::info 프로브 구성에 대한 자세한 내용은 프로브 API를 참조하세요. :::

Readiness 프로브 전략 (Readiness Probe Strategy)

특정 시나리오에서는 클러스터의 readiness 전략을 커스터마이징해야 할 수 있어요. 예를 들어 레플리카가 프라이머리에서 스트리밍을 시작할 때까지 준비됨으로 표시하는 것을 지연시키거나, 레플리카를 준비됨으로 간주하기 전에 최대 복제 지연 임계값을 정의할 수 있어요.

이러한 요구사항을 수용하기 위해 CloudNativePG는 .spec.probes.readiness 스탠자를 type과 maximumLag라는 두 개의 선택 파라미터로 확장해요. 이 옵션에 대한 자세한 정보는 Startup 프로브 전략 섹션을 참조하세요.

:::info[Important] startup 프로브와 달리 .spec.probes.readiness.maximumLag 옵션은 지속적으로 모니터링돼요. 이 설정이 적절히 튜닝되지 않으면 뒤처진 레플리카가 준비 안 됨이 될 수 있어요. :::

:::warning maximumLag 옵션의 잘못된 구성은 반복적인 readiness 프로브 실패를 초래해 다음과 같은 심각한 결과를 일으킬 수 있어요:

- 페일오버 중 승격이나 동기 복제 쿼럼 참여 같은 핵심 연산자 기능에서 레플리카 제외
- 읽기/읽기 전용 서비스의 중단
- 페일오버 시간이 긴 시나리오에서 레플리카가 준비 안 됨으로 선언되어 수동 개입이 필요한 클러스터 정체를 초래할 수 있음

:::

:::note[권장 사항 (Recommendation)] streaming과 maximumLag 옵션은 극도로 주의해서 사용하세요. PostgreSQL 복제에 익숙하지 않다면 기본 전략에 의존하세요. 확실하지 않으면 전문가의 조언을 구하세요. :::

다음 예시는 레플리카가 준비된 것으로 간주되려면 소스로부터 최대 지연 64Mi를 요구해요. 또한 startup 프로브가 성공할 약 300초(30 실패 × 10초)를 제공해요:

# <snip>
probes:
  readiness:
    type: streaming
    maximumLag: 64Mi
    failureThreshold: 30
    periodSeconds: 10

종료 제어 (Shutdown control)

Postgres를 실행하는 Pod가 삭제되면(수동으로든, kubectl node drain 작업에 따른 Kubernetes에 의해서든) kubelet이 인스턴스 매니저에 종료 신호를 보내고, 인스턴스 매니저가 PostgreSQL을 적절한 방식으로 종료하는 것을 담당해요. .spec.smartShutdownTimeout과 .spec.stopDelay 옵션(초 단위)은 PostgreSQL에 주어지는 종료 시간을 제어해요. 기본값은 각각 180초와 1800초예요.

종료 절차는 두 단계로 구성돼요:

  1. 인스턴스 매니저는 먼저 CHECKPOINT를 발행한 다음 스마트 종료를 시작해 PostgreSQL에 대한 새 연결을 허용하지 않아요. 이 단계는 최대 .spec.smartShutdownTimeout초 동안 지속돼요.

  2. PostgreSQL이 아직 살아 있으면 인스턴스 매니저가 fast 종료를 요청해, 기존 연결을 종료하고 신속하게 빠져나와요. 인스턴스가 WAL 파일을 아카이빙 및/또는 스트리밍 중이면, 프로세스는 .spec.stopDelay에 남은 시간까지 작업 완료를 기다린 다음 강제 종료돼요. 이 타임아웃은 최소 15초여야 해요.

:::info[Important] Postgres 클러스터에서 데이터 손실을 피하려면—이는 데이터베이스 RPO에 영향을 줘요—프라이머리 인스턴스가 실행 중인 Pod를 삭제하지 마세요. 이 경우 먼저 다른 인스턴스로 스위치오버를 수행하세요. :::

스위치오버 중 프라이머리 종료 (Shutdown of the primary during a switchover)

스위치오버 중에 종료 절차는 일반적인 경우와 약간 달라요. 이전 프라이머리의 인스턴스 매니저는 먼저 CHECKPOINT를 발행한 다음, 지정된 새 프라이머리가 승격되기 전에 PostgreSQL의 fast 종료를 시작해, 모든 데이터가 새 프라이머리에서 안전하게 사용 가능하도록 보장해요.

이런 이유로 .spec.switchoverDelay(초 단위)는 이전 프라이머리가 우아하게 종료하고 모든 WAL 파일을 아카이빙하는 데 주어지는 시간을 제어해요. 기본값은 3600(1시간)이에요.

:::warning .spec.switchoverDelay 옵션은 PostgreSQL 데이터베이스의 RPO와 RTO에 영향을 줘요. 낮은 값으로 설정하면 RPO보다 RTO를 선호할 수 있지만 클러스터 레벨 및/또는 백업 레벨에서 데이터 손실을 초래할 수 있어요. 반대로 높은 값으로 설정하면 데이터 손실 위험을 제거하면서 스위치오버 중 클러스터가 활성 프라이머리 없이 더 오래 남을 수 있어요. :::

이전 프라이머리의 PostgreSQL에 도달할 수 없으면 CHECKPOINT와 fast 종료가 건너뛰어지고 즉시 종료가 발행돼요. .spec.switchoverDelay는 그 fast 종료의 타임아웃이므로 이 경로에는 적용되지 않아요. 자세한 내용은 "Failover" 섹션을 참조하세요.

페일오버 (Failover)

프라이머리 pod 장애 시 클러스터는 페일오버 모드로 들어가요. 자세한 내용은 "Failover" 섹션을 참조하세요.

디스크 가득 참 (Disk Full Failure)

스토리지 소진은 PostgreSQL 클러스터의 잘 알려진 문제예요. PostgreSQL 문서는 가능한 장애 시나리오와, 디스크 사용량 모니터링이 가득 차지 않도록 방지하는 중요성을 강조해요.

이는 CloudNativePG와 Kubernetes에도 동일하게 적용돼요: "Monitoring" 섹션은 WAL 세그먼트가 사용하는 디스크 공간을 확인하고 Prometheus로 내보내지는 디스크 사용량의 표준 메트릭에 대한 세부 사항을 제공해요.

:::info[Important] 프로덕션 시스템에서 데이터베이스를 지속적으로 모니터링하는 것은 중요해요. 디스크 스토리지 소진은 데이터베이스 서버 종료로 이어질 수 있어요. :::

:::note 스토리지 소진 감지는 디스크 크기와 사용량을 정확히 보고하는 스토리지 클래스에 의존해요. Kind 같은 시뮬레이션된 Kubernetes 환경이나 csi-driver-host-path 같은 테스트 스토리지 클래스 구현에서는 그렇지 않을 수 있어요. :::

WAL이 담긴 디스크가 가득 차고 더 이상 WAL 세그먼트를 저장할 수 없으면 PostgreSQL은 작동을 멈춰요. CloudNativePG는 다음 WAL 세그먼트를 저장할 공간이 충분한지 확인해 이 문제를 올바르게 감지하고, 복구를 복잡하게 할 수 있는 페일오버 트리거를 피해요.

그래서 인간 관리자가 근본 원인을 해결할 수 있어요.

이런 경우 스토리지 클래스가 지원하면 현재 가장 빠른 조치는:

  1. 가득 찬 PVC의 스토리지 크기 확장
  2. Cluster 리소스의 크기를 같은 값으로 증가

문제가 해결되고 WAL 세그먼트에 충분한 여유 공간이 생기면 Pod가 재시작되고 클러스터가 정상 상태가 돼요.

문서의 "Volume expansion" 섹션도 참조하세요.

더 알아보기 (Learn more)