0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

postgresクラスターを構築してみた。(repmgr)

0
Last updated at Posted at 2026-01-16

はじめに

以前、以下の記事で手順を出していましたが、表題について
汎用的に利用できると思い、切り出しました。

構成概要

追加ホスト

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がリストに出ること。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?