docker-composeでpostgresのDBが永続化できていなかったのを直した





問題
-
今いるプロジェクトで、`docker-compose`で名前付きvolumeを使っているのにも関わらず、`postgres`のDBが永続化できませんでした。
なので、`docker-compose down`をするとDBが消えてしまい、`docker-compose up`した後にその都度`rake db:create`やら`rake db:migrate`をやりなおさないといけないという感じでした。

まぁ、そんな頻繁に`docker-compose down`しなければいいとはいえ、たまに`docker-compose down`した時にいちいちDBを作成しなおすのは面倒ですし、必要なデータが存在する場合はDBを削除できないので、誤って`docker-compose down`しないように気をつけないといけません。


余計な部分は省いていますが、当初の`docker-compose.yml`は以下のような感じでした。
( postgresのDBを永続化するために、名前付きvolumeを作成して、`postgres`コンテナ内の`/var/lib/postgresql`とマウントしています)

```docker-compoe.yml
version: '3'
services:

  postgres:
    environment:
     - (略)
    image: postgres:10.5-alpine
    volumes:
      - postgres_volume:/var/lib/postgresql # <名前付きvolume名>:マウントしたいコンテナ内のPATH
    ports:
      - "5432:5432"

volumes:
  postgres_volume: # 名前付きvolumeを定義
```


`postgres`コンテナの情報を`docker inspect`で確認してみると、勝手に`匿名ボリューム(anonymous volume)`が作成され`postgres`コンテナとマウントしているのがわかりました。。うーむ、名前付きvolumeを指定してるんだけどなー:thinking: 
```
docker inspect <コンテナID>
```



解決方法
-
結論から言うと、`volumes`プロパティで指定しているコンテナ側のPATHが誤っていました。
```
【誤】 postgres_volume:/var/lib/postgresql
【正】 postgres_volume:/var/lib/postgresql/data
```

解説
-

### postgresのDockerfileにあるVOLUME命令

`Dockerhub`にて、`postgres`の`Dockerfile`を見ると原因がわかります。
`postgres`の`Dockerfile`に以下の記述があります。
> VOLUME [/var/lib/postgresql/data]

https://hub.docker.com/layers/postgres/library/postgres/10.5-alpine/images/sha256-294f651dec48ecd86c1ba6cd33e589ed669f0e355ed8c8a2a53f5287b4650f80?context=explore#:~:text=14-,VOLUME,-%5B/var/lib/postgresql

### VOLUME命令とは？

`Dockerfile`で、`VOLUME命令`を指定すると匿名volumeが自動で作成されるそうです。

https://qiita.com/daemokra/items/322270091cf41a853226#dockerfile%E3%81%AEvolume%E6%96%87%E3%81%A8volumes%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E4%BD%B5%E7%94%A8%E3%81%97%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AE%E6%8C%99%E5%8B%95


### なぜ解決した？

再度以下を見てください。
```
【誤】 postgres_volume:/var/lib/postgresql
【正】 postgres_volume:/var/lib/postgresql/data
```

上記の記事によれば、`Dockerfile`の`VOLUME命令`で指定されているPATHと同じPATHを、`名前付きvolume`のマウント先として指定すると、`匿名volume`が作成されず、`名前付きvolume`が使用される挙動になるそうです。
実際に試した所そのような挙動となることを確認しました。

なので、DBが永続化できていなかった原因は、`docker-compose.yml`にて、名前付きボリュームがマウントする`postgres`コンテナのPATHの指定が間違っていたことでした。


補足
-

匿名ボリュームが作成されてるので、永続化できそうな気もしますが、実際のところ匿名ボリュームはコンテナを削除して作成するたびに作られいて、使い回されないみたいです。
ただ過去の匿名ボリュームは使い回されないだけで、ずっと残りつづけていて、ストレージを逼迫する原因になります。
自分は過去の匿名ボリュームだけでMACのストレージを50GBくらい使ってました:sweat_smile: 

以下でvolume一覧が確認可能です。
```
docker volume ls
```

不要なvolumeを削除したい場合は以下のコマンドでできます。(現在存在するコンテナと紐付いてないvolumeのみ削除）
```
docker volume rm $(docker volume ls -qf dangling=true)
```
https://www.digitalocean.com/community/tutorials/how-to-remove-docker-images-containers-and-volumes-ja




参考
-
https://hub.docker.com/layers/postgres/library/postgres/10.5-alpine/images/sha256-294f651dec48ecd86c1ba6cd33e589ed669f0e355ed8c8a2a53f5287b4650f80?context=explore

https://qiita.com/daemokra/items/322270091cf41a853226#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB

https://stackoverflow.com/questions/61623124/persist-data-on-postgres-docker-with-a-volume-when-restarting-the-container

https://www.digitalocean.com/community/tutorials/how-to-remove-docker-images-containers-and-volumes-ja