かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

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 ってどこに保存されるのか?、そもそもなぜ失敗するのか?、を調べてみました。

参照したサイト・書籍

  1. Docker for Windowsでpostgresのデータマウントができない人へ
    https://qiita.com/kyo-bad/items/47b96883144a5bf1cb1e

  2. docker volume create
    https://docs.docker.com/engine/reference/commandline/volume_create/

  3. Where are images stored?
    https://forums.docker.com/t/where-are-images-stored/9794

  4. Use volumes
    https://docs.docker.com/storage/volumes/

  5. Manage data in Docker
    https://docs.docker.com/storage/

  6. Docker storage drivers
    https://docs.docker.com/storage/storagedriver/select-storage-driver/

  7. Logs and troubleshooting
    https://docs.docker.com/docker-for-windows/troubleshoot/

  8. LinuxからSambaをマウントする
    https://qiita.com/dojineko/items/e6c21f3fe309b5aae694

  9. How 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#848166

  10. Interactive shell using Docker Compose
    https://stackoverflow.com/questions/36249744/interactive-shell-using-docker-compose

目次

  1. Docker Compose で単体の PostgreSQL サーバの環境を構築してみる
  2. docker volume create コマンドで作成した volume はどこにあるのか?
  3. docker volume create コマンドで作成した volume だと起動するのに、docker-compose.yml の volumes で直接 Windows のディレクトリと関連付けた場合には起動に失敗する理由とは?
  4. docker volume create コマンドで作成された volume はコンテナから使用されていないと docker volume prune コマンドで削除される
  5. ここまでのまとめ
  6. 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 というエラーが出てコンテナが起動しません。

f:id:ksby:20181222094913p:plain

調べてみると Docker for Windowsでpostgresのデータマウントができない人へ という記事を見つけました。この記事を参考にして、まずは docker volume create --name postgresql-data コマンドで volume を作成してから、

f:id:ksby:20181222095849p:plain ※実際には 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 コマンドを実行すると今度は起動しました。

f:id:ksby:20181222100844p:plain

起動はしたのですが、以下の疑問点が浮かびました。

  • 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 DockerVolumes 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 マネージャを起動すると

    f:id:ksby:20181222103417p:plain

    MobyLinuxVM という仮想マシンがあり、

    f:id:ksby:20181222103510p:plain

    MobyLinuxVM の設定を表示するとハードドライブが存在して、この中に volume が作成されます。ハードドライブのデータは C:\Users\Public\Documents\Hyper-V\Virtual Hard Disks\MobyLinuxVM.vhdx のファイルに保存されるようです。

    f:id:ksby:20181222103702p:plain

    C:\Users\Public\Documents\Hyper-V\Virtual Hard Disks の下のファイルを見ようとしたところ、エラーが出て見れませんでした。Hyper-V で管理するファイルなので、アクセスできないように制限されているようです。

    f:id:ksby:20181222104054p:plain

  • またこのハードドライブには 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-datadocker volume create --name postgresql-datapostgresql-data volume を作り直してから(owner や permission の設定をデフォルトに戻します)、docker-compose up -d コマンドでコンテナを起動して chown, chmod を試してみます。

f:id:ksby:20181222142348p:plain

  • 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 コマンドでコンテナを起動します。

f:id:ksby:20181222151527p:plain

コンテナ起動中(volume も使用されている)に docker volume prune コマンドを実行しても volume は削除されませんが、

f:id:ksby:20181222151738p:plain

docker-compose down コマンドでコンテナを終了させてから、

f:id:ksby:20181222151929p:plain

docker volume prune コマンドを実行すると全て削除されます。

f:id:ksby:20181222152110p:plain

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 にしています)。

f:id:ksby:20181222191537p:plain

D:\tmp の下に data フォルダを作成し共有フォルダにします。

f:id:ksby:20181222201000p:plainf:id:ksby:20181222201127p:plainf:id:ksby:20181222201257p:plain
f:id:ksby:20181222201400p:plainf:id:ksby:20181222201527p:plain

まずは docker run コマンドでコンテナを起動して mount コマンドで共有フォルダをマウントしてみます。

docker run -dit --name alpine1 --cap-add=SYS_ADMIN alpine ash コマンドを実行してコンテナを作成します。--cap-add=SYS_ADMIN のオプションが必須です。付けないと共有フォルダをマウントできません。

f:id:ksby:20181222202309p:plain

コンテナに接続した後、apk updateapk add --no-cache samba-client cifs-utils を実行して samba-client と cifs-utils をインストールします。

f:id:ksby:20181222202508p:plain f:id:ksby:20181222202722p:plain

smbclient -L 172.23.136.33 -U test172.23.136.33Windows PC の IPアドレスです)コマンドを実行し、data という共有フォルダがあることを確認します。

f:id:ksby:20181222203454p:plain

/data ディレクトリを作成した後、mount -t cifs -o username=test,password=test,rw,vers=3.0 //172.23.136.33/data /data コマンドを実行してマウントします。ファイルが作成できることも確認します。

f:id:ksby:20181222204029p:plain f:id:ksby:20181222204226p:plain

作成した 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

f:id:ksby:20181222205411p:plain

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 コマンドでコンテナを起動した後、ファイルが作成できることを確認します。

f:id:ksby:20181222211518p:plain f:id:ksby:20181222211616p:plain

/data ディレクトリに chown, chmod コマンドを実行しても owner, permission は変更されませんでした。

f:id:ksby:20181222211949p:plain

docker-compose down コマンドを実行してコンテナを削除します。

この方法で作成された volume は docker volume prune コマンドを実行しても削除されません。docker volume rm コマンドで volume 名を指定しないと削除できません。

f:id:ksby:20181222213250p:plain

test2.txt の削除、フォルダ共有の解除、test ユーザの削除を行います。

履歴

2018/12/22
初版発行。