Magicode logo
Magicode
4 min read

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

https://cdn.apollon.ai/media/notebox/25a1a1b8-7faa-49fd-a85c-4ed19073a293.jpeg

問題

今いるプロジェクトで、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にて、postgresDockerfileを見ると原因がわかります。 postgresDockerfileに以下の記述があります。
VOLUME [/var/lib/postgresql/data]

VOLUME命令とは?

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

なぜ解決した?

再度以下を見てください。
【誤】 postgres_volume:/var/lib/postgresql
【正】 postgres_volume:/var/lib/postgresql/data
上記の記事によれば、DockerfileVOLUME命令で指定されている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)

参考

Discussion

コメントにはログインが必要です。