#追記 20170407 Docker for Macでconsistencyを指定することでパフォーマンスを改善できるようになりました。
unisonを使わなくても本体の機能である程度解決できるようになりました。
下記の計測してるので参照ください。
http://qiita.com/kai-zoa/items/5f38909d37e0e4e36a28
#元記事
この記事はWHITEPLUS Advent Calendar 2016 24日目になります。
開発環境整備担当兼クリーニング師の kai-zoa です。
20日目に書いたDocker for Macのファイル共有が遅いので計測してみるでdocker-for-mac公式は問題を認識しているが優先度低いという旨のコメントを頂いたので、なにかしら対策を講じたい気持ちになり調査しました。
すでにdocker-syncを使う方法は他の方が紹介されているので、今回は使わない方法について書きたいと思います。
実際に開発環境に組み込んでデザイナー・エンジニアの両チームに共有するのにあらかじめrubyを入れてもらったり、gemを使えるようにしてもらうのが面倒くさい方にオススメです。(というのが私の都合です)
環境はmacOSです。
#unisonを使います
いきなりですが、これが答えです。
docker-syncでも使われていますが、同じようにunisonを使ってホストとコンテナのファイルシステムを相互同期します。
DockerHubにalpineベースのシンプルなunisonサーバーのDockerイメージがあったので参考にしました。
onnimonni/unison
このようにunisonサーバーをデータコンテナーにして、同期するディレクトリはアプリケーション側のボリュームにマウントします。
docker-composeの定義はこんな感じです。
version: '2'
services:
data:
image: whiteplus/unison
container_name: piyo_data
volumes:
- /var/www/piyo
ports:
- "5000:5000"
environment:
- UNISON_DIR=/var/www/piyo
web:
container_name: piyo_web
build: .
depends_on:
- data
volumes_from:
- data
ports:
- "80:80"
- "443:443"
environment:
- NGINX_PATH_PREFIX=/var/www/piyo
※ データコンテナー側にinotify-toolsを入れたかったのでonnimonni/unisonに手を入れてwhiteplus/unisonにしてます。
全ソースはこちら
github.com/WHITEPLUS/advent-calendar2016-docker-unison-example
#動作確認
起動します。
$ docker-compose up -d
起動直後はプロジェクトのファイルを同期してないのでwebにアクセスすると404になります。
$ open http://localhost
##ホストのファイルをデータコンテナに同期する
それではunisonクライアントをインストールして、./webappのソースをデータコンテナに同期してみます。
$ brew install unison
$ unison ./webapp socket://127.0.0.1:5000/ -auto -batch
Contacting server...
Connected
〜
Waiting for changes from server
Reconciling changes
dir ----> html
Propagating updates
〜
Synchronization complete at 21:12:35 (2 items transferred, 0 skipped, 0 failed)
$ open http://localhost #開いてみる
WAO! ちゃんと表示されました
##データコンテナからファイルを編集して同期する
それでは逆にデータコンテナからファイルを編集して同期してみましょう
$ docker exec -it piyo_data sh # データコンテナに入る
$ cd /var/www/piyo/html/
$ echo PIYOPIYO > index.html #データコンテナからファイルの内容を変更
$ exit
$ unison ./webapp socket://127.0.0.1:5000/ -auto -batch #同期
Contacting server...
Connected
〜
Looking for changes
Waiting for changes from server
Reconciling changes
<---- changed html/index.html
Propagating updates
〜
Synchronization complete at 21:21:53 (1 item transferred, 0 skipped, 0 failed)
$ cat ./webapp/html/index.html #変更がホストに反映されてることを確認する
PIYOPIYO
WAO! うまくいきました
#ファイル変更を監視して同期する
ここまでできたら、ホストとコンテナでお互いのファイル変更イベントを検知して、unisonを動かすようにすれば完璧ですね。
そこでお互いのinotifyイベントを監視して、ホスト側にログ出力し、tailからxargsでunisonに繋ぐスクリプトを書いてみました。(githubの方にもコミットしています)
unison-fsmonitorをmacOSに入れればこんなもの必要ないかもしれないですがまだ試してません
#! /usr/bin/env bash
LOCAL_DIR=./webapp
REMOTE_DIR=/var/www/piyo
REMOTE_CID=piyo_data
recv_local() {
while read -r event; do
test -n "${event}" && \
echo "LOCAL: ${event}" >> events.log
done
}
recv_remote() {
while read -r event; do
event=$(echo -n $event \
| grep -E '(CREATE|MOVE|MOVED_TO|MOVED_FROM|MODIFY|ATTRIB|DELETE|DELETE_SELF)[,:]' \
| sed -e 's/^[A-Z,_]*://g' \
| tr -d '\n')
test -n "${event}" && \
echo "REMOTE: ${event}" >> events.log
done
}
UNISON="unison ${LOCAL_DIR} socket://127.0.0.1:5000/ -auto -batch"
${UNISON}
rm -f events.log
touch events.log
fswatch ${LOCAL_DIR} 2>&1 | recv_local &
CHILDREN=$!
docker exec -it ${REMOTE_CID} inotifywait -m -r --format '%e:%w%f' ${REMOTE_DIR} 2>&1 | recv_remote &
CHILDREN="${CHILDREN} $!"
trap "kill -KILL ${CHILDREN} > /dev/null 2>&1" INT TERM
tail -f ./events.log | xargs -I{} ${UNISON}
実行するとホストとコンテナ双方のファイル監視と同期をし続けてくれます。
$ ./sync.sh
〜
#積み残し
上記スクリプトだとunisonが同期した結果のファイル変更イベントを検知してunisonが起動するという無駄な動きもしてしまうので改良の余地があるなと思いました。
これ以上、並行処理でなんやかんややるならGoで書きたいですね‥
その前にfsmonitorを使った場合の動作確認をしよう!
#明日
exmeatのmeatの話ですっ
#ホワイトプラスではエンジニアを募集しています
ホワイトプラスでは、新しい技術にどんどん挑戦したい!という技術で事業に貢献したいエンジニアを募集しております。!