このお話は、boot2docker1.4.1で行っています。
- 2017-02-28追記あり
複数の開発環境を素早く用意したり、他の人も同じ環境を用意するとか何かと便利なDocker。
PHPバージョンが違う環境のWEBサーバを複数手早く立ち上げたりとか今までの苦労を考えると画期的。
データベースだってMySQL使ってたりPostgreSQL使ってたり色々あっても大丈夫。
Mac(多分Windowsも一緒)で動かすには、直接動かすことができないのでVirtualBoxを経由して稼働させることになる。
そこで問題となるのがファイルの永続化。
そもそもDockerのコンテナを終了すると、全てがなかったことになる。次回立ち上げればクリーンな状態なので良いのだけど。
Dockerコンテナ内でソースコード編集を行っても、コンテナ終了してしまえばなかった事になってしまうのだ!
そんな時にはコンテナ実行時に -v オプションでホストOSのディレクトリ指定すれば、指定したディレクトリをマウントするような感じで利用できる。コンテナ終了してもホストOSにデータが残るので、次にコンテナ立ち上げる時に同じ-vオプションを指定すれば再開できるのだ。
ここまではDockerの仕組みで特に問題はない。ただ、boot2dockerで実行している環境では、コンテナから見たホストOSはVirtualBox上で動いているOS(以降boot2dockerOSと表記)になる。
このOSがコンテナっぽい動きをして、boot2dockerOSを終了させると綺麗に戻ってしまう。保存したはずのファイルがいなくなるのだ。
そこでVitrualBoxの共有フォルダ機能を利用して本家ホストOS(Mac)のディレクトリをコンテナのホストOS(boot2dockerOS)にマウントさせる。そこからさらにコンテナにマウントさせればよさげ。
そうすればboot2dockerOSを終了してもMacOSにファイルが残るので次回からも使える。
標準状態でMacローカルの /Users ディレクトリが、boot2docerOSの /Users ディレクトリにマウント済みなので、特に設定しなくてもファイル永続化が簡単にできるようになっているのだ。
うんうん。問題解決だね。
これができれば、エディタとか開発ツールはお気に入りをホストOSであるMacOSで起動させて開発できる。
実際にPHPを走らせるのはDockerコンテナなので、複数のバージョン違いのサイト開発も快適に。
データベースも同じ方式にすれば、一々初期データ投入する手間もないし、作成したレコードも残るね。
現状のパーミッションは?
が。
通常使用に際して特に問題は無いんだけど、例えばPostgreSQLのデータファイルを永続化させたい場合などは問題となる。
uid=1000(docker) gid=50(staff)所有で755固定でパーミッション設定されている。
$ ls -l
drwxr-xr-x 1 docker staff 306 Jan 7 01:59 Users/
保存用ディレクトリのパーミッションが postgres:postgres 600 でないとだめなのだ。
boot2dockerOSから chmod
コマンド実行してもパーミッション変更することができない!!
対応策
VirtualBoxの共有フォルダ設定
困ったのぅ。
そんな時は、Macローカルディレクトリをboot2dockerOSでパーミッション指定してマウントする。そんな事ができる。
事前準備として、マウントさせたいMacローカル上のディレクトリをVirtualBoxで共有フォルダ設定しておく。
VBoxManage sharedfolder add boot2docker-vm -name {共有名} -hostpath {MaxOS上のパス}
コマンドで設定。
MacOS上の /path/to/pgsql ディレクトリを volume-pgsql って命名して共有させるには以下のコマンドを実行。
VBoxManage sharedfolder add boot2docker-vm -name volume-pgsql -hostpath /path/to/pgsql
まぁGUIの設定画面からもできると思うけど、boot2dockerいじってる人ってターミナルで実行してるよね。
パーミッション指定してマウント実行
これで準備は整ったので、boot2dockerOSでマウントさせる。
まず boot2docker ssh
でログインしてから modprobe vboxsf
と mount -t vboxsf -o uid={uid},gid={gid},dmode={ディレクトリmod},fmode={フィアルmod} {VirtualBox共有名} {マウント先パス}
コマンド実行すればよい。
先ほど設定した共有フォルダを/var/lib/pgsql ディレクトリにpostgres:postgres でディレクトリを700、ファイルを600でマウントさせる。
yumなどからそのままインストールすれば、postgresユーザー、グループ共に IDが26 でインストールされるのでuidとgidを26で指定。
[macos]$ boot2docker ssh
[boot2docker]$ modprobe vboxsf
[boot2docker]$ mkdir -p /var/lib/pgsql
[boot2docker]$ mount -t vboxsf -o uid=26,gid=26,dmode=700,fmode=600 volume-pgsql /var/lib/pgsql
これで docker run -v /var/lib/pgsql:/var/lib/pgsql pgsql
コマンドにその他必要なオプション指定で立ち上げればいい。
でもね。
boot2dockerOSを一度シャットダウンさせると、せっかくしたマウントがなかったことに。/etc/fstab に記載してもダメ。
マウントの永続化で解決
そこで。
boot2dockerOS の /var/lib/boot2docker/bootlocal.sh にマウントコマンドを記載する。
この /var/lib/boot2docker ディレクトリ内の変更は初期化されないのでずっと生き続けてくれる仕様。
そこにある bootlocal.sh シェルクスリプトがあればboot2docker起動した際に実行してくれる仕様になっている。
# !/bin/sh
# ----------------------------------------------
# パーミッション指定して永続化ディレクトリをマウント
# ----------------------------------------------
modprobe vboxsf
mount_dir=/var/lib/pgsql
mkdir -p $mount_dir
mount -t vboxsf -o uid=26,gid=26,dmode=700,fmode=600 volume-pgsql $mount_dir
これをWEBコンテンツ(PHPのコードとか)のhtdocsディレクトリもマウントさせてWEBサーバの設定すればできるね。
最初の目標通り、MacOS上で開発してDockerコンテナで実行確認できる!
複数のWEB環境を同時に立ち上げたい場合は、リバースプロキシ用のコンテナを用意して、各環境のコンテナを立ち上げたりするとこれ最強。
この辺は気が向いたときにでも書くかな。
initdbできない
これで悩みは解決さ!
と、思うでしょ?
VirtualBoxの共有フォルダはシンボリックリンクが扱えないの。
扱える設定があるってどっかにあった気がしたけど・・・
とりあえずこれが原因で initdb
コマンドが謎のエラーでこけるっぽい。
一旦/tmpディレクトリとかvolume設定していないディレクトリを対象に initdb
コマンド実行して、出来上がったファイルをvolume設定しているディレクトリに移動させた後PostgreSQLサーバを起動させることで問題回避できた。
いずれはシンボリックリンクも扱えるようにしないと・・・
2017-02-28追記
この時は気づかなかったけど、volumeオプションをちゃんと利用すればもっといい方法があった。
ソースコードの様なMac側で変更を加えた物を、コンテナ環境でコンパイルや実行させるみたいな状況ではこの方法がよさそうだけど
DBのような書き換えが頻繁に行われるけど、コンテナからの操作だけで事足りる場合では別の方法がよい。
内容はここに書いた。
http://qiita.com/ll_kuma_ll/items/f182aaadb0368fa5a20b
そうすれば、initdb
コマンドでこけることもないし、かなり安定稼働する。