DockerでPostgreSQLを使う



本番環境ではDBはコンテナ化することは少いと思いますが、諸事情によりメモ。


## 前知識

Docker環境でPostgreSQLを扱う場合に事前に知っておいたほうが良い知識。

### /docker-entrypoint-initdb.d/

PostgreSQLのイメージ(MySQLも）では、/docker-entrypoint-initdb.d/以下に置かれたファイルを起動時に実行する仕組みがあり、これらを利用してDBの初期設定・初期データの作成などを行うことができる。

>サーポートされている拡張子は.sh, .sql, .sql.gzみたい。

### /var/lib/postgresql/data

PostgreSQLのデータ保存場所のパスは/var/lib/postgresql/dataとなる。これをローカルにマウントしてデータの永続化を行う。

## 基本

### 起動

まずはシンプルにPostgreSQLをDockerで起動してみます。

>私の都合上、14.5-bullseyeを指定していますが、単にpostgresでも問題ありません。

```bash
docker run --name postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 -d postgres:14.5-bullseye
```

>-eは環境変数を指定しています（パスワードを指定）。
>-dはバックグラウンドで起動

### ログイン

dockerを利用しているホスト環境にpsqlがインストールされていれば以下でログインできます。


```bash
$ psql -h localhost -U postgres -d postgres
```

>パスワードはdocker run時に環境変数として与えたものになります（ここではpostgres）。

## 応用１（初期データ設定および永続化）

### 準備

```bash
cd
mkdir docker-pg-test
cd docker-pg-test

mkdir init data
touch ./init/init.sql
```

### init.sql


```sql:init.sql
create table if not exists members(
    id serial primary key,
    name text,
    age int
);
```

### 実行と動作確認


基本時の記述に加え、-vでローカルの./initと./dataをコンテナ上のディレクトリにマップしています。

>実行場所は上記docker-pg-testディレクトリの中です。

#### 実行

```bash
docker run --name postgres -it -p 5432:5432 -e POSTGRES_PASSWORD=postgres -v $(pwd)/init:/docker-entrypoint-initdb.d -v $(pwd)/data:/var/lib/postgresql/data -d postgres:14.5-bullseye
```

#### ログイン

ホストPC上で行います。

```bash
$ psql -h localhost -U postgres -d postgres
```

#### テーブル確認

\dtでテーブルを確認してみます。membersテーブルが作成されています。


> members_id_sqlは自動連番用に自動生成されたテーブルです。


```bash
postgres=# \dt;


               List of relations
 Schema |      Name      |   Type   |  Owner
--------+----------------+----------+----------
 public | members        | table    | postgres
 public | members_id_seq | sequence | postgres
(2 rows)
```

#### データの挿入

データを挿入してみます。

>select * from members;で内容確認してみてください。

```bash
postgres=# insert into members(name,age) values('hoge',99);
```

#### DBから抜ける

ここでDBからは一旦抜けておきます（ホストPCでの操作）。

```bash
postgres=# \q;
```

>exitでも抜けられる。


データが永続化されているか確認してみましょう。

#### コンテナの停止

まず、コンテナの停止。

```bash
docker stop postgres
```

#### コンテナの削除

コンテナの削除。

>ここで永続化していなければデータは失われます。

```bash
docker rm postgres
```

#### コンテナの再実行

では、再度コンテナを立ち上げてみます。

```bash
docker run --name postgres -it -p 5432:5432 -e POSTGRES_PASSWORD=postgres -v $(pwd)/init:/docker-entrypoint-initdb.d -v $(pwd)/data:/var/lib/postgresql/data -d postgres:14.5-bullseye
```

#### ログインしてデータ確認

ログインしてデータを確認します。上記（以前）で投入したデータが確認できます（＝データが永続化されています）。

```bash
postgres=# select * from members;

 id | name | age
----+------+-----
  1 | hoge |  99
(1 row)
```


## 応用２（docker-compose化）

ごちゃごちゃしてるのでdocker-composeにまとめてみる。

### docker-compose.ymlの記述

```yml:docker-compose.yml
version: '3'
services:
  postgres:
    image: postgres:14.5-bullseye
    container_name: my_postgres
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - ./data:/var/lib/postgresql/data
      - ./init:/docker-entrypoint-initdb.d
```

### 実行

```bash
docker-compose up -d
```

### 停止

```bash
docker-compose down
```

## 応用３（Dockerfileで記述）


docker-composeに比べたらできることは限られるが、クラウドのマネージ環境で動作させることを前提とすると、Dockerfile（イメージ化）でできることはしておいたほうがいいのかも。


### Dockerfile


```bash:Dockerfile
FROM postgres:14.5-bullseye

COPY ./init/init.sql /docker-entrypoint-initdb.d/init.sql

ENV POSTGRES_USER postgres
ENV POSTGRES_PASSWORD postgres

EXPOSE 5432
```

>DockerfileのVOLUMEでは、名前付きボリュームは指定できないみたい。

### イメージのビルド

```bash
docker build -t my_postgres .
```

### 実行

実行してみる。

```bash
docker run --name my_db -p 5432:5432 -d my_postgres
```

### 動作確認

まずはログイン（ホストPCから）。

```bash
$ psql -h localhost -U postgres -d postgres
```

init.sqlが適用されているか確認（されているみたい）。

```bash
postgres=# select * from members;

 id | name | age
----+------+-----
(0 rows)
```



## 参考

* https://timesaving.hatenablog.com/archive/category/PostgreSQL
* https://kakakakakku.hatenablog.com/entry/2017/11/08/193031
* https://karuta-kayituka.hatenablog.com/entry/2019/05/04/114056