5.1 bootstrap과 initdb
Patroni를 시작한 노드의 데이터 디렉토리가 비어 있다면, 그 노드가 할 일은 둘 중 하나다. 클러스터의 첫 PostgreSQL 인스턴스를 새로 만들거나(bootstrap), 이미 있는 클러스터에서 데이터를 복사해 replica가 되거나. 어느 쪽인지는 노드가 스스로 정하지 않는다. DCS(Distributed Configuration Store)에 남은 흔적이 정한다.
initialize 키가 가르는 분기
판단 기준은 DCS의 initialize 키다.
- 키가 없으면 아직 아무도 이 클러스터를 초기화하지 않은 상태다. 노드들은 initialize lock을 놓고 경쟁하고, lock을 잡은 첫 번째 노드만 bootstrap을 실행한다.
- 키가 있으면 이미 초기화된 클러스터이므로 replica 생성 절차만 수행한다(5.3 replica 생성).
flowchart TD
START["빈 데이터 디렉토리"] --> KEY{"initialize 키 존재?"}
KEY -->|있음| REPLICA["replica 생성"]
KEY -->|없음| LOCK{"initialize lock 획득?"}
LOCK -->|실패| REPLICA
LOCK -->|성공| BOOT["bootstrap 실행<br/>initdb 또는 custom"]
BOOT -->|exit 0| DONE["PostgreSQL 구성<br/>/config 기록"]
BOOT -->|실패| CLEAN["정리 후 lock 해제"]
CLEAN --> KEY
실패 경로가 중요하다. bootstrap이 중간에 실패하거나 non-zero exit code를 반환하면 Patroni는 만들다 만 결과물을 정리하고 initialize lock을 해제해, 다른 노드가 다시 시도할 기회를 넘긴다.
기본 initdb bootstrap
bootstrap.method를 생략하거나 initdb로 지정하면, lock을 잡은 노드가 initdb를 실행해 클러스터를 만든다. initdb에 넘길 옵션은 bootstrap.initdb 아래에 list로 적는다.
bootstrap:
initdb:
- encoding: UTF8
- locale: UTF8
- data-checksumsdata-checksums처럼 값이 없는 플래그 옵션은 단독 항목으로 적는다. pg_rewind는 data checksums가 켜져 있거나 wal_log_hints가 on이어야 동작하므로, use_pg_rewind를 쓸 계획이라면 initdb 시점에 data-checksums를 켜 두는 편이 낫다. pg_rewind가 failover 후 구 primary 재합류에서 하는 역할은 Part VI에서 다룬다.
bootstrap.dcs는 최초 1회만 기록된다
bootstrap.dcs 아래 내용은 클러스터 초기화 직후 DCS의 /config 키에 기록되어 global dynamic configuration이 된다. 여기서 자주 걸리는 함정이 있다. 공식 문서는 “Patroni가 클러스터를 최초 한 번 초기화하고 설정이 DCS에 저장된 이후에는, YAML의 bootstrap.dcs 섹션을 아무리 고쳐도 효력이 없다"고 note로 명시한다. 초기화가 끝난 클러스터의 dynamic configuration은 patronictl edit-config 또는 REST API의 /config 엔드포인트로만 바꾼다. 구성 3계층의 전체 그림은 Part IV 참고.
post_bootstrap 스크립트
초기화 직후 한 번 실행할 스크립트를 bootstrap.post_bootstrap(또는 post_init)에 지정한다. 스크립트는 superuser 계정이 지정된 connection string URL을 인자로 받고, PGPASSFILE 환경변수가 pgpass 파일 위치로 설정된 채 실행된다. 애플리케이션 계정이나 database처럼 클러스터 생성 직후 한 번만 만들면 되는 객체를 준비하는 자리다.
bootstrap:
post_bootstrap: /usr/local/bin/post_bootstrap.sh#!/bin/bash
# $1 = superuser connection string, 비밀번호는 PGPASSFILE 경유로 전달된다
psql "$1" -c "CREATE DATABASE app"custom bootstrap method
initdb 대신 임의의 스크립트로 첫 인스턴스를 만들도록 바꿀 수도 있다. 백업에서 복원해 새 클러스터를 여는 PITR 시나리오가 대표적인 용도다. bootstrap.method에 이름을 적고, 같은 이름의 서브섹션에 계약을 채운다.
bootstrap:
method: pitr_restore
pitr_restore:
command: /usr/local/bin/restore_cluster.sh
keep_existing_recovery_conf: False
no_params: False
recovery_conf:
recovery_target_action: promote
recovery_target_timeline: latest
restore_command: cp /backup/wal/%f %p계약은 다음과 같다.
command는 절대 경로 또는 Patroni 명령 위치 기준 상대 경로다.- Patroni가 인자 두 개를 추가로 전달한다.
--scope(클러스터 이름)와--datadir(data directory 경로)다.no_params: True로 전달을 끈다. - 서브섹션에 적은 나머지 key: value는 전부
--name=value형식으로 command에 붙는다. - 스크립트가 exit code 0을 반환하면 Patroni는 그 결과물로 PostgreSQL을 구성하고 시작을 시도한다. 중간 단계가 실패하거나 non-zero를 반환하면 bootstrap 실패로 간주하고, 정리 후 initialize lock을 해제한다.
recovery_conf블록이 있으면 인스턴스 시작 전에 recovery 설정을 만든다. PostgreSQL 12 이상에서는 recovery.conf 파일 대신 설정 파라미터와 signal 파일 방식으로 처리된다. 보통recovery_target_*하나 이상과recovery_target_action: promote를 함께 둔다.keep_existing_recovery_conf: True면 기존 recovery.conf(PostgreSQL 11 이하) 또는 recovery.signal/standby.signal(PostgreSQL 12 이상)을 지우지 않고 recovery 설정도 덮어쓰지 않는다. pgBackRest처럼 recovery 설정을 스스로 만드는 도구와 함께 쓸 때 필요하다.
create_replica_methods가 목록을 순서대로 시도하는 것과 대비되는 지점으로, custom bootstrap이 계속 실패하면 클러스터는 노드들이 lock을 잡았다 놓기를 반복하며 초기화되지 못한 상태에 머문다.정리
- 빈 데이터 디렉토리의 노드는 DCS의
initialize키 유무에 따라 bootstrap과 replica 생성으로 갈리고, bootstrap은 lock을 잡은 첫 노드만 수행한다. - 기본 bootstrap은 initdb다. pg_rewind를 염두에 두면
data-checksums를 initdb 옵션에 넣어 둔다. bootstrap.dcs는 최초 1회만/config에 기록된다. 이후에는 patroni.yml을 고쳐도 무효이며patronictl edit-config로 바꾼다.- custom bootstrap은 exit 0 계약으로 성패를 알리고, 실패하면 lock을 해제해 다른 노드에 기회를 넘긴다. 체이닝과 fallback은 없다.