はじめに
以前、以下の記事で手順を出していましたが、表題について
汎用的に利用できると思い、切り出しました。
構成概要
追加ホスト
pg1 : PostgreSQL Primary + repmgr + keepalived
pg2 : PostgreSQL Standby + repmgr + keepalived
pg-vip : PostgreSQL 仮想IP(Keepalived制御)
Ubuntu24.04を使用する。
HA 方針
| コンポーネント | HA方式 |
|---|---|
| PostgreSQL | Streaming Replication |
| Primary 切替 | repmgrd |
| postgresql接続先 | VIP (Keepalived) |
前提 IP(例)
192.168.11.56 pg1
192.168.11.57 pg2
192.168.11.58 pg-vip
※適宜読み替えてください
1. PostgreSQL HA 構築
1-1. パッケージインストール(pg1 / pg2)
sudo apt update
sudo apt install -y postgresql postgresql-contrib repmgr keepalived
1-2. PostgreSQL Primary 初期設定(pg1)
ユーザー / DB 作成
sudo -u postgres psql << 'EOF'
-- ===== ロール作成 =====
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'repl') THEN
CREATE ROLE repl WITH REPLICATION LOGIN PASSWORD 'replpass';
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'repmgr') THEN
CREATE ROLE repmgr WITH LOGIN SUPERUSER PASSWORD 'repmgrpass';
END IF;
END
$$;
-- postgres パスワード設定
ALTER USER postgres PASSWORD 'postgrespass';
-- ===== DB 作成 =====
CREATE DATABASE repmgr OWNER repmgr;
-- ===== repmgr DB に接続 =====
\connect repmgr
-- repmgr 拡張
CREATE EXTENSION IF NOT EXISTS repmgr;
-- 確認
SELECT extname FROM pg_extension WHERE extname = 'repmgr';
\dt repmgr.*
EOFsudo -u postgres psql -d repmgr -c "\dt repmgr.*"
→repmgrがあること。
postgresql.conf
sudo tee -a /etc/postgresql/16/main/postgresql.conf << 'EOF'
listen_addresses = '*'
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
hot_standby = on
wal_keep_size = 1024MB
EOF
pg_hba.conf
sudo tee -a /etc/postgresql/16/main/pg_hba.conf << 'EOF'
# replication
host replication repl 192.168.11.57/32 md5
host replication repmgr 192.168.11.57/32 md5
# repmgr
host repmgr repmgr 192.168.11.56/32 md5
host repmgr repmgr 192.168.11.57/32 md5
# allow repmgr standby clone (postgres -> repmgr) from pg2
host repmgr postgres 192.168.11.57/32 scram-sha-256
EOF
設定の有効化
sudo systemctl restart postgresql
1-3. PostgreSQL Primary 初期設定(pg2)
postgresql.conf
sudo tee -a /etc/postgresql/16/main/postgresql.conf << 'EOF'
listen_addresses = '*'
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
hot_standby = on
wal_keep_size = 1024MB
EOF
pg_hba.conf
sudo tee -a /etc/postgresql/16/main/pg_hba.conf << 'EOF'
# replication
host replication repl 192.168.11.56/32 md5
host replication repmgr 192.168.11.56/32 md5
# repmgr
host repmgr repmgr 192.168.11.56/32 md5
host repmgr repmgr 192.168.11.57/32 md5
# allow repmgr standby clone (postgres -> repmgr) from pg2
host repmgr postgres 192.168.11.56/32 scram-sha-256
EOF
設定の有効化
sudo systemctl restart postgresql
1-4. repmgr 設定
1-4-1. pg1(Primary)
regmgr設定
sudo tee /etc/repmgr.conf << 'EOF'
node_id=1
node_name=pg1
conninfo='host=192.168.11.56 user=repmgr password=repmgrpass dbname=repmgr'
data_directory='/var/lib/postgresql/16/main'
use_replication_slots=yes
failover=automatic
promote_command='repmgr standby promote -f /etc/repmgr.conf'
follow_command='repmgr standby follow -f /etc/repmgr.conf'
ssh_options='-o StrictHostKeyChecking=accept-new'
service_start_command = 'sudo systemctl start postgresql'
service_stop_command = 'sudo systemctl stop postgresql'
service_restart_command = 'sudo systemctl restart postgresql'
service_reload_command = 'sudo systemctl reload postgresql'
EOF
regmgr登録(primary)
sudo -u postgres repmgr primary register -f /etc/repmgr.conf
ノード間認証設定
sudo -u postgres tee ~postgres/.pgpass > /dev/null <<'EOF'
pg2:5432:*:postgres:postgrespass
pg2:5432:*:repmgr:repmgrpass
pg2:5432:*:repl:replpass
192.168.11.57:5432:*:repmgr:repmgrpass
EOF
sudo -u postgres chmod 600 ~postgres/.pgpass
1-4-2. pg2(Standby)
regmgr設定
sudo tee /etc/repmgr.conf <<'EOF'
node_id=2
node_name=pg2
conninfo='host=192.168.11.57 user=repmgr password=repmgrpass dbname=repmgr connect_timeout=2'
data_directory='/var/lib/postgresql/16/main'
use_replication_slots=yes
monitoring_history=yes
failover=automatic
promote_command='repmgr standby promote -f /etc/repmgr.conf --log-to-file'
follow_command='repmgr standby follow -f /etc/repmgr.conf --log-to-file'
ssh_options='-o StrictHostKeyChecking=accept-new'
service_start_command = 'sudo systemctl start postgresql'
service_stop_command = 'sudo systemctl stop postgresql'
service_restart_command = 'sudo systemctl restart postgresql'
service_reload_command = 'sudo systemctl reload postgresql'
EOF
ノード間認証設定
sudo -u postgres tee ~postgres/.pgpass > /dev/null <<'EOF'
pg1:5432:*:postgres:postgrespass
pg1:5432:*:repmgr:repmgrpass
pg1:5432:*:repl:replpass
192.168.11.56:5432:*:repmgr:repmgrpass
EOF
sudo -u postgres chmod 600 ~postgres/.pgpass
ActiveからStandbyへのデータクローン
sudo systemctl stop postgresql
sudo -u postgres repmgr standby clone -h pg1 -d repmgr -f /etc/repmgr.conf --force
sudo systemctl start postgresql
regmgr登録(standby)
sudo -u postgres repmgr standby register -f /etc/repmgr.conf
1-5. repmgrdサービス作成(pg1/pg2)
sudo sed -i 's/^[# ]*shared_preload_libraries.*/shared_preload_libraries = '\''repmgr'\''/' /etc/postgresql/16/main/postgresql.conf
sudo systemctl restart postgresql
sudo tee /etc/systemd/system/repmgrd.service > /dev/null <<'EOF'
[Unit]
Description=repmgr daemon
After=network-online.target postgresql.service
Wants=network-online.target
[Service]
Type=simple
User=postgres
Group=postgres
Environment=PGPASSFILE=/var/lib/postgresql/.pgpass
ExecStart=/usr/bin/repmgrd -f /etc/repmgr.conf --daemonize=false
Restart=always
RestartSec=3
TimeoutStartSec=60
TimeoutStopSec=30
KillMode=process
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl disable repmgrd 2>/dev/null || true
sudo systemctl stop repmgrd 2>/dev/null || true
sudo systemctl enable --now repmgrd
確認
ps -ef | grep -E '[r]epmgrd'
→プロセスが見えること。
確認:
repmgr cluster show
以下の結果となること。
pg1 = Role:primary status: running
pg2 = Role:standby status: running
1-6. VIP 制御(Keepalived)
Primary 判定スクリプト(両ノード)
sudo tee /usr/local/bin/is_primary.sh << 'EOF'
#!/bin/bash
pg_isready -q || exit 1
sudo -u postgres psql -qtAX -c "select not pg_is_in_recovery();" | grep -q t
EOF
sudo chmod +x /usr/local/bin/is_primary.sh
sudo 許可:
sudo update-alternatives --config editor
→/usr/bin/vim.basicを選択する。
sudo visudo
以下を追記
keepalived ALL=(postgres) NOPASSWD: /usr/bin/psql
keepalived.conf(pg1)
sudo tee /etc/keepalived/keepalived.conf << 'EOF'
vrrp_script chk_primary {
script "/usr/local/bin/is_primary.sh"
interval 2
}
vrrp_instance VI_PG {
state MASTER
interface eth0
virtual_router_id 70
priority 200
authentication {
auth_type PASS
auth_pass HivePgVIP
}
virtual_ipaddress {
192.168.11.58/24
}
track_script {
chk_primary
}
}
EOF
keepalived.conf(pg2)
sudo tee /etc/keepalived/keepalived.conf << 'EOF'
vrrp_script chk_primary {
script "/usr/local/bin/is_primary.sh"
interval 2
}
vrrp_instance VI_PG {
state BACKUP
interface eth0
virtual_router_id 70
priority 150
authentication {
auth_type PASS
auth_pass HivePgVIP
}
virtual_ipaddress {
192.168.11.58/24
}
track_script {
chk_primary
}
}
EOF
keepalived起動(pg1/pg2)
sudo systemctl enable --now keepalived
確認(pg1で実施):
ip a
VIPがリストに出ること。
1-7 SSH鍵交換(pg1/pg2)
sudo -u postgres bash -lc 'test -f ~/.ssh/id_ed25519 || ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519'
sudo -u postgres cat /var/lib/postgresql/.ssh/id_ed25519.pub
それぞれの公開鍵を控える。
sudo -u postgres touch /var/lib/postgresql/.ssh/authorized_keys
sudo -u postgres chmod 600 /var/lib/postgresql/.ssh/authorized_keys
sudo -u postgres vi /var/lib/postgresql/.ssh/authorized_keys
1,2でそれぞれ交換で書き込む。
pg1:
sudo -u postgres ssh postgres@pg2 'hostname'
pg2:
sudo -u postgres ssh postgres@pg1 'hostname'
→yesを入力し、以下の回答が出てくること。
pg1実施:
pg2
pg2実施:
pg1
1-8. postgresユーザーのsystemctl実行許可設定(pg1/pg2)
sudo tee /etc/sudoers.d/repmgr-postgresql <<'EOF'
postgres ALL=NOPASSWD: /bin/systemctl start postgresql, /bin/systemctl stop postgresql, /bin/systemctl restart postgresql, /bin/systemctl reload postgresql
EOF
sudo chmod 440 /etc/sudoers.d/repmgr-postgresql
2. ユーザーDB構築
2.1. ユーザーDB作成
下記のDB名、DBユーザ名、パスワード、クライアントIPを環境に合わせ作成してください。
例:
DB名:hive_metastore
DBユーザー名:hive
パスワード:HivePasswordHere
クライアントIP:192.168.11.54,192.168.11.55
pg1で実施。
sudo -u postgres psql <<'SQL'
-- ===== Hive 用 role =====
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'hive') THEN
CREATE ROLE hive LOGIN PASSWORD 'HivePasswordHere';
END IF;
END $$;
CREATE DATABASE hive_metastore OWNER repmgr;
-- DB 接続
\connect hive_metastore
-- ===== 権限(必要十分)=====
-- DB 接続/一時テーブル
GRANT CONNECT, TEMP ON DATABASE hive_metastore TO hive;
-- public スキーマの所有者を hive に(Hive がテーブル作るため)
ALTER SCHEMA public OWNER TO hive;
GRANT USAGE, CREATE ON SCHEMA public TO hive;
-- 既存オブジェクトにも権限を揃える(再実行・移行時に効く)
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO hive;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO hive;
GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO hive;
-- 今後作られるオブジェクトのデフォルト権限も hive に
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO hive;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO hive;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON FUNCTIONS TO hive;
SQL
pg1/pg2で実施
sudo tee -a /etc/postgresql/16/main/pg_hba.conf << 'EOF'
# Hive Metastore via VIP
host hive_metastore repmgr 192.168.11.58/32 md5
# Hive Metastore (hive1/hive2) -> PostgreSQL via VIP
host hive_metastore hive 192.168.11.54/32 scram-sha-256
host hive_metastore hive 192.168.11.55/32 scram-sha-256
EOF
3. 動作確認
3-1. PostgreSQL フェールオーバ
目的:primary を pg1 → pg2 に自動的にフェールオーバーさせる。
障害注入方法:pg1のpostgresqlサービスを停止する。
期待する結果:自動的にpg2へ自動的にDBプライマリが切り替わり、外からの接続も実施できること。
pg1で実施:
sudo systemctl stop postgresql
pg2で実施:
repmgr cluster show
期待状態(数分後)
pg1 = Role:primary status: failed
pg2 = Role:primary status: running
VIP確認(pg2で実施):
ip a
VIPがリストに出ること。
確認:
再度beelineでの接続、zeppelinでのnotebook実行が行えること。
3-2. PostgreSQL フェイルバック
目的:primary を pg2 → pg1 に戻す
リスク:両系でプライマリになるとDBクラスタが壊れる。
→ 対策:pg1停止中にpg2からの再クローンを実施し、pg2のスタンバイ機として立ち上げる。
その後プライマリとスタンバイの切り替えを実施することによりリスク軽減を図る。
3-2-1. 新 Primary(pg2)から再クローン(pg1)
sudo -u postgres repmgr standby clone -h pg2 -d repmgr -f /etc/repmgr.conf --force
3-2-2. postgresql起動(pg1)
sudo systemctl start postgresql
3-2-3. pg1をStandby として登録(pg1)
sudo -u postgres repmgr standby register -f /etc/repmgr.conf --force
repmgr cluster show
以下の状態になること。
pg1 = Role:standby status: running
pg2 = Role:primary status: running
3-2-4. pg1へのactive切り戻し(pg1)
運用中の場合は夜間など使用する人のいないタイミングで対応すること。
- 切り戻し(手動フェールバック)
standbyとなっているホストで以下のコマンド実施
sudo -u postgres repmgr standby switchover \
-f /etc/repmgr.conf \
--siblings-follow
- postgresql HA確認
repmgr cluster show
以下の状態になること。
pg1 = Role:primary status: running
pg2 = Role:standby status: running
- VIP確認(pg1で実施):
ip a
VIPがリストに出ること。