問題
今いるプロジェクトで、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
とマウントしています)
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]
VOLUME命令とは?
Dockerfile
で、VOLUME命令
を指定すると匿名volumeが自動で作成されるそうです。
なぜ解決した?
再度以下を見てください。
【誤】 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)
参考