やりたかったこと
MySQLコンテナを立ち上げてデータを入れていたが、docker compose down したらデータが全部消えてしまった。「コンテナを落とすたびにDBが初期化されては困る」と気づいてボリュームを調べ始めた。
環境
- OS: Ubuntu 22.04 LTS
- Docker: 24.0.5
- docker compose: v2.20.2
- MySQL: 8.0.33
試したこと・うまくいかなかったこと
最初はホストのディレクトリをバインドマウントしてみた。
services:
db:
image: mysql:8.0
volumes:
- ./mysql-data:/var/lib/mysql
これで docker compose down してもデータが残るようになった。ただし、ホスト側の ./mysql-data ディレクトリのパーミッションがrootになってしまって、ホストから中身を確認したり操作しようとすると Permission denied が出た。
ls: cannot open directory './mysql-data': Permission denied
次に、バインドマウントをそのままVPSに持っていったら、MySQLの起動時にこんなエラーが出て動かなくなった。
[ERROR] InnoDB: Operating system error number 13 in a file operation.
OS側のパーミッションとMySQLの期待するディレクトリ権限がズレていた。
解決策
Dockerが管理する名前付きボリュームを使うと、こうしたパーミッション問題が起きない。
名前付きボリュームで起動する
docker run -d \
-e MYSQL_ROOT_PASSWORD=secret123 \
-v mydata:/var/lib/mysql \
mysql:8.0
docker-composeで設定する
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret123
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
volumes: セクションを書かないとエラーになるので注意。
ボリュームの操作コマンド
docker volume ls # ボリューム一覧
docker volume create mydata # 手動作成
docker volume inspect mydata # 詳細確認(保存先パスも分かる)
docker volume rm mydata # 削除
docker volume prune # 使われていないボリュームを全削除
バックアップとリストア
# バックアップ(ボリュームの中身をtarで固める)
docker run --rm \
-v mydata:/source \
-v $(pwd):/backup \
alpine tar czf /backup/mydata-backup.tar.gz -C /source .
# リストア
docker run --rm \
-v mydata:/target \
-v $(pwd):/backup \
alpine tar xzf /backup/mydata-backup.tar.gz -C /target
ハマったポイント
docker compose downは停止のみ、ボリュームは残る。docker compose down -vはボリュームも一緒に削除する。うっかり-vをつけてDBのデータを全部吹き飛ばしたことがある- バインドマウント(
./ホストパス:/コンテナパス)とボリューム(名前:/コンテナパス)は別物。バインドマウントはホストのパスを直接使うのでパーミッション問題が起きやすい docker volume inspectで実際の保存先(/var/lib/docker/volumes/mydata/_data)が確認できる。ボリュームがどこにあるか分からなくて焦ったがこれで解決したdocker compose upで再起動してもボリュームのデータはそのまま引き継がれる。MySQLの初期化スクリプト(/docker-entrypoint-initdb.d/)はボリュームが空のときだけ実行される仕様で、データが残っていると実行されない
関連記事
おすすめのVPS
VPSを使って本番環境を構築するなら、以下のサービスがおすすめです。