マルチ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 で発表したスライドがあるので、もし興味があればそちらもご覧ください。

Docker開発環境のMac対応に苦戦した話.jpg Docker開発環境のMac対応に苦戦した話

このときは1/4程度しか改善されないという、早くはなったが実用的ではないという悲しい結果でした。

今回はその続きの話となります。

その後調べたところ、2つ効果があるかも知れない解決策を見つけることが出来ました。

NFS Sharing Volume

実は、dockerにはVolumeにNFSをマウントする機能があります。 ですが、Docker for Macの遅さはmacOSとLinuxコンテナのファイルシステムの違いが原因なので、NFS越しにマウントしたところで早くなるはず無いだろう…と思っていました。

ところが、

Docker for Mac でも快適な Symfony 開発環境を作りたい

こちらの記事によると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} で始まるパスを指定してもエラーになってしまいます。 詳しくは以下の記事が参考になるかと思います。

macOS CatalinaからNFS exportsするには

もう一点は、DocumentsやDownloads、Desktop下を使う場合は明示的に権限を付与(?)しなくてはいけないようです。

Docker: the Problem with MacOS Catalina

以上が設定できれば 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です。

http://docker-sync.io/

このツールは、ホストとコンテナ間で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のファイルを作成する時間を計測するベンチマークを取ってみました。

結果は…

と、Docker-syncの圧倒的勝利となりました! NFS Volumeもかなりはやいのですが、Docker-syncはほぼネイティブと変わらない速度ですね。

まとめ

いかがだったでしょうか?(殴)

NFSでもかなり早くで感動したのですが、Docker-syncはさらに早くてこんなにも違うのかと驚きました。

ここまでMagento Adventcalendarっぽく無い内容でしたが、Magento2はプロジェクトのファイル数がどうしても多くなってしまうので、読み書きのスピードはとても大事になってきます。 今回のこの結果を踏まえて次回、どうマルチOSに対応したdocker-compose.ymlを書くといいのかを書いていこうかと思います。

次 → マルチOS対応Docker開発環境の作り方【docker-compose編】