初心者からこだわりのある人向けRPMからPostgreSQL導入

# はじめに

PostgreSQLはrpmを使えば簡単に導入できます。
しかしRPMにより自動で色々としているので、細かい点にこだわると思うようにいかない場合があります。
そのため自分がRPMで導入した時の簡単な手順と、こだわりのある導入をしたいときの補足情報を共有します。

今回は主に次のような環境を想定しています。

|環境|バージョン|
|---|---|
|OS|CentOS 7, RHEL 7|
|PostgreSQL|ver.10以上|

※OSがLinux6系の場合、サービス(自動起動/停止スクリプト)の設定が異なります。


# 簡単なインストール手順

## RPMによる基本的なインストール
### オンライン環境の場合
以下のサイトの手順に沿ってリポジトリを構築後、RPMを導入してください。

https://www.postgresql.org/download/linux/redhat/#yum

例)CentOS 7(64bit)へPostgreSQL 10を導入する場合(全てrootユーザで実施)

(1)yum用のリポジトリをインストールする。

```bash:
yum install https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/pgdg-redhat10-10-1.noarch.rpm
```

(2)クライアント機能をインストールする。

```bash:
yum install postgresql10
```

(3)サーバ機能をインストールする。

```bash:
yum install postgresql10-server
```



### オフライン環境の場合

以下のサイトからRPMを直接入手可能です。

https://yum.postgresql.org/rpmchart.php

バージョン、環境に合わせたリンク先から、「Available Groups」の「PostgreSQL Database Server XX PGDG」を選択します。
(XXはバージョンの値です)
これらがPostgreSQL導入に必要な基本的なRPMです。

|RPM|説明|
|---|---|
|postgresqlXX|クライアント向け機能|
|postgresqlXX-contrib|PostgreSQLの拡張機能(必須ではない)|
|postgresqlXX-libs|PostgreSQLに必要なライブラリ群|
|postgresqlXX-server|データベースサーバ機能|

例)CentOS 7(64bit)へPostgreSQL 10を導入する場合

(1)上記のRPMを導入先の環境へ転送する。

(2)導入OSのパッケージが必要になる可能性が高いため、インストールメディアをマウントする。

```bash:
mount /dev/sr0 /media
```
※見つからない場合、「mount」と入力し確認する。

(3)メディア用のリポジトリを編集し、マウントしたパッケージ先のパスを追加する。

```bash:
vi /etc/yum.repos.d/CentOS-Media.repo
```

```bash:CentOS-Media.repo
# ----------変更前----------
baseurl=file:///media/CentOS/
        file:///media/cdrom/
        file:///media/cdrecorder/

# ----------変更後----------
baseurl=file:///media/CentOS/
        file:///media/cdrom/
        file:///media/cdrecorder/
        file:///media             # これを追加する
```

※RHELの場合、repoファイルが存在しないので作成する必要がある。詳細は[こちら](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-yum)。

(4)PostgreSQLのRPM配置先へ移動し、以下の順番でインストールする。

```bash:オフライン環境でのRPM導入(全てrootユーザで実施)
cd <PostgreSQLのRPM配置先>

yum --disablerepo=\* --enablerepo=c7-media install postgresql10-libs-10.1-1PGDG.rhel7.x86_64.rpm
yum --disablerepo=\* --enablerepo=c7-media install postgresql10-10.1-1PGDG.rhel7.x86_64.rpm
yum --disablerepo=\* --enablerepo=c7-media install postgresql10-contrib-10.1-1PGDG.rhel7.x86_64.rpm
yum --disablerepo=\* --enablerepo=c7-media install postgresql10-server-10.1-1PGDG.rhel7.x86_64.rpm
```
※yumコマンドの詳細は先程追記した「/etc/yum.repos.d/CentOS-Media.repo」に記載されています。

## PostgreSQLを管理するOSユーザの確認

rpmで導入したPostgreSQLの管理OSユーザはデフォルトで、ユーザ名：postgres、グループ：postgresです。
これらのユーザ、グループはPostgreSQLのrpm導入時に自動的に作成されます。
ただしパスワードは未設定のため、この時点で設定することを推奨します。

```bash:パスワードの設定
passwd postgres
```

postgresユーザのホームディレクトリは「/var/lib/pgsql」であり、環境変数PGDATAが.bash_profileへ既に設定済みです。

```bash:OSのpostgresユーザにログインし確認(/var/lib/pgsql/.bash_profile)
[ -f /etc/profile ] && source /etc/profile
PGDATA=/var/lib/pgsql/10/data
export PGDATA
# If you want to customize your settings,
# Use the file below. This is not overridden
# by the RPMS.
[ -f /var/lib/pgsql/.pgsql_profile ] && source /var/lib/pgsql/.pgsql_profile
```

環境変数が設定されている場合、接続時に必要な情報の指定を省略可能です。
(代わりに環境変数の値を接続時に参照します)

* PostgreSQLの環境変数

|環境変数|説明|
|---|---|
|PGDATA|PostgreSQLのデータディレクトリのパス (デフォルトで設定済み)|
|PGPORT|PostgreSQLのポート番号|
|PGDATABASE|接続先のデータベース名|
|PGUSER|接続に用いるユーザ名|

* 環境変数の詳細<br>
https://www.postgresql.jp/document/current/html/libpq-envars.html

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

準備が整ったので、PostgreSQLのデータベースクラスタを構成します。
クラスタ構築先は、デフォルトで設定済みのPGDATAの値である「/var/lib/pgsql/XX/data」です。
rootユーザで以下のコマンドを実行することで、デフォルト設定のままデータベースクラスタを構築できます。

```bash:デフォルト設定のままクラスタを構築(rootユーザで実施)
/usr/pgsql-10/bin/postgresql-10-setup initdb
```

ただしこのままだと、ロケールや文字コードが環境依存で決まってしまいます。
(特にロケールはクラスタ構築後に変更できないので注意が必要です)

そのため次のように環境変数PGSETUP_INITDB_OPTIONSを用いることで、ロケールと文字コードを、任意の値に設定します。

```bash:ロケールと文字コードを指定してクラスタを構築(rootユーザで実施)
export PGSETUP_INITDB_OPTIONS="--encoding=UTF8 --no-locale"
/usr/pgsql-10/bin/postgresql-10-setup initdb
```

他にもデータベースクラスタのディレクトリを指定したい、ポート番号を変更したい等、デフォルトとは異なる設定で、クラスタを構築したい場合も多々あります。
そのような時は、この環境変数PGSETUP_INITDB_OPTIONSを用いることで、構築設定のカスタマイズが可能です。
実際に指定できる値は以下のinitdb時に指定可能なオプションと同一です。

* initdbで指定可能なオプション<br>
https://www.postgresql.jp/document/current/html/app-initdb.html

ただしRPMによる導入ではデフォルト設定のままデータベースクラスタが構築されることを前提としています。
そのため、オプションによりカスタマイズした場合、いくつか設定変更が必要です。
詳細は[デフォルト設定と異なるPostgreSQLを構築したい](#デフォルト設定と異なるpostgresqlを構築したい)に後述します。


## データベースの状態確認と起動/停止

rpmで導入したPostgreSQLはデフォルトで「postgresql-XX」という名前でサービスに登録されています。
(XXはメジャーバージョンの値)
そのためrootユーザを用いて、サービスから起動/停止できます。
データベースクラスタ構築直後は、PostgreSQLは停止しているため、起動させます。

* 「pg_ctl」コマンドによる起動/停止も可能ですが、サービスとの関係が切れてしまうため推奨しません。

```bash:rootユーザによりサービスからPostgreSQLの状態確認(停止中)
systemctl status postgresql-10
```
```bash:実行結果
● postgresql-10.service - PostgreSQL 10 database server
   Loaded: loaded (/usr/lib/systemd/system/postgresql-10.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
     Docs: https://www.postgresql.org/docs/10/static/
…
```


```bash:rootユーザによりサービスからPostgreSQLの起動
systemctl start postgresql-10
```


```bash:rootユーザによりサービスからPostgreSQLの状態確認(起動中)
systemctl status postgresql-10
```
```bash:実行結果
● postgresql-10.service - PostgreSQL 10 database server
   Loaded: loaded (/usr/lib/systemd/system/postgresql-10.service; disabled; vendor preset: disabled)
   Active: active (running) since 水 2018-10-17 09:44:59 JST; 15s ago
     Docs: https://www.postgresql.org/docs/10/static/
…
```

PostgreSQLを停止する場合は次のコマンドを実施します。

```bash:(補足)rootユーザによりサービスからPostgreSQLの停止
systemctl stop postgresql-10
```


## データベースの自動起動/停止スクリプトの確認

RPMによる導入時は/lib/systemd/system配下に自動起動/停止スクリプトpostgresql-XX.serviceが自動的に作成されます。


```bash:自動起動/停止スクリプト(/lib/systemd/system/postgresql-10.service)
# It's not recommended to modify this file in-place, because it will be
# overwritten during package upgrades.  If you want to customize, the
# best way is to create a file "/etc/systemd/system/postgresql-10.service",
# containing
#       .include /usr/lib/systemd/system/postgresql-10.service
#       ...make your changes here...
# For more info about custom unit files, see
# http://fedoraproject.org/wiki/Systemd#How_do_I_customize_a_unit_file.2F_add_a_custom_unit_file.3F

# Note: changing PGDATA will typically require adjusting SELinux
# configuration as well.

# Note: do not use a PGDATA pathname containing spaces, or you will
# break postgresql-setup.
[Unit]
Description=PostgreSQL 10 database server
Documentation=https://www.postgresql.org/docs/10/static/
After=syslog.target
After=network.target

[Service]
Type=notify

User=postgres
Group=postgres

# Note: avoid inserting whitespace in these Environment= lines, or you may
# break postgresql-setup.

# Location of database directory
Environment=PGDATA=/var/lib/pgsql/10/data/

# Where to send early-startup messages from the server (before the logging
# options of postgresql.conf take effect)
# This is normally controlled by the global default set by systemd
# StandardOutput=syslog

# Disable OOM kill on the postmaster
OOMScoreAdjust=-1000
Environment=PG_OOM_ADJUST_FILE=/proc/self/oom_score_adj
Environment=PG_OOM_ADJUST_VALUE=0

ExecStartPre=/usr/pgsql-10/bin/postgresql-10-check-db-dir ${PGDATA}
ExecStart=/usr/pgsql-10/bin/postmaster -D ${PGDATA}
ExecReload=/bin/kill -HUP $MAINPID
KillMode=mixed
KillSignal=SIGINT


# Do not set any timeout value, so that systemd will not kill postmaster
# during crash recovery.
TimeoutSec=0

[Install]
WantedBy=multi-user.target
```


ただし上記スクリプトは有効化していないため、以下のように自動起動/停止を有効化させます。


```bash:自動起動/停止スクリプトの状態確認(無効化)
systemctl list-unit-files -t service | grep postgres
```
```bash:実行結果
postgresql-10.service                         disabled
```

```bash:自動起動/停止スクリプトの有効化
systemctl enable postgresql-10
```
```bash:実行結果
Created symlink from /etc/systemd/system/multi-user.target.wants/postgresql-10.service to /usr/lib/systemd/system/postgresql-10.service.
```

```bash:自動起動/停止スクリプトの状態確認(有効化)
systemctl list-unit-files -t service | grep postgres
```
```bash:実行結果
postgresql-10.service                         enabled
```

また自動起動/停止スクリプトを無効化する場合は次のようにします。

```bash:(補足)自動起動/停止スクリプトの無効化
systemctl disable postgresql-10
```
```bash:実行結果
Removed symlink /etc/systemd/system/multi-user.target.wants/postgresql-10.service.
```

余談ですがソースコードから、手動でPostgreSQLを導入した場合、当然ながら自動起動スクリプトは作成されません。
ですが、RPMによって作成されたスクリプトと類似した内容のスクリプトを、同じディレクトリに配置後、同様の有効化をすれば、自動起動/停止は可能です。
ただしその場合、作成/変更したスクリプトの反映と、ファイルパーミッションを644にする必要がある点に注意してください。

```bash:(補足)自作の自動起動/停止スクリプトを作成した場合
chmod 644 /lib/systemd/system/postgresql-10.service
systemctl daemon-reload
```


## データベースへのログイン

今までの手順により、PostgreSQLの導入が完了しました。
よって実際にログイン可能かを確認してみます。
PostgreSQLへのログインはOSのpostgresユーザから、psqlコマンドにより可能です。

```bash:OSのpostgresユーザからPostgreSQLへログイン
# su - postgres
$ psql

=# SELECT now();
              now
-------------------------------
 2018-10-17 10:14:40.802799+09
(1 行)
```

今回はローカル接続のため、(デフォルト設定では)パスワードは必要ありません。
しかし、そもそもパスワードは未設定のため、正しいパスワードを入力しようがありません。
そのためパスワードを設定します。

```sql:
=# ALTER ROLE postgres PASSWORD '<任意のパスワード>';
```

本来、ログイン時は環境変数、またはpsqlのオプションにより、接続ユーザ名や接続先DB名の指定が必要です。
しかし今回はデフォルト設定のまま導入したため、psqlのデフォルト値のままログイン可能です。
独自にポート番号、接続ユーザ名、DB名を指定した場合、環境変数やpsqlのオプションが必要です。
PostgreSQLの環境変数については前述の[PostgreSQLを管理するOSユーザの確認](#postgresqlを管理するosユーザの確認)を参照ください。

ログインできることが確認できました。
これによりRPMからPostgreSQLの導入は完了です。


# デフォルト設定と異なるPostgreSQLを構築したい

RPMを用いることで細かい設定をせずに、PostgreSQLは導入可能です。
ただし異なるディレクトリに、データベースクラスタを構築したいなど、デフォルトと異なる構成にしたいケースも多々あります。
そのため、以下にデフォルト設定と異なるPostgreSQLの構築方法を記載します。


## データディレクトリを変更したい

データディレクトリ(PGDATA)は自動起動/停止スクリプトにデフォルト値が設定されています。
そのため、クラスタ構築前に自動起動/停止スクリプトを編集します。
今回は、データディレクトリを「/pg10/pgdata」配下に作成する想定で手順例を示します。

```bash:自動起動/停止スクリプト(/lib/systemd/system/postgresql-10.service)
# [変更前]
Environment=PGDATA=/var/lib/pgsql/10/data

# [変更後：任意のディレクトリ]
Environment=PGDATA=/pg10/pgdata
```

その後、postgresユーザにログインし、環境変数PGDATAもデフォルト値から変更します。

```bash:環境変数の変更(/var/lib/pgsql/.bash_profile)
# ----------変更前----------
PGDATA=/var/lib/pgsql/10/data

# ----------変更後----------
PGDATA=/pg10/pgdata
```

後は通常の手順通り、[データベースクラスタの構成](#データベースクラスタの構成)以降の操作を実施します。


## 異なるOSユーザで導入したい

PostgreSQLのOS管理者ユーザをpostgresではなく、任意のユーザにする方法を記載します。
PostgreSQLを構築する「/usr/pgsql-10/bin/postgresql-10-setup」スクリプトは、PostgreSQLのOS管理者ユーザをpostgresでハードコードしています。
そのため、initdbコマンド実施、環境変数の設定、自動起動/停止スクリプトの編集が必要です。
今回はpg10ユーザ(グループはpostgresのまま)を、PostgreSQLのOS管理者ユーザにし、データディレクトリは/home/pg10/data配下に作成する想定で手順例を示します。

(1)任意のユーザを作成する。

```bash:postgresグループに属し、ホームディレクトリ/home/pg10のpg10ユーザを作成(rootユーザで実施)
useradd -g postgres -d /home/pg10 pg10
passwd pg10
```

(2)rootユーザによりデータディレクトリを予め作成し、所有者をpg10ユーザへ変更する

```bash:データディレクトリを予め作成(rootユーザで実施)
mkdir -p /home/pg10/data
chown -R pg10:postgres /home/pg10/data
chmod -R 700 /home/pg10/data
```

(3)pg10ユーザの環境変数を設定する。

```bash:pg10ユーザにログインし、.bash_profileを編集(pg10ユーザで実施)
vi .bash_profile
```

```bash:環境変数PGDATAを追記(.bash_profile)
export PGHOST=localhost
export PGDATA=/home/pg10/data
export PGDATABASE=postgres
```

* ↑RPM導入においては、ローカル接続はpostgresユーザで実施することが前提となっているため、接続先を明示的にしておきます。

```bash:変更内容を反映(pg10ユーザで実施)
. .bash_profile
```


(4)自動起動/停止スクリプトを編集する。

```bash:自動起動/停止スクリプト(/lib/systemd/system/postgresql-10.service)
# ----------変更前----------
[Service]
Type=notify

User=postgres
Group=postgres

…(中略)…

Environment=PGDATA=/var/lib/pgsql/10/data/

# ----------変更後----------
[Service]
Type=notify

User=pg10
Group=postgres

…(中略)…

Environment=PGDATA=/home/pg10/data
```

(5)initdbをpg10ユーザで実行する。

```bash:initdbの実行(pg10ユーザで実行)
/usr/pgsql-10/bin/initdb --encoding=UTF8 --no-locale
```

(6)設定ファイルを変更する。

```設定ファイル(/home/pg10/data/postgresql.conf)を変更(pg10ユーザで実行)
# ----------変更前----------
unix_socket_directories = '/var/run/postgresql, /tmp'

# ----------変更後----------
unix_socket_directories = '/tmp'
```

* ↑これもRPM導入においてローカル接続がpostgresユーザで実施することが前提となっているための措置です。

後は通常の手順通り、[データベースの状態確認と起動/停止](#データベースの状態確認と起動停止)以降の操作を実施します。

上記の通り、RPMにおいてはPostgreSQLのOS管理者ユーザはpostgresであることを前提として構築されております。
そのためpostgresユーザ以外で管理したい場合、RPMではなくソースコードによる導入を用いるのも適切な手法です。