1サーバでPostgreSQLインスタンスを複数起動する方法

# はじめに

同じサーバのPostreSQLで複数インスタンスを同時に立ち上げて、アプリケーションの動作を簡単に確認する必要がありまして、備忘録としてまとめました。
今回は、簡単に環境を構築するために、PostgreSQL用アカウントを作成せず、自分のアカウントを使用して、PostgreSQLをソースコードからインストールします。

# 環境

OS は、Ubuntu 20.04 を使用しています。PostgreSQLのバージョンは現時点での最新である PostgreSQL 13.3 を使用します。

```bash
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
```

# 事前準備
PostgreSQLに必要なパッケージをインストールします。
```bash
$ sudo apt install libreadline-dev zlib1g-dev bison flex
```

PostgreSQLのインストールと実行に必要なディレクトリを作成します。src はソースコードの格納先、pgsql は PosthreSQLのインストール先、data はデータベースクラスタの格納先としています。

```bash
$ cd $HOME
$ mkdir src
$ mkdir pgsql
$ mkdir data
```

# PostgreSQLのインストール
PostgreSQLのソースコードのアーカイブファイルを入手して、アーカイブファイルを展開します。

```bash
$ cd src
$ wget https://ftp.postgresql.org/pub/source/v13.3/postgresql-13.3.tar.gz
$ tar xvzf postgresql-13.3.tar.gz
```

PostgreSQLをビルドします。configure の実行時に prefix オプションで PostgreSQL のインストール先を指定します。今回は、$HOME/pgsql/postgresql-13.3 です。

```bash
$ cd postgresql-13.3
$ ./configure --prefix=$HOME/pgsql/postgresql-13.3
$ make
$ make install
```

# データベースクラスタの作成
データベースクラスタを作成します。今回は 3つのクラスタ cluster1, cluster2, cluster3 を作成します。

```bash
$ cd $HOME/pgsql/postgresql-13.3/bin
$ ./initdb $HOME/data/cluster1
$ ./initdb $HOME/data/cluster2
$ ./initdb $HOME/data/cluster3
```

インスタンスを同時に立ち上げるために、それぞれ違うポート番号を設定します。cluster1 は PostgreSQL デフォルトのポート番号 5432 を使用して、cluster2 は 5433 に、cluster3 は 5434 にポート番号を変更します。

```bash
$ cd $HOME/data/cluster2
$ vi postgresql.conf
port = 5433
$ cd $HOME/data/cluster3
$ vi postgresql.conf
port = 5434
```

# PostgreSQLインスタンスの起動
pg_ctl コマンドで、それそれの PostgreSQL インスタンスを起動します。起動時にデータベースクラスタと、ログファイルを指定します。

```bash
$ cd $HOME/pgsql/postgresql-13.3/bin
$ ./pg_ctl -D $HOME/data/cluster1 -l $HOME/data/cluster1/postgres1.log start
$ ./pg_ctl -D $HOME/data/cluster2 -l $HOME/data/cluster2/postgres2.log start
$ ./pg_ctl -D $HOME/data/cluster3 -l $HOME/data/cluster3/postgres3.log start
```

# データベースとテーブルの作成
createdb コマンドで、それぞれのデータベースを作成します。

```bash
$ ./createdb -p 5432 postgresdb1
$ ./createdb -p 5433 postgresdb2
$ ./createdb -p 5434 postgresdb3
```

psqlコマンドで、それぞれのインスタンスに接続して、テーブル dbnmae を作成して、レコードを1行追加します。

```sql
$ ./psql -p 5432 postgresdb1
postgresdb1=# CREATE TABLE dbname(name text);
postgresdb1=# INSERT INTO dbname VALUES('postgres database1');
$ ./psql -p 5433 postgresdb2
postgresdb2=# CREATE TABLE dbname(name text);
postgresdb2=# INSERT INTO dbname VALUES('postgres database2');
$ ./psql -p 5434 postgresdb3
postgresdb3=# CREATE TABLE dbname(name text);
postgresdb3=# INSERT INTO dbname VALUES('postgres database3');
```

# PostgreSQLインスタンス起動確認
上記のpsqlでインスタンス起動は確認できていますが、同時に各インスタンスへアクセスできるか確認してみます。

```python:print_dbname.py
import psycopg2
# PostgreSQLインスタンス接続情報、実行SQL 
dsn1 = "dbname=postgresdb1 host=localhost"
dsn2 = "dbname=postgresdb2 host=localhost port=5433"
dsn3 = "dbname=postgresdb3 host=localhost port=5434"
sql = "SELECT * FROM dbname"
# PostgreSQLインスタンスと接続 
conn1 = psycopg2.connect(dsn1)
conn2 = psycopg2.connect(dsn2)
conn3 = psycopg2.connect(dsn3)
# カーソルの取得
cur1 = conn1.cursor()
cur2 = conn2.cursor()
cur3 = conn3.cursor()
# SQL実行
cur1.execute(sql)
cur2.execute(sql)
cur3.execute(sql)
# 取得結果を出力
print(cur1.fetchone())
print(cur2.fetchone())
print(cur3.fetchone())
# カーソルを閉じる
cur1.close()
cur2.close()
cur3.close()
# PostgreSQLインスタンスとの接続を切断
conn1.close()
conn2.close()
conn3.close()
```
上記 pythonプログラムを実行すると、以下のように各インスタンスのテーブルに格納されているレコードを表示されます。

```bash
$ python3 print_dbname.py 
('postgres database1',)
('postgres database2',)
('postgres database3',)
```
下図のようなイメージになります。

![PostgreSQL_multi_instance.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308856/16536f26-8722-6f30-9bdc-b7a4071e09fc.png)

python3、psycopg2がインストールされていなく、上記プログラムが実行できない場合、以下のコマンドでインストールをお願いします。

```bash
$ sudo apt install python3
$ sudo apt install python3-pip
$ pip install psycopg2-binary
```

# PostgreSQLインスタンスの終了
pg_ctl コマンドで、それそれの PostgreSQL インスタンスを終了させます。

```bash
$ cd $HOME/pgsql/postgresql-13.3/bin
$ ./pg_ctl -D $HOME/data/cluster1 stop
$ ./pg_ctl -D $HOME/data/cluster2 stop
$ ./pg_ctl -D $HOME/data/cluster3 stop
```

# まとめ
ポート番号を変更することで、同じサーバのPostreSQLで複数インスタンスを同時に立ち上げました。自分のアカウントで簡単にPostgreSQLの複数インスタンスを確認することができました。

もし、記述について誤りがあったり、気になることがあれば、編集リクエストやコメントでフィードバックしていただけると助かります。

# 参照

以下の情報を参考にさせて頂きました。

- [データベースクラスタ作成手順【複数作成する場合で解説】【PostgreSQL】](https://kohei.life/postgresql-create-culuster/)