Patroni + etcd + HAProxy による自動 failover クラスタ
PostgreSQLレベル: 上級所要時間: 2~3 時間自動 failover 対応の PostgreSQL クラスタを構築・運用します。各ノードの PostgreSQL は Patroni が管理し、leader 選出は 3(または 5)メンバーの etcd で行われます。アプリケーションは HAProxy の書き込み(5000)・読み取り(5001)ポートに、必要に応じて keepalived の VIP 経由で接続します。構築に加え、稼働中クラスタ向けの運用シナリオがあります。ヘルスチェック、switchover、旧 leader の再参加、reinit、ノードの追加・削除、edit-config、pause、Patroni アップグレード、全停止・起動、etcd メンバー交換、etcd クォーラム喪失です。Patroni ノードでは pg-install ガイドは使いません(initdb は Patroni 自身が実行します)。Patroni を使わず failover を手動で行う HA には pg-streaming ガイドを使ってください。
構成: PostgreSQL + etcd ノード 3 台(共用または別)+ HAProxy(+ VIP)
シナリオ
- 構築: 新しい Patroni クラスタ — etcd + Patroni + HAProxy(+ VIP)クラスタをゼロから構築します。サーバーに PostgreSQL クラスタがあってはいけません。initdb は Patroni が実行します(pg-install は適用しません)。
- 運用 runbook: switchover、failover テスト、メンテナンスモード、パラメータ変更 — 構築直後のクラスタで基本操作を順に試します。状態確認、switchover、failover テスト(leader を停止するため短時間の書き込み停止あり)、メンテナンスモード、パラメータ変更です。メンテナンスウィンドウ内で実施してください。
- クラスタは正常か(ヘルスチェック) — 読み取り専用: ロール、遅延、タイムライン、REST API、etcd の健全性、スロット、保留中の再起動、メンテナンスモード。
- 計画 switchover(leader を別ノードへ移す) — メンテナンス前に leader ロールを制御された形でレプリカへ移します。数秒の書き込み停止があり、データ損失はありません。
- failover 後、旧 leader が再参加しない(pg_rewind / reinit) — クラッシュした旧 leader は起動するとレプリカとして参加するはずです。pg_rewind が失敗した場合は、データディレクトリを leader から再構築します。
- レプリカをゼロから再構築する(reinit) — レプリカが破損している、大きく遅れている、または WAL を失った場合です。データディレクトリを削除し、leader(またはバックアップ)から再構築します。leader には影響しません。
- クラスタに新しいノードを追加する — 新しいノードはフォームのリストの末尾に追加してください。ソフトウェアがインストールされ、既存ノードの pg_hba と HAProxy が更新され、レプリカとして参加します。
- クラスタからノードを削除する — レプリカであるノードを恒久的に削除します。Patroni を停止し、DCS の登録とスロットを削除し、HAProxy から外します。
- PostgreSQL または Patroni の設定を変更する(edit-config) — 設定は DCS に書き込まれ、全ノードに適用されます。再起動が必要な設定は restart --pending(レプリカから先に)。
- メンテナンスのため自動 failover を止める(pause / resume) — pause 中の Patroni は PostgreSQL に手を出さず、failover も行いません。ネットワーク・etcd のメンテナンスや手動作業に使います。作業が終わったら resume します。
- Patroni ソフトウェアをアップグレードする(rolling) — クラスタを pause にし、ノードごとに Patroni を更新して再起動します。PostgreSQL は停止せず、failover も起きません。
- クラスタ全体を停止 / 起動する(正しい順序) — 計画的な全停止(ストレージ、データセンターのメンテナンス): レプリカ、leader、最後に etcd の順に停止し、起動は逆順です。
- etcd メンバーを交換または追加する(etcdctl member) — 故障した etcd メンバーを外して新しいサーバーを追加します(またはメンバー数を増やします)。Patroni の etcd ホストリストも更新します。
- etcd のクォーラム喪失: leader が読み取り専用になった — etcd のクォーラムがないと Patroni は leader を読み取り専用にし、failover も行われません。etcd を復旧するか、1 メンバーから再構築します。
開始前の確認
- PostgreSQL ノードに稼働中または作成済みの PostgreSQL クラスタはなく、… は空です(クラスタは Patroni 自身が作成します)。これらのサーバーには pg-install ガイドを適用していません。
- すべてのサーバーが同じ OS リリースで最新化されており、時刻は NTP で同期されています(etcd と Patroni は時刻ずれに敏感です)。
- PostgreSQL ノードの RAM は … GB です。… は別ディスク/LV 上にあり、全ノードで同じサイズです。
- etcd のデータ(/var/lib/etcd)は低レイテンシのディスク(SSD)上にあります。遅いディスクは leader 選出を不安定にします。I/O の多い PostgreSQL データと同じディスクに置かないことを推奨します。
- 注意: etcd ノード数が …(偶数)です。偶数にしても耐障害性は上がりません。3 または 5 にしてください。
- サーバー同士が次のポートで通信できます: PostgreSQL …、Patroni REST 8008、etcd 2379/2380、HAProxy 5000/5001/7000…、VRRP(IP プロトコル 112)…。経路上のネットワーク機器でもこれらのルールが開いています。
- サーバーから PGDG リポジトリ(download.postgresql.org…、apt.postgresql.org…)と、etcd 用に github.com へ HTTPS で接続できるか、社内ミラーが設定されています。
- VIP … は空いており(どのサーバーでも使われていない)、ネットワーク(仮想化基盤/クラウド)が VRRP と同一 IP のサーバー間移動を許可しています。クラウド環境では多くの場合許可されないため、代わりにクラウドのロードバランサーを使ってください。
- 注意: VIP 用の HAProxy サーバーが 1 台しかありません。そのサーバーが停止すると VIP の移動先がありません。
- 全サーバーで root または sudo 権限があり、メンテナンスウィンドウと切り戻し計画が用意されています。
- …: 他のノードと同じ OS と PostgreSQL メジャーバージョンをインストールでき、… 用に他のノードと同等のディスクがあり、時刻は NTP で同期され、他のノードの …、8008、etcd 2379 へのアクセスが開いています。
- …(…): 低レイテンシのディスク(SSD)、NTP で同期した時刻、他の etcd メンバーからの 2379/2380 と PostgreSQL ノードからの 2379 へのアクセスが開いていること、github.com へのアクセスまたは /tmp に etcd アーカイブがあること。
ガイドのフェーズ
- 事前準備(全サーバー) — サーバー名を /etc/hosts に追加する · 時刻同期(chrony)を有効にする · カーネル設定と THP · ファイアウォールルール(PostgreSQL ノード) · ファイアウォールルール(etcd サーバー) · ファイアウォールルール(HAProxy サーバー)
- etcd クラスタ — etcd ソフトウェアをインストールする · etcd ソフトウェアをインストールする · etcd の設定: … · etcd の systemd サービスを作成する · etcd の systemd サービスを作成する · etcd を起動する(全 etcd ノードで同時に) …
- PostgreSQL と Patroni のソフトウェア — PGDG リポジトリを追加する · PGDG リポジトリを追加する · PostgreSQL と Patroni をインストールする · 単体の PostgreSQL サービスを無効にしてディレクトリを準備する
- Patroni の設定 — パスワードを環境ファイルに書き込む · Patroni サービスに環境ファイルを紐付ける · patroni.yml: … · 設定を検証する
- クラスタを起動する — 最初のノードで Patroni を起動する · 他のノードで Patroni を起動する: … · クラスタの状態を確認する
- HAProxy — HAProxy をインストールする · HAProxy をインストールする · haproxy.cfg を書き込む · haproxy.cfg を書き込む · HAProxy を検証して起動する · HAProxy を検証して起動する
- keepalived による VIP — keepalived をインストールする · keepalived をインストールする · keepalived の設定: … · keepalived を起動する · keepalived を起動する
- アプリケーションユーザーと接続テスト — アプリケーションユーザーとデータベース · アプリケーションユーザーのパスワードを設定する · REST API のヘルスチェックエンドポイントを確認する · HAProxy 経由で接続を試す · アプリケーションの接続文字列
- 構築後の作業 — etcd のスナップショットバックアップを取得する · etcd のスナップショットバックアップを取得する · バックアップを設定する(必須) · 監視に接続する
- クラスタの状態 — メンバー、ロール、遅延
- 計画 switchover — switchover を実行する
- failover テスト(leader を停止する) — leader ノードで Patroni を停止する · 新しい leader を監視する · 旧 leader を再起動する
- メンテナンスモード(pause) — クラスタをメンテナンスモードにする · メンテナンスを実施する · メンテナンスモードを解除する
- パラメータ変更 — クラスタ全体でパラメータを変更する · 保留中の再起動を適用する
- ヘルスチェック(読み取り専用) — メンバー、ロール、タイムライン、遅延 · 直近の leader 交代(history) · REST API のヘルスエンドポイント · etcd の健全性 · レプリケーション遅延、スロット、保留中の再起動(leader で) · 設定とメンテナンスモード
- 計画 switchover — switchover 前の確認 · switchover を実行する · 新しい leader と旧 leader の再参加を確認する
- メンテナンスモード(pause / resume) — pause 前の確認 · クラスタをメンテナンスモードにする(pause) · メンテナンスを実施する · メンテナンスモードを解除する(resume)
- Patroni アップグレード: 準備 — 現在と目標の Patroni バージョン · 設定をバックアップして検証する · クラスタをメンテナンスモードにする(pause)
- Patroni アップグレード: 完了 — メンテナンスモードを解除する(resume)
- クラスタを停止する(レプリカ → leader → etcd) — 状態とロールを記録する · アプリケーションを停止する · レプリカで Patroni を停止する · leader で Patroni を停止する · etcd を停止する
- クラスタを起動する(etcd → 最後の leader → レプリカ) — etcd を起動する(全 etcd メンバーで同時に) · etcd の健全性を確認する · 最後の leader で先に Patroni を起動する · レプリカで Patroni を起動する · クラスタを確認してアプリケーションを起動する
- 診断: etcd クォーラム喪失 — 症状を確認する: leader 不在、PostgreSQL が読み取り専用 · etcd メンバーの状態を確認する
- 手順 A: etcd メンバーを復旧する — 手順 A: etcd サービスを起動する · Patroni が回復したことを確認する
- 検証と再発防止 — etcd と Patroni を検証し、failsafe を検討する