【PostgreSQL】Dockerコンテナビルド時にpostgresql.confの設定を反映する

## 概要
PostgreSQLのDockerコンテナビルド時に、postgresql.confをホストから送り込んで初期設定値を変更する方法を記載します。

confファイルによってDBの設定値を変更したいときに使います。今回は事例として以下3点を変更しますが、お手元で設定変更したい内容にしたがって、読み換えてください。
* max_connections
* max_wal_size
* timezone

| 項目 | 内容 |
|------|------|
| **取り扱う内容** | ・ PostgreSQLのDockerコンテナビルド時の設定カスタマイズ方法<br>・ postgresql.confファイルを使用した設定値の変更手順<br> ・ 変更した設定値が有効になっていることを確認する方法 |
| **想定読者** | ・ PostgreSQLをDockerで運用しようとしている人<br>・ Dockerの基本的な知識を持っている人<br>・ PostgreSQLの設定をカスタマイズする必要がある人 |
| **ゴール** | ・ PostgreSQLコンテナの設定値を初期値から変更する方法の理解|

## ホストのディレクトリ構成
本記事では、以下の構成でファイルが配置されている前提で構築を進めていきます。もちろん、細かいファイルの配置はプロジェクトの方針にしたがって変更してよいです。
```text
postgres/
├── docker-compose.yml
├── Dockerfile
└── config/
    └── postgresql.conf
```

## まずはconfの設定を反映しないでコンテナを起動し、初期値を確認する
コンテナ内の`postgresql.conf`を直接読めば初期値はわかるんですが、予行演習としてやっておきます。
### 設定ファイルの作成・記載
まずは`docker-compose.yml`と`Dockerfile`を以下の通り記載します。

`docker-compose.yml`
```yaml
version: '3.8' # 最新のDocker composeではバージョン自動判定されるので要らない

services:
  db:
    build: . # Dockerfileがあるディレクトリを指定 今回はカレントディレクトリ
    environment:
      POSTGRES_DB: testdb
      POSTGRES_USER: testuser
      POSTGRES_PASSWORD: testpass
    ports:
      - "5435:5432" # ホストで使用しているポートに重複しないよう、左辺を適宜変更
    volumes: # データの永続化が必要ならvolumeを定義する
    - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
```

`Dockerfile`
```bash
FROM postgres:15 # バージョンは適宜、お好きなものへ変更
```

### コンテナ起動
ホストにて、以下のコマンドを実行します。コンテナがビルド・起動されます。
```bash
docker-compose up --build -d
```

### DBの設定値を確認
ホストにて以下のコマンドを実行します。もちろん、コンテナにアタッチしてコンテナ内で`psql`以降を実行したり、外部のDB管理ツールからダブルクォート内のSQLを投げてもOK。とにかくこれによって、今回変更するDB設定の初期値がわかりましたね。
```bash
# psqlコマンドをdbコンテナで実行する
docker-compose exec db psql -U testuser -d testdb -c "SHOW max_connections; SHOW max_wal_size; SHOW timezone;"
```
実行結果：
```text
 max_connections 
-----------------
 100
(1 row)

 max_wal_size 
--------------
 1GB
(1 row)

 TimeZone 
----------
 Etc/UTC
(1 row)
```

## confファイルの設定を反映してコンテナを起動する
前項で確認した3つの設定値を、confファイルによってコンテナビルド時点で変更していきます。

### 設定ファイルの編集・追加
`docker-compose.yml`は前項と同様でOK。`dockerfile`の編集と、confファイルの作成・記載を行います。

`Dockerfile`
```bash
FROM postgres:15

# postgresql.confをコンテナ内にコピー
COPY config/postgresql.conf /etc/postgresql/postgresql.conf

# 設定ファイルの場所を指定して起動するようにCMDを上書き
# docker-compose.ymlで別のcommandを書いていると、そちらが優先されてしまうので注意
CMD ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf"]

```

`config/postgresql.conf`
```bash
max_connections = 200
max_wal_size = 2GB
timezone = 'Asia/Tokyo'
```

DockerfileのCOPY先ディレクトリについて：
Dockerfileにおいて、confファイルの送り先をPostgreSQLのデフォルトconfファイルパスである`/var/lib/postgresql/data/postgresql.conf `ではなく、`/etc/postgresql/postgresql.conf`へのCOPYとしています。これは、以下の理由によります。
* デフォルトの設定ファイルを上書きしないようにするため
* `docker-compose.yml`でvolumesマウントしているので、COPYした内容が永続化ボリュームによって上書きされる可能性があるため

### コンテナ起動
ホストにて、以下のコマンドを実行します。コンテナがビルド・起動されます。
```bash
# docker-compose up -d ではコンテナがビルドされない = 設定反映されないので、--buildをつける
docker-compose up --build -d
```

### DBの設定値を確認
ホストにて以下のコマンドを実行します。confファイルに記載した設定でコンテナが稼働していることが分かります。
```bash
# psqlコマンドをdbコンテナで実行する
docker-compose exec db psql -U testuser -d testdb -c "SHOW max_connections; SHOW max_wal_size; SHOW timezone;"
```
実行結果：
```text
 max_connections 
-----------------
 200
(1 row)

 max_wal_size 
--------------
 2GB
(1 row)

  TimeZone  
------------
 Asia/Tokyo
(1 row)

```

以上です！　大きいデータを扱う際は、PostgreSQLの初期値では心許ない場面も多いので、この方法で設定値を変えながら色々遊んでみましょう。