DockerをつかってCentOS7上でPostgreSQLの論理レプリケーションを試す

「実機サーバー1台しか開発環境ないけど、本番2台でいい感じに同期とる仕組みつくって」と言われたのでいろいろ試した中でのひとつ。
PostgreSQL童貞・Docker童貞からなんとか、動くところまで行ったのでその時に結果を記載
そんな状態なので間違ったこと書いていたらすみません。

# やりたいこと
本番相当を作りたいので

 - CentOS7
 - PostgreSQL10.3

を2台という形で作りたかった（PostgreSQLのサーバーだけでなく、普通にこのあと開発サーバーとしても使うのでこの構成）

# 事前の状態
もはや用意された実機で動かす必要もないので自前のIDCF Cloud（Ubuntu16.04）を利用

Dokcerの入れ方は公式をそのまま打っただけ
https://docs.docker.com/install/linux/docker-ce/ubuntu/

# Dockerのコンテナを作る
### マスタ側
何度もはまったところだが、CentOS7をDockerで作ると
systemd コマンド、serviceコマンドなどで

```bash
Failed to get D-Bus connection: Operation not permitted
```
が出て起動しないので、以下を参考に実施
https://blog.adachin.me/archives/3588

```bash
# つなぎやすいようにネットワークの設定を入れる
$ sudo docker network create --driver bridge psql
# privilegedと/sbin/initがキモ　今回の内容的には-pのポートフォワードは必要なかったっぽい
$ sudo docker run --privileged --name=postgresql1 --net=psql -d -p 5431:5432 -p 8000:80 centos /sbin/init
# bashで入ってみる
$ sudo docker exec -it postgresql1 /bin/bash
```

### スレーブ側
名前とポートフォワードの設定だけかぶらないようにする

```bash
$ sudo docker run --privileged --name=postgresql2 --net=psql -d -p 5433:5432 -p 8080:80 centos /sbin/init
```


# PostgreSQLサーバーの準備（M/S共通）

足りないコマンドを補いつつ下記を参考にというか、ほぼそのまま実行
https://weblabo.oscasierra.net/postgresql10-centos7-install/

```bash
# serviceコマンド等がなくて困るので
yum -y install initscripts && yum clean all
# wgetを入れる
yum -y install wget

wget https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/pgdg-centos10-10-2.noarch.rpm
yum -y localinstall pgdg-centos10-10-2.noarch.rpm
yum -y install postgresql10-server
/usr/pgsql-10/bin/postgresql-10-setup initdb
systemctl enable postgresql-10
systemctl start postgresql-10
```

# PostgreSQLサーバーが外から参照できるようにする（マスタのみ）
実際の作業では「つながらないじゃん」を繰り返して終盤にやった作業
https://qiita.com/YusukeHigaki/items/9bd0c21fbcc47e12b5c1

マスターとなるサーバー側だけで大丈夫です

```bash
vi /var/lib/pgsql/10/data/postgresql.conf
```
59行目～あたり。#を外して書き換える（試しなので全受け入れ）

```vim
listen_addresses = '*'                  # what IP address(es) to listen on;
                                        # comma-separated list of addresses;
                                        # defaults to 'localhost'; use '*' for all
port = 5432                             # (change requires restart)
```

さらに接続できるクライアントを設定する

```bash
vi /var/lib/pgsql/10/data/pg_hba.conf
```

一番最後の似たようなのが書いてあるあたりにテキトーに

```vim
host    all             all             all                     trust
```
こちらも試しなので全受け入れにしてますが、実際はADDRESS等を絞ったほうがいいと思います

再起動

```bash
service postgresql-10 restart
```

# PostgreSQLのユーザー等の設定（M/S共通）
適当にmydbというデータベースに、test_dbというテーブルを作ってそれをレプリケーションするようにします
testユーザーが実行できるようにします。レプリケーションができるユーザーにする必要があります。
権限はテストなので適当

```
# su postgres
$ createdb mydb
$ psql mydb
mydb=# CREATE TABLE test_db (
    id              SERIAL,
    name            varchar(80)
);
mydb=# CREATE ROLE test WITH LOGIN REPLICATION PASSWORD 'hogehoge';
mydb=# GRANT ALL ON test_db TO test;
```

# レプリケーションの設定
### マスタ側
論理レプリケーションをするにあたって、
http://tkrd.hatenablog.com/entry/2017/04/23/223936

```bash
vi /var/lib/pgsql/10/data/postgresql.conf
```

180行目あたり

```vim
wal_level = logical                     # minimal, replica, or logical
```
max_replication_slotsあたりも触るべき？（触らなくてもとりあえず動いた）


```
service postgresql-10 restart
```

```sql

$ psql mydb
mydb=# CREATE PUBLICATION pub_srv1_test_db FOR TABLE test_db;
```

### スレーブ側

別ホストとみなせるのでポートは5432でよい。

```
$ psql mydb
mydb=# CREATE SUBSCRIPTION sub_srv2_test_db CONNECTION 'dbname=mydb host=postgresql1 port=5432 user=test' PUBLICATION pub_srv1_test_db;
NOTICE:  created replication slot "sub_srv2_test_db" on publisher
CREATE SUBSCRIPTION
```

この時点で接続を試みるため、接続設定がうまくいっていないとここでこける。
~~~あれ、パスワード指定してないけど・・・。
このあたり釈然としないものがいまのところあるが、とりあえず動いたのでよしとする・・・（？~~~
さすがにアレなので調べたら、pg_hba.confのtrustが理由らしい
https://www.postgresql.jp/document/10/html/auth-pg-hba-conf.html


```
host    mydb            test            samenet             password
```
こうするとpasswordが必要になる（同じネットワーク内なのでまあ平文でよいでしょ）
またmydbデータベースのみのtestユーザーによる接続の許可もついでに入れた

```
mydb=# CREATE SUBSCRIPTION sub_srv2_test_db CONNECTION 'dbname=mydb host=postgresql1 port=5432 user=test' PUBLICATION pub_srv1_test_db;
ERROR:  could not connect to the publisher: fe_sendauth: no password supplied
mydb=# CREATE SUBSCRIPTION sub_srv2_test_db CONNECTION 'dbname=mydb host=postgresql1 port=5432 user=test password=hogehoge' PUBLICATION pub_srv1_test_db;
NOTICE:  created replication slot "sub_srv2_test_db" on publisher
CREATE SUBSCRIPTION
```


### 試してみる

マスタ側

```sql
mydb=# insert into test_db (name) values('aaa');
```

スレーブ側

```sql
mydb=# select * from test_db;
 id | name
----+------
  1 | aaa
(1 row)
```

なんか動いた。

### その他
マスタ側で以下を実行してもスレーブは変わらない

```
truncate test_db;
```

スレーブ側でinsertすると

```
mydb=# insert into test_db (name) values('aaa');
mydb=# select * from test_db;
 id | name
----+------
  1 | aaa
  1 | aaa
```

うーむ。まあスレーブ側は基本的には読み込みのみだからいいのだけど、id,nameともに値としてレプリケーションされるのね。
MySQLに慣れているのもあって、SERIALとsequenceテーブルの存在がなかなかにわかりにくい。

### 感想
PostgreSQL初めて触ったけど、古い情報が結構出てきて情報が調べにくいですね。。。
というか10のドキュメントに簡単に飛べないのどうなんよ・・・
https://www.postgresql.jp/document/