dockerでデータを永続化して、イメージをアップデートしてみる

# はじめに
Dockerを仕事で使った経験はないんですが、もし仮にアプリケーションに脆弱性が見つかったら、アップデートが必要になるんだろうなと思っていて、このときデータが消えないように、どのようにして永続化されているのか気になったので調べてみました。
今回はPostgreSQLを使って、データを永続化する方法を調べてます。

# 永続化手段
[公式サイト](https://docs.docker.jp/storage/bind-mounts.html) によると、マウント手段は３つありますが、このうちtmpfsマウントはテンポラリなので、永続化にはなりません。
では残る２つのうち、ボリュームとバインドマウントのどちらを使うのがよいのか？ですが、ボリュームの方が複数の利点があり、一般的にはこれを選ぶのが良いようです。

### ボリュームの利点
- 移植性。バインドマウントだと、ホストマシンを絶対パスで参照するため、移植性が低い。ボリュームだとクラウド上も指定できるようです。
- 安全性。 [公式の図](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674934/0f20614f-83f5-2590-7692-d4b507d01f75.png) を見ても、公開範囲を限定できるので、セキュリティ面でもボリュームが良さそうです。
- etc

# ボリュームを使って永続化してみる
docker-compose.ymlに`volumes:`が用意されており、これを使うだけのようです。。
適当にググったサイトでは、すべて`volumes:`が定義されていました。私が知らなかっただけで、簡単に永続化を実現できていたようです。お恥ずかしい :sweat_smile:


### yamlの用意

今回はPostgreSQL 14を使って検証してみます。

~~~docker-compose.yml
version: '3.1'

services:
  postgres:
    image: postgres:14
    container_name: pg_work
    restart: always
    environment:
      POSTGRES_PASSWORD: passw0rd
    ports:
      - "5432:5432"
    volumes:
      - pg_volume:/var/lib/postgresql/data

volumes:
  pg_volume: # services設定で設定したホスト側のボリューム名
~~~

`postgres:`に`volumes:`オプションを指定します。`<ホスト側のボリューム名>:<コンテナ内にマウントされるパス>`と書くようです。


### コンテナ起動
```
docker-compose up -d
```
と実行して、コンテナを起動します。

### ボリュームの情報を確認

```
docker inspect pg_work
```
を実行し、マウント情報を確認すると


```console:docker inspect pg_work
～～～割愛～～～
        "Mounts": [
            {
                "Type": "volume",
                "Name": "postgre_work_pg_volume",
                "Source": "/var/lib/docker/volumes/postgre_work_pg_volume/_data",
                "Destination": "/var/lib/postgresql/data",
～～～割愛～～～
```

となったことから
- `Type`から、ボリュームとしてマウントされていることが分かります。
- `Source`がホストディレクトリ、`Destination`がコンテナ内のパス。
- 今回は`postgre_work`というサブフォルダ上の`docker-compose.yml`を使ってコンテナ起動していますが、ボリューム名はこの`<サブフォルダ>_<docker-compose.ymlで定義したホスト側のボリューム名>`となることが分かりました。


### ボリュームを確認
```
docker volume ls
```
を実行し、念のためにボリュームが存在することを確認します。

```console:docker volume ls
DRIVER    VOLUME NAME
local     postgre_work_pg_volume
```
無事存在しました。

なおWindowsだと、以下にマウントされるようです。
`\\wsl$\docker-desktop-data\version-pack-data\community\docker\volumes`
![スクリーンショット 2022-06-25 222838.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674934/d44284fb-7fbe-9a4e-b0ac-2cf5062c12dc.png)

### 任意のデータ追加

ここは永続化が確認できれば良いので、任意のテーブルを作ってデータを追加しますが、中身は重要ではないので、折りたたんでます。

<details><summary>データ追加</summary>

まずはdockerに入ってbashを起動します。
```
docker exec -it pg_work /bin/bash
```

psqlを使って、PostgreSQLへ接続します。
```
root@ddada874b2bc:/# psql -h localhost -U postgres
```

テーブルを作ります。
```
postgres=# create table hoge (id char(4) not null, name varchar(100));
CREATE TABLE
```

データ追加します。
```
postgres=# insert into hoge values ('aaa', 'abc');
INSERT 0 1
```

</details>

こんなデータが入ってます。
```
postgres=# select * from hoge;
  id  | name
------+------
 aaa  | abc
(1 row)
```

### イメージをアップデート

まずコンテナとイメージを破棄します。
```
docker-compose down
```

ボリュームの存在を確認します。
```console:docker volume ls
DRIVER    VOLUME NAME
local     postgre_work_pg_volume
```


本来はここでイメージのアップデートに、`docker-compose build --pull postgres`を実行するのかもしれませんが、時間経っていないからdockerイメージが変わっていないので、今回は直接yamlを編集して、PosgreSQL 14を14.4に変えてみました。
これが、適切なアップデート手順なのかは自信がないです。。

この1行だけ変更します。
~~~docker-compose.yml
    image: postgres:14.4
~~~

```
docker-compose up -d --build
```

を実行すると、14.4をpullしているのが確認できます。

```console:docker-compose up -d --build
Pulling postgres (postgres:14.4)...
14.4: Pulling from library/postgres
Digest: sha256:4ba3b78788bb284687376b9c1e0565b245375ddee0fe14cef25e315b6bd88b1a
Status: Downloaded newer image for postgres:14.4
Recreating pg_work ... done
```

### 永続化の確認

```
postgres=# select * from hoge;
  id  | name
------+------
 aaa  | abc
(1 row)
```

無事データが確認できました。永続化成功です。