PostgreSQLのDockerコンテナ起動時に指定したSQLファイルを実行する

# 目的
開発環境用のPostgreSQLをDockerコンテナとして作って配るのに、テーブルがあらかじめ作ってあって、データも入ってたらよいよねということで、手順をまとめてみました。

# 準備
こんな感じの構成です。
work
├Dockerfile
├init-user-db.sh
└test.sql

## Dockerfile
この記事を書いている時点の最新版13.3をベースにしていますが、任意のpostgresイメージを指定してください。

```
FROM postgres:13.3

COPY test.sql /
COPY init-user-db.sh /docker-entrypoint-initdb.d

EXPOSE 5432
```

複数SQLファイルがある場合は、
COPY *.sql /
とかも出来ます。

## init-user-db.sh
[https://hub.docker.com/_/postgres]
Initialization scriptsに書いてある通り、コンテナ開始時に/docker-entrypoint-initdb.d配下の*.sql, *.sql.gz, or *.shスクリプトを実行してくれる仕組みがあるので、これを利用します。

```init-user-db.sh
#!/bin/sh 
set -e

psql -f test.sql -U postgres
```

sqlファイルを直接置いても実行できるのですが、順番制御を考えるとシェル経由で実行した方が良いと思います。
**改行コードはLFにします。**

## test.sql
実行したいSQLを記述します。

```test.sql
CREATE TABLE test(id int, name varchar(50));

INSERT INTO test VALUES(1, 'hoge');
INSERT INTO test VALUES(2, 'moge');
```

\COPYコマンドを使ってCSVをロードすることも出来ます。その場合はDockerfileでCSVファイルもコピーしておきましょう。
**改行コードはLFにします。**

# 実行
## Dockerイメージのビルド
```
>docker build -t mypostgres .
[+] Building 3.3s (8/8) FINISHED
 => [internal] load build definition from Dockerfile                                                               0.1s
 => => transferring dockerfile: 141B                                                                               0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [internal] load metadata for docker.io/library/postgres:13.3                                                   2.4s
 => CACHED [1/3] FROM docker.io/library/postgres:13.3@sha256:a8f25ca44e98a4846cad176be8017f8f9c34028e4eebbf905dd4  0.0s
 => [internal] load build context                                                                                  0.1s
 => => transferring context: 116B                                                                                  0.0s
 => [2/3] COPY test.sql /                                                                                          0.1s
 => [3/3] COPY init-user-db.sh /docker-entrypoint-initdb.d                                                         0.1s
 => exporting to image                                                                                             0.2s
 => => exporting layers                                                                                            0.1s
 => => writing image sha256:52c65adfdab3bcd8193ef08c249a164c9dace17bae8e613e716ca984136ea2c4                       0.0s
 => => naming to docker.io/library/mypostgres                                                                      0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

>
```

## コンテナの実行
```
>docker run --name=mypostgres -e POSTGRES_PASSWORD=mysecretpassword -d mypostgres
8c9553e5403049dbddf3dd0ed6a2f78a4f11834306f673e1bf61731690b1122f

>
```

## コンテナに入ってSQL結果の確認
```
>docker exec -it mypostgres /bin/bash
root@8c9553e54030:/# psql -U postgres
psql (13.3 (Debian 13.3-1.pgdg100+1))
Type "help" for help.

postgres=# \dt
        List of relations
 Schema | Name | Type  |  Owner
--------+------+-------+----------
 public | test | table | postgres
(1 row)

postgres=# select * from test;
 id | name
----+------
  1 | hoge
  2 | moge
(2 rows)

postgres=# exit
root@8c9553e54030:/# exit
exit

>
```

ちゃんとテーブルもできていて、データも入ってましたね。

# トラブルシューティング

* 最もハマったのは、シェルとSQLファイルの改行コードをLFにしていなかったせいで、コンテナが即時終了してしまう事象でした。気を付けましょう。 
* docker logsでログを見るのを怠らないようにしましょう。（自戒を込めて）