PostgreSQL を Red Hat 系 Linux にインストールするには

PostgreSQL を Red Hat Enterprise Linux (以下、RHEL) や Rocky Linux、AlmaLinux などの Red Hat 系 Linux にインストールする手順について少し詳しく説明します。Windows へのインストールについては [こちらの記事](https://qiita.com/tom-sato/items/037b8f8cb4b326710f71) を参照してください。

説明は基本的に PostgreSQL 16、RHEL 9 を対象にしますが、バージョンによって異なる部分はなるべく補足します。

# PostgreSQL のインストール

PostgreSQL のインストール方法はいくつかあります。おもな方法は以下のとおりです。

* ソースコードからビルド
* OS 標準の Yum リポジトリを使う
* PostgreSQL 開発元の Yum リポジトリを使う

ソースコードからビルドする方法は、最新バージョンを使えますが、最初にビルド環境を整えたり、バージョンアップのたびにビルドしたりするのに手間がかかります。

OS 標準の Yum リポジトリを使う方法は、すぐにインストールできて、手間がかかりませんが、最新バージョンを使えません。

ここでは、最初に Yum リポジトリを追加するだけで、あまり手間がかからず、最新バージョンを使える方法として、PostgreSQL 開発元の Yum リポジトリを使ってインストールします。

## PostgreSQL 開発元 Yum リポジトリの追加

PostgreSQL 開発元の Yum リポジトリを使うには、リポジトリパッケージをインストールし、Yum リポジトリを追加します。リポジトリパッケージは以下のページからダウンロードできます。

**Repo RPMs - PostgreSQL YUM Repository**
https://yum.postgresql.org/repopackages.php

上記のページで OS に応じたリポジトリパッケージをダウンロードします。

ここでは、RHEL 9 (x86_64) にインストールするので、「Red Hat Enterprise Linux 9 - x86_64」の URL をコピーします。

コピーした URL を引数に指定し、リポジトリパッケージをインストールします。

```shell-session
$ sudo dnf -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
(省略)
インストール済み:
  pgdg-redhat-repo-42.0-38PGDG.noarch

完了しました!
```

OS 標準の `postgresql` モジュールが優先されないように無効化します。

```shell-session
$ sudo dnf -y module disable postgresql
(省略)
完了しました!
```

RHEL 7 では、`dnf` コマンドの代わりに `yum` コマンドを使います。`postgresql` モジュールの無効化は不要です。

これで、PostgreSQL とその関連ソフトウェアのパッケージをインストールできるようになります。

## PostgreSQL パッケージのインストール

PostgreSQL のパッケージは以下のサブパッケージからなります。

| パッケージ名             | 説明                             |
|--------------------------|----------------------------------|
| `postgresql16`           | クライアントプログラム           |
| `postgresql16-libs`      | 共有ライブラリ                   |
| `postgresql16-server`    | サーバプログラム                 |
| `postgresql16-docs`      | マニュアル                       |
| `postgresql16-contrib`   | 追加モジュール                   |
| `postgresql16-devel`     | 開発用ヘッダファイルとライブラリ |
| `postgresql16-llvmjit`   | JIT コンパイル対応               |
| `postgresql16-plperl`    | PL/Perl (Perl 手続き言語)        |
| `postgresql16-plpython3` | PL/Python (Python 3 手続き言語)  |
| `postgresql16-pltcl`     | PL/Tcl (Tcl 手続き言語)          |
| `postgresql16-test`      | テストツール                     |

PostgreSQL をサーバとして使うには、`postgresql16-server` パッケージをインストールします。

```shell-session
$ sudo dnf -y install postgresql16-server
(省略)
インストール済み:
  lz4-1.9.3-5.el9.x86_64
  postgresql16-16.1-2PGDG.rhel9.x86_64
  postgresql16-libs-16.1-2PGDG.rhel9.x86_64
  postgresql16-server-16.1-2PGDG.rhel9.x86_64

完了しました!
```

RHEL 7 では、`dnf` コマンドの代わりに `yum` コマンドを使います。

`postgresql16-server` パッケージをインストールすると、依存関係で `postgresql16`、`postgresql16-libs`、`lz4` の 3 つのパッケージがインストールされます。`lz4` パッケージはバージョン 14 で追加の LZ4 圧縮に必要なライブラリです。

PostgreSQL のインストール先はバージョンごとに異なります。バージョン 16 であれば `/usr/pgsql-16` になります。同じ環境に複数のバージョンをインストールすることもできます。

```shell-session
$ ls /usr/pgsql-16
bin  lib  share
```

また、`postgresql16-server` パッケージのインストール時に PostgreSQL のスーパーユーザ `postgres` が存在しなければ、作成されます。

```shell-session
$ id postgres
uid=26(postgres) gid=26(postgres) groups=26(postgres)
```

# データベースクラスタの作成

データベースクラスタとはデータベースを格納する領域のことです。データベースサーバの起動にはデータベースクラスタが必要です。

データベースクラスタの作成は `initdb` コマンドで行います。OS に付属のスクリプト `postgresql-16-setup` でもできますが、認証方式が固定で指定できず、わざわざ使うメリットはほとんどないでしょう。

データベースクラスタの作成先は環境変数 `PGDATA` または `-D` オプションで指定します。デフォルトは `/var/lib/pgsql/16/data` で、`postgres` ユーザの設定ファイル `~/.bash_profile` で環境変数 `PGDATA` に指定されています。ただ、このファイルは [後述の理由](#postgresql-スーパーユーザの環境変数設定) により直接編集すべきでないため、データベースクラスタの場所を変更する場合には `-D` オプションを使ったほうがいいでしょう。

そのほかに指定するオプションとして、ここでは、`-E UTF8` オプションでデータベース作成時のデフォルトのエンコーディングに `UTF8`、`--locale=C` オプションで同じくデフォルトのロケールに `C` (ロケールなし)、`-A scram-sha-256` オプションで認証方式に `scram-sha-256` (SCRAM-SHA-256 暗号化によるパスワード認証)、`-W` オプションでパスワード設定の入力プロンプトを表示するように指定します。

ロケールは言語や国によって異なる文字の扱いや並び替え順を指定するものです。日本語ではロケールを使う必要があまりなく、ロケールを使うと文字の処理が遅くなり、インデックスの作成時にオプションを指定しないと、`LIKE` でインデックスも使えなくなるので、ロケールを使わないようにします。

`initdb` コマンドは `postgres` ユーザで実行する必要があるため、`su` コマンドでユーザを切り替えて実行します。途中でパスワード設定の入力プロンプトが表示されるので、同じパスワードを繰り返し二回入力します。実行が完了したら、`exit` コマンドで元のユーザに戻ります。

```shell-session
$ sudo su - postgres
$ /usr/pgsql-16/bin/initdb -E UTF8 --locale=C -A scram-sha-256 -W
データベースシステム内のファイルの所有者はユーザー"postgres"となります。
このユーザーをサーバープロセスの所有者とする必要があります。

データベースクラスタはロケール"C"で初期化されます。
デフォルトのテキスト検索構成は english に設定されます。

データベージのチェックサムは無効です。

新しいスーパーユーザーのパスワードを入力してください: (パスワードを入力)
再入力してください: (パスワードを再入力)

ディレクトリ/var/lib/pgsql/16/dataの権限を設定しています ... ok
サブディレクトリを作成しています ... ok
動的共有メモリの実装を選択しています ... posix
デフォルトのmax_connectionsを選択しています ... 100
デフォルトのshared_buffersを選択しています ... 128MB
デフォルトの時間帯を選択しています ... Asia/Tokyo
設定ファイルを作成しています ... ok
ブートストラップスクリプトを実行しています ... ok
ブートストラップ後の初期化を実行しています ... ok
データをディスクに同期しています ... ok

成功しました。以下のようにしてデータベースサーバーを起動できます:

    /usr/pgsql-16/bin/pg_ctl -D /var/lib/pgsql/16/data -l ログファイル start

$ exit
ログアウト
```

データベースクラスタが作成できたら、ディレクトリ内のファイルを確認してみましょう。

```shell-session
$ sudo ls /var/lib/pgsql/16/data
PG_VERSION    pg_hba.conf    pg_replslot   pg_subtrans  postgresql.auto.conf
base          pg_ident.conf  pg_serial     pg_tblspc    postgresql.conf
global        pg_logical     pg_snapshots  pg_twophase
pg_commit_ts  pg_multixact   pg_stat       pg_wal
pg_dynshmem   pg_notify      pg_stat_tmp   pg_xact
```

データベースクラスタ内で名前が `.conf` で終わるのが設定ファイルです。`base` と `global` ディレクトリにはデータファイル、名前が `pg_` で始まるディレクトリには制御ファイルが格納されます。ログファイルはデフォルトでは `log` ディレクトリに格納されます。

PostgreSQL 16 では、データベースクラスタ作成時にロケールなしを指定しても、設定ファイル `postgresql.conf` 内で `lc_messages` パラメータがコメントになったままで、メッセージのロケールがシステムと同じになり、日本語環境ではメッセージが日本語で出力されます。メッセージが日本語でも動作に影響ありませんが、日本語だとネットで検索しても情報が見つかりづらいので、行頭の `#` を削除してコメントから外しておきます。

```config:/var/lib/pgsql/16/data/postgresql.conf
# These settings are initialized by initdb, but they can be changed.
lc_messages = 'C'                      # locale for system error message
                                        # strings
#lc_monetary = 'C'                      # locale for monetary formatting
#lc_numeric = 'C'                       # locale for number formatting
#lc_time = 'C'                          # locale for time formatting
```

# データベースサーバの起動

データベースクラスタの場所を変更している場合には、PostgreSQL サービスのユニットファイルを編集します。

```shell-session
$ sudo systemctl edit postgresql-16.service
```

エディタが起動されたら、`Service` セクション内の `Environment` オプションで環境変数 `PGDATA` にデータベースクラスタの場所を指定します。

```ini
[Service]
Environment=PGDATA=/var/lib/pgsql/16/data
```

PostgreSQL サービスとしてデータベースサーバを起動します。

```shell-session
$ sudo systemctl start postgresql-16.service
```

何も出力されなければ、起動できています。

ついでに OS の起動時に PostgreSQL サービスが起動されるようにします。

```shell-session
$ sudo systemctl enable postgresql-16.service
Created symlink /etc/systemd/system/multi-user.target.wants/postgresql-16.service → /usr/lib/systemd/system/postgresql-16.service.
```

# PostgreSQL スーパーユーザの環境変数設定

データベースサーバの管理は PostgreSQL のスーパーユーザ `postgres` で行います。`postgres` ユーザで操作しやすくなるように環境変数の設定を行います。

環境変数の設定は、通常、設定ファイル `~/.bash_profile` で行いますが、`postgres` ユーザの `~/.bash_profile` はパッケージのインストール時に上書きされてしまいます。そのため、`~/.bash_profile` から設定ファイル `~/.pgsql_profile` を読み込むようになっており、環境変数の設定は `~/.pgsql_profile` で行います。

```shell-session
$ sudo su - postgres
$ vi ~/.pgsql_profile
```

設定ファイル `~/.pgsql_profile` では環境変数 `PATH`、`MANPATH`、`PGDATA` の設定を行います。`psql` などのクライアントプログラムは (そのシンボリックリンクが) デフォルトの検索パスに含まれていますが、`pg_ctl` などのサーバプログラムは含まれていないので、環境変数 `PATH`、`MANPATH` の設定が必要です。環境変数 `PGDATA` にはデータベースクラスタの場所を指定します。サーバプログラムではデータベースクラスタの場所を指定する必要がありますが、環境変数 `PGDATA` の設定を行えば省略できます。

```bash:~/.pgsql_profile
export PATH=/usr/pgsql-16/bin:$PATH
export MANPATH=/usr/pgsql-16/share/man:$MANPATH
export PGDATA=/var/lib/pgsql/16/data
```

設定ファイル `~/.bash_profile` の再読み込みを行い、設定の変更を反映します。

```shell-session
$ . ~/.bash_profile
```

# データベースの接続確認

最後にデータベースの一覧を表示し、データベースに接続できるかを確認します。パスワードの入力プロンプトが表示されるので、データベースクラスタ作成時に設定したパスワードを入力します。

```shell-session
$ psql -l
ユーザー postgres のパスワード: (パスワードを入力)
                                                                 データベース一覧
   名前    |  所有者  | エンコーディング | ロケールプロバイダー | 照合順序 | Ctype(変換演算子) | ICUロケール | ICUルール: |     アクセス権限
-----------+----------+------------------+----------------------+----------+-------------------+-------------+------------+-----------------------
 postgres  | postgres | UTF8             | libc                 | C        | C                 |             |            |
 template0 | postgres | UTF8             | libc                 | C        | C                 |             |            | =c/postgres          +
           |          |                  |                      |          |                   |             |            | postgres=CTc/postgres
 template1 | postgres | UTF8             | libc                 | C        | C                 |             |            | =c/postgres          +
           |          |                  |                      |          |                   |             |            | postgres=CTc/postgres
(3 行)

```

データベースクラスタを作成した直後は `postgres`、`template0`、`template1` の 3 つのデータベースが存在します。

PostgreSQL のインストールはこれで完了です。ただ、ローカルホスト以外から接続するには、さらに設定を行う必要があります。それについては [こちらの記事](https://qiita.com/tom-sato/items/d5f722fd02ed76db5440) を参照してください。