オンプレとCloud Native PostgreSQLのレプリケーション検証

はじめに

説明

Cloud Native PostgreSQL(CNP)とはEDB社の提供しているPostgreSQLのKubernates Operatorになります。

Kubernates Operatorを初耳の方も多いと思いますが、一言で申しますとクラスタ管理・構築ツールになります。

今回はオンプレのPostgreSQLから同じオンプレのminikube(kvm2)上のCloud Native PostgreSQLのレプリケーションを行います。

構築所要時間

30分程度を想定しております

前提やトラブルシュート

CNPの構築は初回の記事を参考にして下さい。

レプリケーションがうまく行かない場合、前回の記事でまずオンプレ同士で構築することを推奨します。

CNPのパラメータ制約

CNPのパラメータには一部制限がございます。

このためストリーミングレプリケーションのスタンバイになることは難しそうです。
ロジカルレプリケーションのサブスクリプションには執筆時点では支障がございません。

wal_level
wal_log_hints
synchronous_standby_names
hot_standby
primary_conninfo
restore_command

パブリケーションの設定

パラメータ確認

パブリケーションの設定を確認します。
こちらは普通に作成下さい。
クライアント認証で接続可能か、wal_levelがlogicalかを確認します。
他のパラメーターはデフォルトであれば動作するはずですが必要に応じて確認ください。

$ cat /var/lib/pgsql/*/data/pg_hba.conf 
$ psql
psql# show wal_level;
 wal_level 
-----------
 logical

パブリケーション設定

パブリケーションを作成します。

psql# CREATE ROLE replica WITH ENCRYPTED PASSWORD 'password' LOGIN REPLICATION;
psql# create database app;
psql# \c app
psql# create table japan ( id serial primary key, pref text, city text );
psql# CREATE PUBLICATION "logical_pub" FOR TABLE japan;
psql# \dRp
    名前     |  所有者  | 全テーブル | Insert文 | Update文 | Delete文 
-------------+----------+------------+----------+----------+----------
 logical_pub | postgres | f          | t        | t        | t
psql # SELECT * FROM pg_publication_tables;
   pubname   | schemaname | tablename 
-------------+------------+-----------
 logical_pub | public     | japan

第一弾のデータを流し込みます。

psql# INSERT INTO japan
  ( pref , city ) 
VALUES
  ( '東京都', '八王子市' ),
  ( '東京都', '立川市' ),
  ( '東京都', '武蔵野市' ),
  ( '東京都', '三鷹市' ),
  ( '東京都', '青梅市' ),
  ( '東京都', '府中市' ),
  ( '東京都', '昭島市' ),
  ( '東京都', '調布市' ),
  ( '東京都', '小金井市' ),
  ( '東京都', '小平市' ),
  ( '東京都', '日野市' ),
  ( '東京都', '東村山市' ),
  ( '東京都', '国分寺市' ),
  ( '東京都', '国立市' ),
  ( '東京都', '福生市' ),
  ( '東京都', '狛江市' ),
  ( '東京都', '東大和市' ),
  ( '東京都', '清瀬市' ),
  ( '東京都', '東久留米市' ),
  ( '東京都', '武蔵村山市' ),
  ( '東京都', '多摩市' ),
  ( '東京都', '稲城市' ),
  ( '東京都', '羽村市' ),
  ( '東京都', 'あきる野市' ),
  ( '東京都', '西東京都市' );
psql# select * from japan;
\q
$ exit

サブスクリプションの設定

CNPのプライマリを確認します。
pingするとわかりますがPodにpingは通りません。

$ kubectl cnp status クラスタ名
kubectl cnp status cluster-example
Pod name           Current LSN  Received LSN  Replay LSN  System ID            Primary  Replicating  Replay paused  Pending restart  Status
--------           -----------  ------------  ----------  ---------            -------  -----------  -------------  ---------------  ------
cluster-example-1  0/E000000                              6976160584607547411  ✓        ✗            ✗              ✗                OK
cluster-example-2               0/E000000     0/E000000   6976160584607547411  ✗        ✓            ✗              ✗                OK
cluster-example-3               0/E000000     0/E000000   6976160584607547411  ✗        ✓            ✗              ✗                OK
$ kubectl get pod プライマリPod -o wide | tail -n1 | awk {'print $6'} | xargs ping
kubectl get pod cluster-example-1 -o wide | tail -n1 | awk {'print $6'} | xargs ping
PING 172.17.0.4 (172.17.0.4) 56(84) bytes of data.

プライマリpodにログインしてサブスクリプションを設定します。

$ kubectl exec -it プライマリPod -- /bin/bash
kubectl exec -it cluster-example-1 -- /bin/bash
$ psql -U replica -h パブリケーションIP postgres
psql -U replica -h 192.168.1.99 postgres
psql# \q
$ psql
psql# create table japan ( id serial primary key, pref text, city text );
psql# CREATE SUBSCRIPTION "logical_sub2" CONNECTION 'hostaddr=パブリケーションIP port=5432 dbname=app user=replica' publication "logical_pub";
CREATE SUBSCRIPTION "logical_sub2" CONNECTION 'hostaddr=192.168.1.99 port=5432 dbname=app user=replica' publication "logical_pub";
psql# SELECT * FROM pg_subscription;
  oid  | subdbid |   subname    | subowner | subenabled |                         subconninfo                          | subslotname  | subsynccommit | subpublications 
-------+---------+--------------+----------+------------+--------------------------------------------------------------+--------------+---------------+-----------------
 24594 |   13434 | logical_sub2 |       10 | t          | hostaddr=192.168.1.99 port=5432 dbname=postgres user=replica | logical_sub2 | off           | {logical_pub}
psql# select * from japan;

筆者もびっくりしたのですがレプリケーションが構築できました。

テーブルの内容が同期されているはずです。

動作確認

通信先の確認

パブリケーションを確認するとnodeではなくKVMホストに対してセッションを張ってます。

$ ss -natp | grep 5432
LISTEN 0      128     192.168.1.99:5432         0.0.0.0:*                                      
ESTAB  0      0       192.168.1.99:5432  192.168.122.15:52946

$ kubectl get node -o wide
NAME       STATUS   ROLES                  AGE   VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE               KERNEL-VERSION   CONTAINER-RUNTIME
minikube   Ready    control-plane,master   19h   v1.20.7   192.168.39.33   <none>        Buildroot 2020.02.12   4.19.182         docker://20.10.6

$ sudo virsh net-dhcp-leases default
 Expiry Time           MAC アドレス        Protocol   IP address          Hostname   Client ID or DUID
-----------------------------------------------------------------------------------------------------------
 2021-06-22 13:07:27   52:54:00:ba:8f:a4   ipv4       192.168.122.15/24   minikube   01:52:54:00:ba:8f:a4

INSERT,UPDATE,DELETEの確認

パブリケーションでinsert,update,deleteを行います

$ psql
psql# \c app
psql# INSERT INTO japan
  ( pref , city ) 
VALUES
  ( '神奈川県', '横浜市' ),
  ( '神奈川県', '川崎市' ),
  ( '神奈川県', '相模原市' ),
  ( '神奈川県', '町田市' ),
  ( '神奈川県', '横須賀市' ),
  ( '神奈川県', '平塚市' ),
  ( '神奈川県', '鎌倉市' ),
  ( '神奈川県', '藤沢市' ),
  ( '神奈川県', '小田原市' ),
  ( '神奈川県', '茅ヶ崎市' ),
  ( '神奈川県', '伊豆市' ),
  ( '神奈川県', '三浦市' ),
  ( '神奈川県', '秦野市' ),
  ( '神奈川県', '厚木市' ),
  ( '神奈川県', '大和市' ),
  ( '神奈川県', '伊勢原市' ),
  ( '神奈川県', '海老名市' ),
  ( '神奈川県', '座間市' ),
  ( '神奈川県', '南足柄市' ),
  ( '神奈川県', '綾瀬市' );
psql# UPDATE japan SET  pref = '東京都' where city = '町田市';
psql# DELETE FROM japan WHERE pref = '神奈川県';

レプリケーティングPodでデータを確認します。

insert,update,deleteの結果、東京26市が残るはずです。

$ kubectl exec -it レプリケーティングPod -- /bin/bash
kubectl exec -it cluster-example-2 -- /bin/bash
psql# select * from japan;

あとがき

オンプレからPodにpingを行えない厳しい環境でレプリケーションが構築できましたので
多くの環境でレプリケーション構築が期待できそうです。
なお、マニュアルに記載がございませんので利用になる際はサポート対象か確認をお願いします。

ここまでお読みいただき、ありがとうございました!