この記事では、PG-REXの概要と構築手順について紹介します。
PG-REXとは
PG-REX (ピージーレックスと読む) はPacemakerによるPostgreSQLの高可用性ソリューションです。あくまでソリューションなので、PG-REXという名前のソフトはなく、マニュアルに従って構築、運用するシステムをPG-REXと呼びます。
PG-REXの構成要素
PG-REXの構成要素は以下です。
名前 | 開発元 | 入手先 | 説明 |
---|---|---|---|
PG-REX利用マニュアル | NTT OSSセンタ | 最新版はGitHub、古い版はOSDNミラー (IIJ、JAIST) | PG-REXの構築や運用などについて書かれたマニュアル |
PG-REX運用補助ツール | 同上 | 同上 | PG-REXの起動や停止、高速スイッチオーバなど、運用しやすくするツール |
Pacemaker | ClusterLabs | High Availabilityリポジトリ、RHELの場合はHigh Availability Add-Onが必要 | HAクラスタソフト、狭義にはクラスタリソースマネージャ、広義にはほかの関連ソフトを含めてそう呼ぶ |
Pacemaker追加パッケージ | Linux-HA Japan | 最新版はGitHub、古い版はOSDNミラー (IIJ、JAIST) | リソース定義生成ツール、PostgreSQL/HULFT用リソースエージェントを含む |
PostgreSQL | PostgreSQL Global Development Group | PostgreSQLリポジトリ | リレーショナルデータベース管理システム |
PG-REXのシステム構成
PG-REXの標準的なシステム構成は以下です。
PostgreSQLはプライマリ、スタンバイからなるレプリケーション構成です。プライマリは参照と更新、スタンバイは参照のみを受けつけます。プライマリで更新されたデータはスタンバイに複製されます。各ノードへの接続は仮想IPを通じて透過的に行われます。
Pacemakerはノード間で連携して、PostgreSQLや仮想IPなどのリソースを監視します。リソースの障害を検知すると別ノードに切り替えます。これをフェイルオーバと呼びます。ただ、ノード間の通信が途絶えると、相手ノードに障害が発生したと見なし、同じリソースを両ノードで起動して、スプリットブレンと呼ばれる競合状態になる可能性があります。
そうしたスプリットブレインを防ぐため、障害の発生したノードを強制的にクラスタから切り離します。これをフェンシングと呼び、とくにサーバ再起動、停止を伴うものをSTONITHと呼びます。STONITHはハードや仮想環境によっていろいろな方式があって、IPMIはハードで行う一般的な方式の1つです。
PG-REXとほかの構成との違い
PG-REXとほかのPacemakerによるPostgreSQLのHAクラスタ構成とのおもな違いは以下です。
- PG-REX独自ツールの使用が必要
- とくにリソース定義はMS Excelで環境定義書を編集して、独自ツールで変換、反映する必要があります。
- 同期レプリケーションのみに対応
- 非同期レプリケーションのほか、共有ディスクやDRBDにも対応していません。
- STONITHの設定が必要
- STONITHはIPMI以外の方式でも構いません。
- ノード間の通信経路が3本以上必要
- 少なくともサービス提供用、インターコネクト用、データ転送・インターコネクト兼用に分けて、インターコネクト用は冗長化する必要があります。
- 2ノードのみに対応
- ノード数が定足数 (クォーラム) を満たさず、スプリットブレイン時に多数決できません。
PG-REXの構築
PG-REXの構築手順はマニュアルに書いてあります。マニュアルはPG-REXの配布物に含まれていて、こちらからダウンロードできます。tar.gzファイル内のzipファイルに入っていて、日本語ファイル名のMS Word形式です。
-
pg-rex17-1.0-1.tar.gz
-
README.txt
-
PG-REX17-1.0.doc.zip
-
PG-REX17利用マニュアル_第1.0.0版(公開用利用者マニュアル).docx
-
PG-REX17環境定義書_第1.0版.xlsx
-
-
Net_OpenSSH-0.62-1.el9.x86_64.rpm
-
pg-rex_operation_tools_script-17.0-1.el9.noarch.rpm
-
Rocky Linux 9上でPacemaker 2.1、PostgreSQL 17、STONITHにIPMIを使って、PG-REXを構築する手順は以下です。IPMIは基本的にオンプレ環境でサーバにIPMI対応の制御チップが必要です。IPMIが使えなければ、ハードや仮想環境に応じた方式を設定する必要があります。
ちなみに、WSL2上のVirtualBoxでPG-REXを構築するAnsibleプレイブックをこちらで公開していて、そちらではVirtualBMCを使ってIPMI経由で仮想マシンを制御しています。
Pacemakerのインストール
-
Pacemakerをインストールします。pcsはPacemaker設定ツール、fence-agents-allはフェンスエージェントをまとめたパッケージです。
両ノードで実行# dnf -y --enablerepo=highavailability install pacemaker pcs fence-agents-all Rocky Linux 9 - High Availability 67 kB/s | 258 kB 00:03 メタデータの期限切れの最終確認: 0:00:02 前の 2025年04月20日 14時31分37秒 に実施しました。 依存関係が解決しました。 (省略) unbound-libs-1.16.2-8.el9_5.1.x86_64 完了しました!
-
pcsdを起動して、自動起動を有効化します。pcsdはpcsのコマンドを処理するデーモンです。
両ノードで実行# systemctl start pcsd # systemctl enable pcsd Created symlink /etc/systemd/system/multi-user.target.wants/pcsd.service → /usr/lib/systemd/system/pcsd.service.
-
haclusterユーザのパスワードを設定します。haclusterユーザはpcsdでノード間の認証に使うユーザです。パスワードは両ノードで同じにする必要があります。
いずれかのノードで実行# passwd hacluster Changing password for user hacluster. New password: (パスワードを入力) Retype new password: (パスワードを再入力) passwd: all authentication tokens updated successfully.
-
pcsdでノード間の認証を行います。各ノードのホスト名、運用管理用IPを指定します。最初にhaclusterユーザのユーザ名、パスワードを入力します。
両ノードで実行# pcs host auth node-1 addr=192.168.60.101 node-2 addr=192.168.60.102 Username: hacluster Password: (パスワードを入力) node-2: Authorized node-1: Authorized
-
Pacemakerの設定を行って、内部プロセスのクラッシュ時に再起動せず、即フェンシングするようにします。行頭の数字は行番号を表します。
両ノードで実行# vi /etc/sysconfig/pacemaker 179 PCMK_fail_fast="yes"
-
logindの設定を行って、フェンシングを高速化するため、電源ボタンによるサーバ停止処理を無効化し、設定を反映するため、logindを再起動します。
両ノードで実行# vi /etc/systemd/logind.conf 25 HandlePowerKey=ignore # systemctl restart systemd-logind
PostgreSQLのインストール
-
PostgreSQLリポジトリをインストールします。
両ノードで実行# dnf -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm メタデータの期限切れの最終確認: 0:06:43 前の 2025年04月20日 14時30分58秒 に実施しました。 pgdg-redhat-repo-latest.noarch.rpm 22 kB/s | 12 kB 00:00 依存関係が解決しました。 (省略) pgdg-redhat-repo-42.0-50PGDG.noarch 完了しました!
-
PostgreSQLをインストールします。
両ノードで実行# dnf -y install postgresql17-server postgresql17-contrib PostgreSQL common RPMs for RHEL / Rocky / AlmaL 1.2 kB/s | 659 B 00:00 PostgreSQL common RPMs for RHEL / Rocky / AlmaL 1.1 MB/s | 2.4 kB 00:00 GPG 鍵 0x08B40D20 をインポート中: (省略) postgresql17-server-17.4-1PGDG.rhel9.x86_64 完了しました!
-
PostgreSQLのデータディレクトリ、WALディレクトリ、アーカイブディレクトリを作成して、PostgreSQLのスーパーユーザpostgresのみ読み書き可能にします。
両ノードで実行# mkdir -p /dbfp/pgdata/data /dbfp/pgwal/pg_wal /dbfp/pgarch/arc1 # chown -R postgres:postgres /dbfp # chmod -R 700 /dbfp
-
postgresユーザに切り替わります。
両ノードで実行# su - postgres
-
postgresユーザの環境変数を設定して、設定を反映します。
両ノードで実行$ vi ~/.pgsql_profile export PATH=/usr/pgsql-17/bin:$PATH export MANPATH=/usr/pgsql-17/share/man:$MANPATH export PGDATA=/dbfp/pgdata/data $ . ~/.pgsql_profile
-
データベースクラスタを作成します。途中でデータベース上のpostgresユーザに設定するパスワードを入力します。
プライマリで実行$ initdb -E UTF8 -k --no-locale -W -X /dbfp/pgwal/pg_wal データベースシステム内のファイルの所有者はユーザー"postgres"となります。 このユーザーをサーバープロセスの所有者とする必要があります。 データベースクラスタはロケール"C"で初期化されます。 デフォルトのテキスト検索構成は english に設定されます。 データページのチェックサムは有効です。 新しいスーパーユーザーのパスワードを入力してください: (パスワードを入力) 再入力してください: (パスワードを再入力) ディレクトリ/dbfp/pgdata/dataの権限を設定しています ... ok ディレクトリ/dbfp/pgwal/pg_walの権限を設定しています ... ok サブディレクトリを作成しています ... ok 動的共有メモリの実装を選択しています ... posix デフォルトの"max_connections"を選択しています ... 100 デフォルトの"shared_buffers"を選択しています ... 128MB デフォルトの時間帯を選択しています ... Asia/Tokyo 設定ファイルを作成しています ... ok ブートストラップスクリプトを実行しています ... ok ブートストラップ後の初期化を実行しています ... ok データをディスクに同期しています ... ok initdb: 警告: ローカル接続に対して"trust"認証を有効にします initdb: ヒント: pg_hba.confを編集する、もしくは、次回initdbを実行する時に -A オプション、あるいは --auth-local および --auth-host オプションを使用することで変更できます。 成功しました。以下のようにしてデータベースサーバーを起動できます: pg_ctl -D /dbfp/pgdata/data -l ログファイル start
-
PostgreSQLの設定を行います。行頭の数字は行番号を表します。
プライマリで実行$ vi /dbfp/pgdata/data/postgresql.conf 60 listen_addresses = '*' 64 port = 5432 67 superuser_reserved_connections = 10 97 password_encryption = scram-sha-256 221 wal_level = replica 226 synchronous_commit = on 268 archive_mode = always 273 archive_command = '/bin/cp %p /dbfp/pgarch/arc1/%f' 329 max_wal_senders = 10 331 max_replication_slots = 10 333 wal_keep_size = 512MB 335 wal_sender_timeout = 20s 356 hot_standby = on 358 max_standby_archive_delay = -1 361 max_standby_streaming_delay = -1 368 hot_standby_feedback = on 370 wal_receiver_timeout = 20s 817 restart_after_crash = off
-
データベースサーバを一時的に起動して、レプリケーション接続用ユーザrepuserを作成し、パスワードを設定します。
プライマリで実行$ pg_ctl start サーバーの起動完了を待っています....2025-04-20 15:57:34.740 JST [41657] LOG: redirecting log output to logging collector process 2025-04-20 15:57:34.740 JST [41657] HINT: Future log output will appear in directory "log". 完了 サーバー起動完了 $ psql psql (17.4) "help"でヘルプを表示します。 postgres=# CREATE ROLE repuser LOGIN REPLICATION; CREATE ROLE postgres=# \password repuser ユーザー"repuser"の新しいパスワードを入力してください: (パスワードを入力) もう一度入力してください: (パスワードを再入力) postgres=# \q $ pg_ctl stop サーバー停止処理の完了を待っています....完了 サーバーは停止しました
-
クライアント認証の設定を行って、サービス提供用LANを通じたすべての接続と、データ転送用LANを通じたレプリケーション接続をパスワード認証で受けつけるようにします。
プライマリで実行$ vi /dbfp/pgdata/data/pg_hba.conf 127 host all all 192.168.56.0/24 scram-sha-256 128 host replication repuser 192.168.57.101/32 scram-sha-256 129 host replication repuser 192.168.57.102/32 scram-sha-256
-
パスワードファイルを作成して、データ転送用LANを通じたレプリケーション接続はパスワード不要にし、postgresユーザのみ読み書き可能にします。
両ノードで実行$ vi ~/.pgpass 192.168.57.111:5432:replication:repuser:reppasswd (ノード1の場合) 192.168.57.102:5432:replication:repuser:reppasswd (ノード2の場合) 192.168.57.101:5432:replication:repuser:reppasswd $ chmod 600 ~/.pgpass
-
rootユーザに戻ります。
両ノードで実行$ exit logout
IPMIの動作確認
-
IPMI用IPに接続して、電源の状態を取得できるか確認します。
いずれかのノードで実行# ipmitool -I lanplus -H 172.23.135.101 -U Administrator -P adminpasswd chassis power status Chassis Power is on # ipmitool -I lanplus -H 172.23.135.102 -U Administrator -P adminpasswd chassis power status Chassis Power is on
Pacemaker追加パッケージのインストール
-
Pacemaker追加パッケージをインストールします。
両ノードで実行# dnf -y install https://github.com/linux-ha-japan/pm_extra_tools/releases/download/pm_extra_tools-1.6/pm_extra_tools-1.6-1.el9.noarch.rpm メタデータの期限切れの最終確認: 3:01:32 前の 2025年04月20日 14時39分56秒 に実施しました。 pm_extra_tools-1.6-1.el9.noarch.rpm 87 kB/s | 150 kB 00:01 依存関係が解決しました。 (省略) pm_extra_tools-1.6-1.el9.noarch 完了しました!
PG-REX運用補助ツールのインストール
-
PG-REXの配布物に含まれるパッケージを両ノードに転送します。
-
パッケージをインストールします。ほかに運用補助ツールが内部的に使うlsof、perl-File-Compareもインストールします。
両ノードで実行# dnf -y install pg-rex_operation_tools_script-17.0-1.el9.noarch.rpm \ Net_OpenSSH-0.62-1.el9.x86_64.rpm lsof perl-File-Compare メタデータの期限切れの最終確認: 0:12:36 前の 2025年04月20日 20時35分45秒 に実施しました。 依存関係が解決しました。 ================================================================================ (省略) pg-rex_operation_tools_script-17.0-1.el9.noarch 完了しました!
-
運用補助ツールの設定を行います。D_LAN_IPAddressパラメータにはデータ転送用IPをカンマ区切りで、IC_LAN_IPAddressパラメータにはインターコネクト用IPを系統ごとにカッコで囲んでカンマ区切りで指定します。
両ノードで実行# vi /etc/pg-rex_tools.conf 1 D_LAN_IPAddress = 192.168.57.101,192.168.57.102 5 IC_LAN_IPAddress = (192.168.58.101,192.168.58.102),(192.168.59.101,192.168.59.102) 9 Archive_dir = /dbfp/pgarch/arc1 18 PGPATH = /usr/pgsql-17/bin 22 PEER_NODE_SSH_PASS_MODE = nopass 34 BACKUP_NODE_SSH_PASS_MODE = nopass
-
運用補助ツールは内部的にデータ転送LANを通じてSSH接続しますが、その際、接続するか聞かれて処理が止まらないように、接続先の公開鍵を取得して、登録します。
両ノードで実行(ノード1の場合) # ssh-keyscan 192.168.57.102 >> ~/.ssh/known_hosts (ノード2の場合) # ssh-keyscan 192.168.57.101 >> ~/.ssh/known_hosts
-
運用補助ツールの内部的なSSH接続時にパスワードを入力しないで済むように、rootユーザの秘密鍵と公開鍵を生成して、公開鍵を接続先に登録します。
両ノードで実行# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): (何も入力せず、Enterキーを入力) Enter passphrase (empty for no passphrase): (何も入力せず、Enterキーを入力) Enter same passphrase again: (何も入力せず、Enterキーを入力) Your identification has been saved in /root/.ssh/id_rsa Your public key has been saved in /root/.ssh/id_rsa.pub The key fingerprint is: SHA256:yK5kF+s79hzY83owMV6BpCSNpx15JY0O2daKRQuMZVA root@node-1 The key's randomart image is: +---[RSA 3072]----+ | oOE*+*. | | o+OoBo+ | | +.O.. . | | ..o.= . | | +.S+ | | . =+ | | o = +o | | o +o. +. | | ..o++o. | +----[SHA256]-----+ (ノード1の場合) # ssh-copy-id node-2 (ノード2の場合) # ssh-copy-id node-1 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub" The authenticity of host 'node-2 (192.168.56.102)' can't be established. ED25519 key fingerprint is SHA256:6ppZrEbtEpqZlR/l62uD+1gX2u1hxkEIRV8YbA82bWU. This host key is known by the following other names/addresses: ~/.ssh/known_hosts:3: 192.168.57.102 Are you sure you want to continue connecting (yes/no/[fingerprint])? yes /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys root@node-2's password: (パスワードを入力) Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'node-2'" and check to make sure that only the key(s) you wanted were added.
リソースの設定
-
PG-REXの配布物に含まれる環境定義書をMS Excelで編集して、CSV形式で保存し、プライマリに転送します。
記入例
- Primitiveリソース
- ipaddr-primary
- ip: 192.168.56.111 (プライマリ接続用仮想IP)
- nic: eth1
- cidr_netmask: 24
- ipaddr-replication
- ip: 192.168.57.111 (レプリケーション接続用仮想IP)
- nic: eth2
- cidr_netmask: 24
- ipaddr-standby
- ip: 192.168.56.112 (スタンバイ接続用仮想IP)
- nic: eth1
- cidr_netmask: 24
- pgsql
- pgctl: /usr/pgsql-17/bin/pg_ctl
- psql: /usr/pgsql-17/bin/psql
- pgdata: /dbfp/pgdata/data
- pgport: 5432
- node_list: node-1 node-2
- master_ip: 192.168.57.111 (レプリケーション接続用仮想IP)
- restore_command: /bin/cp /dbfp/pgarch/arc1/%f %p
- repuser: repuser
- ping
- host_list: 10.0.2.2 (デフォルトゲートウェイIP)
- ipaddr-primary
- STONITHリソース
- fence1-ipmilan
- pcmk_host_list: node-1
- ip: 172.23.135.101 (IPMI接続用IP)
- username: Administrator (IPMI接続用ユーザ名)
- password: adminpasswd (IPMI接続用パスワード)
- fence2-ipmilan
- pcmk_host_list: node-2
- ip: 172.23.135.102 (IPMI接続用IP)
- username: Administrator (IPMI接続用ユーザ名)
- password: adminpasswd (IPMI接続用パスワード)
- fence1-ipmilan
- リソース配置制約 (ノード)
- fence1-ipmilan
- avoids: node-1
- fence1-ipmilan
- avoids: node-2
- fence1-ipmilan
- Primitiveリソース
-
環境定義書をCIBと呼ばれるXML形式に変換します。
プライマリで実行# pm_pcsgen ./pm_pcsgen_env.csv pm_pcsgen_env.xml (CIB), pm_pcsgen_env.sh (PCS) を出力しました。
PG-REXの起動
-
プライマリを起動します。環境定義書から変換したXMLファイルを指定します。
プライマリで実行# pg-rex_primary_start ./pm_pcsgen_env.xml 1. Pacemaker および Corosync が停止していることを確認 ...[OK] 2. 稼働中の Primary が存在していないことを確認 ...[OK] 3. 起動禁止フラグの存在を確認 ...[OK] 4. HAクラスタ の作成 Destroying cluster on hosts: 'node-1', 'node-2'... node-1: Successfully destroyed cluster node-2: Successfully destroyed cluster Requesting remove 'pcsd settings' from 'node-1', 'node-2' node-1: successful removal of the file 'pcsd settings' node-2: successful removal of the file 'pcsd settings' Sending 'corosync authkey', 'pacemaker authkey' to 'node-1', 'node-2' node-1: successful distribution of the file 'corosync authkey' node-1: successful distribution of the file 'pacemaker authkey' node-2: successful distribution of the file 'corosync authkey' node-2: successful distribution of the file 'pacemaker authkey' Sending 'corosync.conf' to 'node-1', 'node-2' node-1: successful distribution of the file 'corosync.conf' node-2: successful distribution of the file 'corosync.conf' Cluster has been successfully set up. ...[OK] 5. Pacemaker 起動 Starting Cluster... Waiting for node(s) to start... Started ...[OK] 6. リソース定義 xml ファイルの反映 CIB updated ...[OK] Warning: If node(s) 'node-2' are not powered off or they do have access to shared resources, data corruption and/or cluster failure may occur Warning: If node 'node-2' is not powered off or it does have access to shared resources, data corruption and/or cluster failure may occur Quorum unblocked Waiting for nodes canceled 7. Primary の起動確認 ...[OK] ノード(node-1)が Primary として起動しました
-
スタンバイを起動します。途中でスタンバイの起動方法を聞かれるので、b (ベースバックアップを取得して起動) を入力します。
スタンバイで実行# pg-rex_standby_start 1. Pacemaker および Corosync が停止していることを確認 ...[OK] 2. 稼働中の Primary が存在していることを確認 ...[OK] 3. 起動禁止フラグが存在しないことを確認 ...[OK] 4. DB クラスタの状態を確認 4.1 現在のDBクラスタのまま起動が可能か確認 DB クラスタが存在していません ...[NG] 4.2 巻き戻しを実行することで起動が可能か確認 DB クラスタが存在していません ...[NG] 4.3 ベースバックアップを取得することが可能か確認 ...[OK] 以下の方法で起動が可能です b) ベースバックアップを取得してStandbyを起動 q) Standbyの起動を中止する 起動方法を選択してください(b/q) b 5. IC-LAN が接続されていることを確認 ...[OK] 6. Primary からベースバックアップ取得 NOTICE: all required WAL segments have been archived 23192/23192 kB (100%), 1/1 テーブル空間 ...[OK] 7. Primary のアーカイブディレクトリと同期 000000010000000000000002.partial 00000002.history 000000020000000000000003.00000028.backup 000000010000000000000001 000000020000000000000002 000000020000000000000003 ...[OK] 8. Standby の起動 (アーカイブリカバリ対象 WAL セグメント数: 1) Starting Cluster... ...[OK] 9. Standby の起動確認 ...[OK] ノード(node-2)が Standby として起動しました
-
クラスタが正常に稼働しているか確認します。
いずれかのノードで実行# pcs status Cluster name: pgrex_cluster Cluster Summary: * Stack: corosync (Pacemaker is running) * Current DC: node-1 (version 2.1.8-3.el9-3980678f0) - partition with quorum * Last updated: Sun Apr 20 23:08:51 2025 on node-1 * Last change: Sun Apr 20 23:08:25 2025 by root via root on node-1 * 2 nodes configured * 11 resource instances configured Node List: * Online: [ node-1 node-2 ] Full List of Resources: * Clone Set: pgsql-clone [pgsql] (promotable): * Promoted: [ node-1 ] * Unpromoted: [ node-2 ] * Resource Group: primary-group: * ipaddr-primary (ocf:heartbeat:IPaddr2): Started node-1 * ipaddr-replication (ocf:heartbeat:IPaddr2): Started node-1 * ipaddr-standby (ocf:heartbeat:IPaddr2): Started node-2 * Clone Set: ping-clone [ping]: * Started: [ node-1 node-2 ] * Clone Set: storage-mon-clone [storage-mon]: * Started: [ node-1 node-2 ] * fence1-ipmilan (stonith:fence_ipmilan): Started node-2 * fence2-ipmilan (stonith:fence_ipmilan): Started node-1 Daemon Status: corosync: active/disabled pacemaker: active/disabled pcsd: active/enabled
これで、PG-REXの構築は完了です。
終わりに
この記事では、PG-REXの概要と構築手順について紹介しました。PostgreSQLやPacemakerは使ったことがあっても、PG-REXはあまり知らなかった人もいると思いますが、この記事を通じてPG-REXもPacemakerによるPostgreSQLのHAクラスタ構成で、いくつか制限はあるものの、基本は同じだと知ってもらえるとよいです。
PG-REXにはほかにも高速スイッチオーバやアーカイブ削除の独自ツールがあって、マニュアルに運用や障害対応についても書いてあるので、今後、時間があればそちらも紹介したいと思います。