본문으로 건너뛰기
10.2 메이저 업그레이드

10.2 메이저 업그레이드

patronictl에는 메이저 업그레이드 명령이 없다. pg_upgrade 실행은 Patroni 바깥의 작업이고, Patroni 쪽에는 업그레이드된 데이터 디렉토리를 새 클러스터로 다시 인식시키는 절차가 따라붙는다. pg_upgrade가 새 데이터 디렉토리를 initdb로 만들면서 PostgreSQL의 system identifier가 바뀌기 때문에, DCS에 남은 구 클러스터 상태를 지우지 않으면 Patroni가 보는 클러스터와 실제 데이터가 어긋난다.

전체 흐름

    flowchart TD
  A["전 노드 Patroni 정지"] --> B["primary에서 pg_upgrade"]
  B --> C["patroni.yml 수정"]
  C --> D["DCS initialize key 제거"]
  D --> E["dynamic config 복원"]
  E --> F["primary Patroni 시작"]
  F --> G["standby 데이터 비우기"]
  G --> H["standby Patroni 시작<br/>재복제 대기"]
  

절차 전체가 클러스터 정지를 전제로 한다. Patroni를 멈추는 시점부터 primary가 새 버전으로 서비스를 다시 시작할 때까지 쓰기가 중단되므로, pg_upgrade 소요 시간을 사전에 측정해 다운타임 창을 잡아야 한다.

Patroni 정지

전 노드에서 Patroni를 정지한다. 작업 도중 leader race나 자동 failover가 일어나지 않게 하기 위해서다.

primary에서 pg_upgrade

primary 노드에 새 버전 PostgreSQL 바이너리를 설치하고 pg_upgrade를 실행한다.

patroni.yml 수정

새 버전에 맞게 patroni.yml을 수정한다. 바이너리 경로(bin_dir)나 데이터 디렉토리 경로처럼 버전 번호가 들어간 값이 주 대상이다.

DCS 상태 제거

DCS에서 initialize key를 제거하거나, patronictl remove로 클러스터 상태 전체를 지운다.

dynamic configuration 복원

구 데이터 디렉토리의 patroni.dynamic.json을 새 데이터 디렉토리로 복사해 둔다. 클러스터를 다시 초기화할 때 기존 dynamic configuration이 유지된다. 선택 단계다.

primary에서 Patroni 시작

primary에서 Patroni를 시작한다. initialize key가 없으므로 Patroni는 이 노드의 데이터 디렉토리를 기준으로 클러스터를 새로 초기화한다.

standby 재구축

standby의 구 데이터 디렉토리는 비우고 재복제한다. 공식 문서는 “Running pg_upgrade on standby nodes is not supported by PostgreSQL"라고 명시한다. standby에 새 버전 바이너리를 설치하고 데이터 디렉토리를 비운 뒤 Patroni를 시작하면, replica 생성 경로(기본 pg_basebackup)로 다시 만들어진다.

복제 완료 대기

standby가 primary를 따라잡을 때까지 기다린다. patronictl list로 각 노드의 state를 확인한다.

가장 잦은 실수는 initialize key를 지우지 않고 primary에서 Patroni를 시작하는 것이다. pg_upgrade가 initdb로 새 system identifier를 만들기 때문에, DCS에 남은 구 클러스터 상태와 새 데이터 디렉토리는 더 이상 일치하지 않는다. 새로 시작하기 전에 initialize key 제거 또는 patronictl remove로 DCS 상태를 반드시 초기화한다.
pause 문서는 유지보수 모드의 용례로 major version upgrade를 든다. 다만 위의 공식 절차는 pause가 아니라 Patroni 정지를 기반으로 한다. pause는 PostgreSQL을 살려 둔 채 Patroni의 관리만 멈추는 모드라서, 클러스터를 내리고 다시 세우는 이 절차와는 쓰임이 다르다.

Kubernetes에서는: Spilo의 in-place upgrade

Kubernetes 환경이라면 Zalando Spilo 이미지의 inplace_upgrade.py가 참고 구현이다. Spilo 13 이상 이미지에 포함되어 있고, master pod 안에서 다음처럼 실행한다.

python3 /scripts/inplace_upgrade.py N   # N = 클러스터 멤버 수

Zalando postgres-operator를 쓰면 major_version_upgrade_mode 설정(기본 off, manual, full)으로 이 스크립트의 트리거를 제어한다. 대상 버전은 PGVERSION 환경변수 기반이다.

정리

메이저 업그레이드에서 Patroni가 대신해 주는 것은 없다. pg_upgrade와 바이너리 교체는 바깥에서 실행하고, DCS의 initialize key를 지워 새 system identifier의 클러스터로 다시 세우는 것이 절차의 뼈대다. standby는 pg_upgrade 대상이 아니므로 데이터 디렉토리를 비운 뒤 재복제로 맞춘다.