본문으로 건너뛰기
4.1 Bootstrap: 클러스터 초기화

4.1 Bootstrap: 클러스터 초기화

Bootstrap은 CloudNativePG가 Cluster 리소스를 받아 첫 primary 인스턴스의 데이터 디렉토리를 채우는 초기화 단계다. spec.bootstrap 섹션에 어떤 방식으로 데이터를 마련할지 선언하면, Operator가 그에 맞춰 PGDATA를 준비하고 나머지 replica는 그 primary로부터 복제해 채운다.

방식은 세 가지이며, 한 매니페스트에는 하나만 지정할 수 있다.

  • initdb — 빈 데이터 디렉토리에서 완전히 새 클러스터를 만든다. 기본이자 가장 흔한 방식이다.
  • recovery — 기존 물리 base backup에서 복원한다. 특정 시점으로 되돌리는 point-in-time recovery도 가능하다.
  • pg_basebackup — 지금 돌고 있는 다른 PostgreSQL 인스턴스를 streaming replication으로 물리 복제해 온다.
    flowchart TD
  START["Cluster 생성"]
  BS{"bootstrap 방식"}
  INIT["initdb"]
  REC["recovery"]
  PBB["pg_basebackup"]
  NEW["빈 PGDATA 새로 생성"]
  BACKUP["object store<br/>base backup 복원"]
  CLONE["원본 인스턴스<br/>물리 복제"]
  READY["primary 기동"]

  START --> BS
  BS -->|새 클러스터| INIT --> NEW --> READY
  BS -->|백업에서| REC --> BACKUP --> READY
  BS -->|라이브 복제| PBB --> CLONE --> READY
  
CloudNativePG는 postgres superuser와 데이터베이스가 항상 존재한다고 전제한다. Operator는 Unix Domain Socket의 peer authentication으로 postgres 유저에 접속해 관리 작업을 수행하기 때문이다. 이 유저와 데이터베이스는 절대 삭제하면 안 된다.

initdb: 새 클러스터 만들기

initdb는 PostgreSQL 기본 명령인 initdb를 그대로 호출해 새 PGDATA를 만든다. 이 과정에서 Operator는 다음을 자동으로 처리한다.

  • 새 PGDATA 디렉토리 생성
  • 권한 없는 애플리케이션 유저(기본 이름 app) 생성
  • Secret에서 읽은 비밀번호 설정
  • 그 유저가 소유하는 애플리케이션 데이터베이스 생성

가장 기본적인 형태는 다음과 같다.

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-example-initdb
spec:
  instances: 3
  bootstrap:
    initdb:
      database: app
      owner: app
      secret:
        name: app-secret
  storage:
    size: 1Gi

database는 만들 애플리케이션 DB 이름, owner는 그 소유자 유저, secret은 소유자 비밀번호가 담긴 Secret이다. secret을 생략하면 Operator가 무작위 비밀번호로 Secret을 자동 생성한다.

자격 증명 Secret

애플리케이션 유저와 superuser의 비밀번호는 kubernetes.io/basic-auth 타입 Secret으로 전달한다.

apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: kubernetes.io/basic-auth
data:
  username: YXBw
  password: cGFzc3dvcmQ=

Secret의 username은 애플리케이션 자격 증명이면 owner 값과, superuser 자격 증명이면 postgres와 일치해야 한다.

data 아래 값은 base64로 인코딩한다. 위 예의 YXBwapp, cGFzc3dvcmQ=password를 인코딩한 값이다. 쿠버네티스 Secret은 인코딩일 뿐 암호화가 아니므로, RBAC로 접근을 제한하고 필요하면 별도 암호화(예: sealed-secrets)를 함께 쓴다.

initdb 옵션

initdb 호출에 넘길 옵션을 매니페스트에서 그대로 지정할 수 있다.

옵션용도
dataChecksumsdata page checksum 활성화 (I/O 손상 감지)
encodingtemplate DB 인코딩 (기본 UTF8)
locale전체 locale 동작
localeCollateLC_COLLATE (기본 C)
localeCTypeLC_CTYPE (기본 C)
localeProviderlocale provider (libc 또는 icu, PG 15+)
icuLocaleICU locale (PG 15+, localeProvider: icu 필요)
icuRulesICU collation 규칙 (PG 16+)
builtinLocalebuiltin locale (PG 17+)
walSegmentSizeWAL segment 크기
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-example-initdb
spec:
  instances: 3
  bootstrap:
    initdb:
      database: app
      owner: app
      dataChecksums: true
      encoding: 'LATIN1'
  storage:
    size: 1Gi
CloudNativePG는 locale 옵션을 검증 없이 initdb에 그대로 전달하는 프록시 역할만 한다. 값이 잘못되면 초기화가 실패하므로, PostgreSQL 문서 기준으로 조합을 확인하고 넣는다.

초기화 직후 SQL 실행

클러스터 초기화가 끝난 뒤 superuser 권한으로 SQL을 자동 실행할 수 있다. 실행 대상 DB에 따라 세 지점이 있다.

  • postInitSQLpostgres 데이터베이스에 실행
  • postInitTemplateSQLtemplate1 데이터베이스에 실행
  • postInitApplicationSQL — 애플리케이션 데이터베이스에 실행

각 지점은 SQL 문을 직접 나열하거나(postInitSQL 등), Secret·ConfigMap에 담긴 스크립트를 참조(postInitSQLRefs 등)할 수 있다.

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-example-initdb
spec:
  instances: 3
  bootstrap:
    initdb:
      database: app
      owner: app
      dataChecksums: true
      localeCollate: 'en_US'
      localeCType: 'en_US'
      postInitSQL:
        - CREATE DATABASE angus
  storage:
    size: 1Gi

외부 스크립트를 참조하는 형태는 다음과 같다. 각 목록에서 Secret이 ConfigMap보다 먼저 처리된다.

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-example-initdb
spec:
  instances: 3
  bootstrap:
    initdb:
      database: app
      owner: app
      postInitApplicationSQLRefs:
        secretRefs:
        - name: my-secret
          key: secret.sql
        configMapRefs:
        - name: my-configmap
          key: configmap.sql
  storage:
    size: 1Gi
초기화 SQL에서 에러가 나면 bootstrap 단계가 중단되고, 클러스터는 미완성 상태로 남아 수동 개입이 필요하다. 신중하게 작성한다. 또한 이 SQL은 기본 search_path"$user", public으로 실행되므로, 객체를 참조할 때는 스키마를 명시해 search_path에 의존하지 않게 한다.

recovery: 백업에서 복원

recovery 방식은 기존 물리 base backup에서 클러스터를 복원하며, 필요하면 특정 시점으로 되돌리는 point-in-time recovery도 지원한다. 백업 저장소(object store), snapshot, WAL archiving과 엮이는 부분이 많아, 백업·복구 절차와 함께 다루는 것이 자연스럽다.

이 방식의 상세는 Part VII. 백업과 복구에서 별도로 설명한다. 여기서는 recovery가 bootstrap의 한 방식이라는 점만 짚어 둔다.

pg_basebackup: 라이브 클러스터 복제

pg_basebackup은 지금 돌고 있는 다른 PostgreSQL 인스턴스를 streaming replication으로 물리 복제해 그대로 사본을 만든다. 원본은 primary든 standby든 상관없다.

주로 다음 상황에 쓴다.

  • 리포팅·BI 클러스터를 주기적으로(매일·매주) 새로 만들 때
  • 테스트 DB를 주기적으로 재생성하고 익명화할 때
  • 독립 replica 클러스터를 빠르게 띄울 때
  • namespace나 쿠버네티스 클러스터를 넘어 물리 마이그레이션할 때

요구 조건

물리 복제이므로 원본과 대상이 다음을 만족해야 한다.

  • 동일한 하드웨어 아키텍처
  • 동일한 PostgreSQL major 버전
  • 동일한 tablespace 구성
  • 원본의 max_wal_senders가 충분할 것 (백업용 1 + WAL streaming용 1, 최소 2)
  • 대상→원본 방향으로 PostgreSQL 포트 접속이 열려 있을 것
  • 원본에 REPLICATION LOGIN 권한을 가진 role이 있고, pg_hba.conf가 대상의 접속을 허용할 것

원본에서 복제 유저는 다음처럼 만든다.

createuser -P --replication streaming_replica

인증 방식

비밀번호 인증과 TLS 인증서 인증 두 가지가 있다. 운영 환경에서는 TLS 인증서 방식을 권장한다.

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: target-db
spec:
  instances: 3
  imageName: ghcr.io/cloudnative-pg/postgresql:18.4-system-trixie
  bootstrap:
    pg_basebackup:
      source: source-db
  storage:
    size: 1Gi
  externalClusters:
  - name: source-db
    connectionParameters:
      host: source-db.foo.com
      user: streaming_replica
    password:
      name: source-db-replica-user
      key: password

원본 pg_hba.conf에는 다음 항목이 필요하다(가능하면 TLS를 강제하는 형태로).

host replication streaming_replica all md5

externalClusters는 외부 PostgreSQL 원본에 접근하는 방법을 정의하는 섹션으로, 복제 정보(streaming connection)나 recovery용 object store 정보를 담는다. bootstrap의 source가 이 목록의 name을 참조한다.

애플리케이션 DB 설정과 제약

복제가 끝난 뒤(replica 클러스터가 아닌 경우) 애플리케이션 DB를 설정할 수 있다.

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
spec:
  bootstrap:
    pg_basebackup:
      database: app
      owner: app
      secret:
        name: app-secret
      source: cluster-example

복제 후 Operator는 app 데이터베이스와 유저가 없으면 만들고, 소유권을 부여하고, Secret의 비밀번호로 갱신한다.

pg_basebackup은 그 시점의 스냅샷을 뜨는 방식이다. 백업 중 생성된 WAL은 대상으로 streaming되지만, 완료 순간 대상은 새 timeline으로 갈라져 원본과 독립한다. 따라서 마이그레이션 목적이라면 대상으로 전환하기 전에 원본의 모든 쓰기를 멈춰야 한다(replica 클러스터에는 해당 없음). 실제 전환 전에 절차와 애플리케이션을 반드시 테스트해 다운타임을 측정한다.

정리

  • bootstrap 방식은 initdb·recovery·pg_basebackup 세 가지, 한 매니페스트에 하나만
  • initdb는 새 클러스터, recovery는 백업 복원, pg_basebackup은 라이브 물리 복제
  • postgres superuser·DB는 Operator 운영의 전제 — 삭제 금지
  • 자격 증명은 kubernetes.io/basic-auth Secret으로, usernameowner 또는 postgres와 일치
  • pg_basebackup은 동일 아키텍처·major 버전·tablespace가 전제이며, 전환 전 쓰기 중단과 테스트가 필수

다음 절(4.2)에서는 이미 운영 중인 기존 PostgreSQL을 논리 백업으로 가져오는 방법을 본다.