on
マルチOS対応Docker開発環境の作り方【Mac対応編】
この投稿は Magento Advent Calendar 2019 の11日目です。
皆さんDocker使ってますか?
以前はVirtualbox+Vagrantを使って開発環境を整えていたのですが、動きが遅い重い! 当時個人的に気になっていたDockerに(趣味半分で)乗り換えてみたところ、早い軽いで素晴らしいものでした。
私はもっぱらLinux(Ubuntu)をメインで使っているのですが、社内にはMacやWindowsを使っている開発者もいます。
せっかく作ったし他のOSでも使えるようにしよう、まずはMacで試してみよう!と思っていたところ、ある問題に阻まれてしまったのでした。
Docker for Macの欠点
Linuxで使っていたイメージや設定ファイルを移動させ、起動させるところまでは順調でした。 ですが…
明らかに動きが遅い……!!!
実はこの問題、Docker for Macでは有名で、以前私もこの問題を解決しようと悪戦苦闘していました。 Docker Meetup Kansai で発表したスライドがあるので、もし興味があればそちらもご覧ください。
このときは1/4程度しか改善されないという、早くはなったが実用的ではないという悲しい結果でした。
今回はその続きの話となります。
その後調べたところ、2つ効果があるかも知れない解決策を見つけることが出来ました。
NFS Sharing Volume
実は、dockerにはVolumeにNFSをマウントする機能があります。 ですが、Docker for Macの遅さはmacOSとLinuxコンテナのファイルシステムの違いが原因なので、NFS越しにマウントしたところで早くなるはず無いだろう…と思っていました。
ところが、
こちらの記事によるとNFS Volumeを使うことでかなり改善されることが判明しました。 なぜ早くなるのかは謎ですが、効果があるかも知れないなら試すしかありません!
Macでnfsdを動かすには、/etc/nfs.conf
と /etc/exports
を設定しておく必要があります。
#
# nfs.conf: the NFS configuration file
#
nfs.server.mount.require_resv_port = 0
/System/Volumes/Data/Users/{USERNAME}/{PASS_TO_PROJECTROOT} localhost -alldirs -mapall={uid}:{gid}
-mapall
オプションで指定したUIDとGIDは、NFSでアクセスした際に指定したユーザーのものとして扱われます。
macOS Catalinaをお使いの方には注意点が二点あって、一つは /Users/{USERNAME}
で始まるパスを指定してもエラーになってしまいます。
詳しくは以下の記事が参考になるかと思います。
もう一点は、DocumentsやDownloads、Desktop下を使う場合は明示的に権限を付与(?)しなくてはいけないようです。
以上が設定できれば sudo nfsd start
で起動するとホスト側の設定は終了です。
docker-compose.ymlの方にもNFSを使う設定をします。
version: "3"
services:
nfs:
image: ubuntu:18.04
volumes:
- src:/src:nocopy
volumes:
src:
driver: local
driver_opts:
type: nfs
device: ":/System/Volumes/Data/Users/{USERNAME}/{PASS_TO_PROJECTROOT}"
o: addr=host.docker.internal,rw,nolock,hard,nointr,nfsvers=3
services下のvolumesに :nocopy
を忘れず、driver_optsのdeviceにexportsで指定したパスを書くことを忘れずに!
これでNFS Volumeを使ったコンテナが起動できます✌️
欠点を挙げるとするならば、プロジェクトごとにdocker-compose.ymlにパスを書く必要があって手間という点です。 Gitで管理していたりすると、誤Pushとかがありそうで怖いですよね…。
Docker-sync
もう一つは高速にホストとコンテナ間を同期するためのツール、docker-syncです。
このツールは、ホストとコンテナ間でrsyncやunisonなどを使って高速な同期を実現しているようです。 rsyncの方が高速(?)のようですが同期が双方向ではなく一方通行(ホスト→コンテナ)なのがネックなので、今回はunisonを使ってみます。
brew install unison
brew install eugenmayer/dockersync/unox
gem install docker-sync
以上のコマンドでインストールが完了します。 詳しいインストール手順は公式ドキュメントをご覧ください。
docker-syncには docker-sync.yml
が必要になります。
version: "2"
syncs:
src:
src: '/{PASS_TO_PROJECTROOT}'
sync_strategy: 'unison'
sync_userid: '{UID}'
version: "3"
services:
nfs:
image: ubuntu:18.04
volumes:
- src:/src
volumes:
src:
external: true
docker-sync.ymlとdocker-compose.yml間でVolume名を統一しないと正しく起動しないので注意が必要です。 設定ファイルが準備できたら、
docker-sync start
このコマンドで起動してあげると、Volumeを作成して同期が開始されるという仕組みになっています。 Docker-syncを起動した状態でdockerコンテナにVolumeをマウントすると、ホスト-コンテナ間が同期されている状態になる、といった具合です。
Docker-syncの欠点は別途インストールが必要な点と、このコマンドを打つ手間があるところでしょうか。 起動しっぱなしでも良いのかも知れませんが、使い終わったら終わらせておきたい気もしますよね…🤔
測定
time dd if=/dev/zero of=/benchmark bs=1k count=100000
このコマンドで100MBのファイルを作成する時間を計測するベンチマークを取ってみました。
結果は…
- 通常のVolumeが約25秒
- NFS Volumeが約2.5秒
- Docker-syncが約0.35秒
と、Docker-syncの圧倒的勝利となりました! NFS Volumeもかなりはやいのですが、Docker-syncはほぼネイティブと変わらない速度ですね。
まとめ
いかがだったでしょうか?(殴)
NFSでもかなり早くで感動したのですが、Docker-syncはさらに早くてこんなにも違うのかと驚きました。
ここまでMagento Adventcalendarっぽく無い内容でしたが、Magento2はプロジェクトのファイル数がどうしても多くなってしまうので、読み書きのスピードはとても大事になってきます。 今回のこの結果を踏まえて次回、どうマルチOSに対応したdocker-compose.ymlを書くといいのかを書いていこうかと思います。