きなこもち.net

.NET Framework × UiPath,Orchestrator × Azure × AWS × SIer

Docker for Windows × postgres × /var/lib/postgresql/dataがWindowsのフォルダにマウントできない件について

この記事の目的

この記事では、
Docker for Windowsでpostgesのデータディレクトリを
Windowsディレクトリにマウントしようとして
頑張ったときの情報をまとめること
を目的としています。


本題

★要約

環境

f:id:kinakomotitti:20190614160214p:plain

ことのはじまり

「ローカル環境にPostgresの環境を構築したい。」
「どこでも同じ環境を構築できるようにしたい。」
「Postgresをローカル環境に入れたくない。」

という気持ちから、PostgresをDockerで用意することにしました。
この時、データの永続化は別に必須ではなかったですが、
できることなら永続化しておこうと思ったのが、このトラブルの発端です。

起こった現象

任意の場所にPostgresのデータをマウントするためのディレクトリを作成し、
そこにマウントするようにDocker runしました。

 mkdir C:\postgres
 docker run -d -v "C:\postgres":/var/lib/postgresql/data postgres:11.3

陽気に↑を実行すると、以下のエラーが発生し、
指定したディレクトリに一瞬現れたpostgresのデータファイルが消されました。

running bootstrap script ... 2019-06-14 06:49:00.898 UTC [77] FATAL:
data directory "/var/lib/postgresql/data" has wrong ownership

2019-06-14 06:49:00.898 UTC [77] HINT:
The server must be started by the user that owns the data directory.

child process exited with exit code 1

initdb: removing contents of data directory "/var/lib/postgresql/data"

このエラーに対し、Githubの情報*1も参考に調査を進めました。

結論

とりあえず、先に結論的対応をまとめておきます。

Step1)対象のDocker Volumeを作成する。
※明示的に作成しなくても、なければDocker run時に勝手に作ってくれます。
[volume name]は任意の値を入れます。ここでは、db-data という名前で進めました。

Docker create volume [volume name]


Step2)Docker runする

docker run -d -v db-data:/var/lib/postgresql/data postgres:11.3


これで、作成されたコンテナの/var/lib/postgresql/dataディレクトリが、
Docker Volumeのdb-dataにマウントされ、
コンテナを消しても、データが消えない(永続化)ができるようになりました。

めでたしめでたし・・・?


★補足情報

そもそも/var/lib/postgrsql/dataがマウントできなかった原因について

GithubのIssueから、Docker for Windows では、
特定の権限を持つディレクトリをマウントできないということと、
ほかにも同じ現象で困っていることがわかりました(/・ω・)/

技術的な原因は把握できていませんが、これがすべて・・・なのかな。

For the time being, this won't work.
You should either just use in-container storage or use a volume not mounted from your Windows host.

docker volumeのdb-dataの実体

無事にデータを永続化しながらdocker runをすることができましたが、
永続化したファイルたちはどこにいるのか。
という点についてもう少し探ってみました。

docker volumeの詳細な設定情報は、以下のコマンドで確認することができます。

docker volume ls
>DRIVER              VOLUME NAME
>local               db-data

docker volume inspect db-data
>[
>    {
>        "CreatedAt": "2019-06-14T06:34:48Z",
>       "Driver": "local",
>        "Labels": null,
>        "Mountpoint": "/var/lib/docker/volumes/db-data/_data",
>        "Name": "db-data",
>        "Options": null,
>        "Scope": "local"
>    }
>]

この情報から、どこかしらの
"/var/lib/docker/volumes/db-data/_data"ディレクト
にマウントされていることがわかります。

Docker for WindowsLinux用機能は、Hyper-v上に構築された
MobyLinuxVMというマシン上で動いています。
そのため、上記で得られたディレクトリは、
MobyLinuxVMのディレクトリであるということがわかります。


ここで、MobyLinuxVMマシンに入って実際のディレクトリを確認したい気持ちが出てきました。
Hyper-vマネージャーから接続できるかと思いきや、そんなことはできませんでした。


そのため、この記事を参考にして、コンテナのホストへアクセスしてみました。
qiita.com

記事に従い、Dockerfileを作成し、コンテナにアクセスしたときの状態がこちらになります。

docker run -it --privileged --pid=host hostenter /bin/sh
/ # ls
>EFI         dev         lib         proc        sendtohost  usr
>bin         etc         media       root        srv         var
>boot        home        mnt         run         sys
>containers  init        opt         sbin        tmp

ホストの名前空間に特権ユーザーでアクセスしているため、
以下のディレクトリが参照できるようになっているらしいです。
正直ここら辺はあやふやです(;´Д`)
EFI、sendtohost、varboot、containers、init

目的のpostgresのデータは、"/var/lib/docker/volumes/db-data/_data"にあるので、
dockerコンテナにアクセスした状態で、中を確認してみます。

ls /var/lib/docker/volumes/db-data/_data
>PG_VERSION            pg_ident.conf         pg_snapshots          pg_wal
>base                  pg_logical            pg_stat               pg_xact
>global                pg_multixact          pg_stat_tmp           postgresql.auto.conf
>pg_commit_ts          pg_notify             pg_subtrans           postgresql.conf
>pg_dynshmem           pg_replslot           pg_tblspc             postmaster.opts
>pg_hba.conf           pg_serial             pg_twophase           postmaster.pid

無事、マウントされたファイルたちを見ることができました。
マウントされたファイルに何かする用事はないですが、
実体がどこにあるか確認しないと不安でしょうがないときは、
こうやって確認することができますね!

その他の方法について

※失敗した方法です。
postgresでも、ほかのディレクトリ(ex. /mnt)は、Windowsディレクトリでマウントすることができます。ということは、postgresのイメージを実行する前に、問題となっているディレクトリの権限、所有者、所有グループをまとめて変更しておけばマウントできるのではないかと考えました。

//postgresのコンテナにアクセスしたときのフォルダ権限の状態

//問題のディレクトリ
root@ee8c8156c478:/# ls -ld /var/lib/postgresql/data
>drwxrwxrwx 2 root root 8192 Jun 14 07:46 /var/lib/postgresql/data

//問題のディレクトリの親ディレクトリ
root@ee8c8156c478:/# ls -ld /var/lib/postgresql/
drwxr-xr-x 1 postgres postgres 4096 Jun 10 23:51 /var/lib/postgresql/

//マウントできるディレクトリ
root@ee8c8156c478:/# ls -ld /mnt
drwxr-xr-x 2 root root 4096 Jun 10 00:00 /mnt

結果、このアプローチでは、同じエラーが発生したため、うまくいきませんでした。。。

まとめ

docker for windowsでpostgresのデータを永続化するには、dokcer volumeを利用する。
永続化したデータは、Hyper-v仮想マシン上に存在する。