Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( 番外編 )( docker volume メモ書き )
概要
記事一覧はこちらです。
PostgreSQL の環境を Docker Compose で構築しようとしたのですが、docker-compose.yml に postgresql コンテナの設定を追加して volumes に ./docker/postgresql/data:/var/lib/postgresql/data
と記述したところ、docker-compose up -d
コマンドは成功するのですが postgresql コンテナのログに FATAL: data directory "/var/lib/postgresql/data" has wrong ownership
というエラーメッセージが出力されて PostgreSQL サーバが起動しません。
Docker for Windowsでpostgresのデータマウントができない人へ という記事を見つけて、確かにこの記事の通りにすれば PostgreSQL サーバが起動したのですが、docker volume create
コマンドで作成した docker volume ってどこに保存されるのか?、そもそもなぜ失敗するのか?、を調べてみました。
参照したサイト・書籍
Docker for Windowsでpostgresのデータマウントができない人へ
https://qiita.com/kyo-bad/items/47b96883144a5bf1cb1edocker volume create
https://docs.docker.com/engine/reference/commandline/volume_create/Where are images stored?
https://forums.docker.com/t/where-are-images-stored/9794Use volumes
https://docs.docker.com/storage/volumes/Manage data in Docker
https://docs.docker.com/storage/Docker storage drivers
https://docs.docker.com/storage/storagedriver/select-storage-driver/Logs and troubleshooting
https://docs.docker.com/docker-for-windows/troubleshoot/LinuxからSambaをマウントする
https://qiita.com/dojineko/items/e6c21f3fe309b5aae694How to create CIFS docker volume with username, password, uid, and gid
https://serverfault.com/questions/805790/how-to-create-cifs-docker-volume-with-username-password-uid-and-gid/848166#848166Interactive shell using Docker Compose
https://stackoverflow.com/questions/36249744/interactive-shell-using-docker-compose
目次
- Docker Compose で単体の PostgreSQL サーバの環境を構築してみる
docker volume create
コマンドで作成した volume はどこにあるのか?docker volume create
コマンドで作成した volume だと起動するのに、docker-compose.yml の volumes で直接 Windows のディレクトリと関連付けた場合には起動に失敗する理由とは?docker volume create
コマンドで作成された volume はコンテナから使用されていないとdocker volume prune
コマンドで削除される- ここまでのまとめ
- Windows の共有フォルダを
docker volume create
コマンドで作成した volume 経由でアクセスする
手順
Docker Compose で単体の PostgreSQL サーバの環境を構築してみる
PostgreSQL のデータ用ディレクトリを関連付けるディレクトリとして docker/postgresql/data を作成した後、docker-compose.yml に postgresql コンテナの設定を追記します。
postgresql: image: postgres:11.1-alpine container_name: postgresql ports: - "5432:5432" volumes: - ./docker/postgresql/data:/var/lib/postgresql/data environment: - POSTGRES_PASSWORD=xxxxxxxx restart: always
docker-compose up -d
コマンドを実行するとコマンドではエラーは出ませんが、postgresql コンテナのログを見ると FATAL: data directory "/var/lib/postgresql/data" has wrong ownership
というエラーが出てコンテナが起動しません。
調べてみると Docker for Windowsでpostgresのデータマウントができない人へ という記事を見つけました。この記事を参考にして、まずは docker volume create --name postgresql-data
コマンドで volume を作成してから、
※実際には
docker volume ls
を実行するとランダムな文字列の名称の volume が大量に表示されたので、先に docker volume prune
を実行して削除しています。
docker-compse.yaml を以下のように変更し、
postgresql: image: postgres:11.1-alpine container_name: postgresql ports: - "5432:5432" volumes: - postgresql-data:/var/lib/postgresql/data environment: - POSTGRES_PASSWORD=xxxxxxxx restart: always volumes: postgresql-data: external: true
docker-compose up -d
コマンドを実行すると今度は起動しました。
起動はしたのですが、以下の疑問点が浮かびました。
docker volume create --name postgresql-data
コマンドで作成した postgresql-data は、実際にはどこにデータが保存されているのか? docker volume create コマンドのマニュアルを見ても Windows のディレクトリを指定する方法が記載されていません。docker volume create
コマンドで作成した volume だと成功するのに、docker-compose.yml の volumes で直接 Windows のディレクトリと関連付けた場合には起動に失敗するのか?
Docker って network も分からなかったけれど、volume とかいうものもあるのか。。。
docker volume create
コマンドで作成した volume はどこにあるのか?
- Docker の Document の Manage data in Docker に
Volumes are stored in a part of the host filesystem which is managed by Docker (/var/lib/docker/volumes/ on Linux).
という記述がありました。docker volume create
コマンドで作成した volume は Docker の Host(Linux らしい) の/var/lib/docker/volumes/
の下に作成・保存されるようです。 Docker の Host(Linux?)とは何だろうと思って調べると、Docker for Windows では Hyper-V を利用しますが、Hyper-V で Host の仮想マシンが Linux で作成されており、そのディスクの中に
/var/lib/docker/volumes/
ディレクトリがあるそうです。Hyper-V マネージャを起動するとMobyLinuxVM という仮想マシンがあり、
MobyLinuxVM の設定を表示するとハードドライブが存在して、この中に volume が作成されます。ハードドライブのデータは
C:\Users\Public\Documents\Hyper-V\Virtual Hard Disks\MobyLinuxVM.vhdx
のファイルに保存されるようです。C:\Users\Public\Documents\Hyper-V\Virtual Hard Disks
の下のファイルを見ようとしたところ、エラーが出て見れませんでした。Hyper-V で管理するファイルなので、アクセスできないように制限されているようです。またこのハードドライブには volume だけでなくダウンロードされた Docker Image(
docker image ls
コマンドで表示されます)等も保存されるようです。デフォルトで 60GB のサイズで作成されているのですが、Docker Image は 500MB くらいのものもあるので、いろいろやっていたらすぐに足りなくなりそうな気がします。
docker volume create
コマンドで作成した volume だと起動するのに、docker-compose.yml の volumes で直接 Windows のディレクトリと関連付けた場合には起動に失敗する理由とは?
Docker の Document の Logs and troubleshooting の「Volumes」 を読むと、以下の記載があります。
- shared volumes の permission のデフォルトは 0777。設定ファイルで事前に別の permission を設定しておくことはできない。
- Docker for Windows の場合、host-mounted volumes(docker-compose.yml の volumes で直接 Windows のディレクトリと関連付けたものがこれ)は Microsoft SMB protocol をベースに実装されており chmod で permission を変更することができない。
- デフォルト以外の permission で動作させる必要があるような場合には、non-host-mounted volumes(
docker volume create
コマンドで作成する volume がこれ)を使用するか、デフォルトの permission で動作するように変えること。
PostgreSQL の Docker Image の GitHub レポジトリである https://github.com/docker-library/postgres を見ると以下の処理が行われていました。
- Dockerfile-alpine.template の中で、
ENV PGDATA /var/lib/postgresql/data
により環境変数 PGDATA に/var/lib/postgresql/data
をセットしている。 - docker-entrypoint.sh の中で、
chmod 700 "$PGDATA"
を呼び出して/var/lib/postgresql/data
の permission を 0700 に変更しようとしている。また、その前にchown -R postgres "$PGDATA"
で owner を postgres に変更しようともしている。
FATAL: data directory "/var/lib/postgresql/data" has wrong ownership
のエラーメッセージだと permission というより onwer の問題のように思えます。おそらく host-mounted volumes だと owner も変更できないようなので試してみます。
docker-compose.yml を以下のように変更します。
postgresql: image: postgres:11.1-alpine container_name: postgresql ports: - "5432:5432" volumes: - postgresql-data:/test/non-host-mounted-volume - ./docker/postgresql/data:/test/host-mounted-volume environment: - POSTGRES_PASSWORD=xxxxxxxx restart: always volumes: postgresql-data: external: true
docker volume rm postgresql-data
、docker volume create --name postgresql-data
で postgresql-data volume を作り直してから(owner や permission の設定をデフォルトに戻します)、docker-compose up -d
コマンドでコンテナを起動して chown, chmod を試してみます。
- non-host-mounted volumes の permisson が 0777 ではなく 0755 でした。
- non-host-mounted volumes は owner も permission も変更できましたが、host-mounted volumes はどちらも変更できませんでした。
docker-compose.yml の volumes で直接 Windows のディレクトリと関連付けた場合に PostgreSQL の起動に失敗するのは、コンテナの起動時に実行される docker-entrypoint.sh が /var/lib/postgresql/data の owner、permission を変更しようとするが、Docker for Windows では owner も permission も変更できないためでした。
docker volume create
コマンドで作成された volume はコンテナから使用されていないと docker volume prune
コマンドで削除される
docker-compose.yml を以下の内容に変更してから
postgresql: image: postgres:11.1-alpine container_name: postgresql ports: - "5432:5432" volumes: - postgresql-data:/var/lib/postgresql/data environment: - POSTGRES_PASSWORD=xxxxxxxx restart: always volumes: postgresql-data: external: true
postgresql-data volume を作成し直した後、docker-compose up -d
コマンドでコンテナを起動します。
コンテナ起動中(volume も使用されている)に docker volume prune
コマンドを実行しても volume は削除されませんが、
docker-compose down
コマンドでコンテナを終了させてから、
docker volume prune
コマンドを実行すると全て削除されます。
docker volume create
コマンドで作成した volume に PostgreSQL のデータを保存すると、うっかり削除してしまう気がしますね。。。
ここまでのまとめ
- PostgreSQL のコンテナを起動する時にデータ保存ディレクトリをコンテナ外に配置したい場合には
docker volume create
コマンドで non-host-mounted volumes を作成して割り当てる必要がある。host-mounted volumes では owner, permission を変更できないのでコンテナが起動しない。 - ただし
docker volume create
コマンドで作成した volume はコンテナから使用されていない状態の時にdocker volume prune
コマンドが使用されると削除される。 docker volume create
コマンドで作成した volume は Docker の Host(Hyper-V の仮想マシン)のハードドライブに作成されてデータもその中に保存される。ハードドライブのサイズはデフォルトで 60GB だが、Docker Image も保存されるので PostgreSQL のデータも保存するならばサイズを増やした方がよいかもしれない。
データは Windows のディレクトリに保存したかったのですが、PostgreSQL の場合はあきらめて /var/lib/postgresql/data はコンテナをそのまま使用し、Web アプリ起動時に Flyway でテーブル作成+データ投入することにします。
Windows の共有フォルダを docker volume create
コマンドで作成した volume 経由でアクセスする
コンテナ --> Docker Host の volume --> Windows の共有フォルダ のように docker volume create
で作成した volume 経由でコンテナから Windows の共有フォルダにアクセスできる方法を見つけたので、まとめておきます。ちなみにこの方法で作成した volume は owner, permission を変更できないので、PostgreSQL コンテナ用には使えません。
コンピュータの管理を起動し、test ユーザを作成します(パスワードも test にしています)。
D:\tmp の下に data フォルダを作成し共有フォルダにします。





まずは docker run
コマンドでコンテナを起動して mount コマンドで共有フォルダをマウントしてみます。
docker run -dit --name alpine1 --cap-add=SYS_ADMIN alpine ash
コマンドを実行してコンテナを作成します。--cap-add=SYS_ADMIN
のオプションが必須です。付けないと共有フォルダをマウントできません。
コンテナに接続した後、apk update
、apk add --no-cache samba-client cifs-utils
を実行して samba-client と cifs-utils をインストールします。
smbclient -L 172.23.136.33 -U test
(172.23.136.33
は Windows PC の IPアドレスです)コマンドを実行し、data という共有フォルダがあることを確認します。
/data
ディレクトリを作成した後、mount -t cifs -o username=test,password=test,rw,vers=3.0 //172.23.136.33/data /data
コマンドを実行してマウントします。ファイルが作成できることも確認します。
作成した alpine1 コンテナを削除します。test.txt も削除します。
次は docker volume create
コマンドで作成した volume 経由でアクセスしてみます。コンテナは Docker Compose で作成します。
以下の docker volume create
コマンドを実行して data という名前の volume を作成します。
docker volume create \ --driver local \ --opt type=cifs \ --opt device=//172.23.136.33/data \ --opt o=username=test,password=test,rw,vers=3.0 \ --name data
D:\tmp の下に docker-compose.yml を作成し、以下の内容を記述します。
version: '3' services: alpine1: image: alpine container_name: alpine1 volumes: - data:/data entrypoint: ash cap_add: - SYS_ADMIN stdin_open: true tty: true volumes: data: external: true
docker-compose up -d
コマンドでコンテナを起動した後、ファイルが作成できることを確認します。
/data
ディレクトリに chown, chmod コマンドを実行しても owner, permission は変更されませんでした。
docker-compose down
コマンドを実行してコンテナを削除します。
この方法で作成された volume は docker volume prune
コマンドを実行しても削除されません。docker volume rm
コマンドで volume 名を指定しないと削除できません。
test2.txt の削除、フォルダ共有の解除、test ユーザの削除を行います。
履歴
2018/12/22
初版発行。