Docker for Macの代わりに、Vagrant + Dockerで開発環境を構築する

エンジニアの内山です。最近は家に引きこもって、どう森とスプラトゥーンを楽しんでいます。

今回は、Vagrant + Dockerで開発環境を構築する手順をご紹介します。

概要

Docker for Mac はパフォーマンスが悪いため、開発効率に悪くなってしまいます。原因については、以下を参照してください。

https://forums.docker.com/t/file-access-in-mounted-volumes-extremely-slow-cpu-bound/8076/158

Docker自体が遅いわけではないため、Linux上で動かした場合は、問題になりません。

この記事では、Docker for Macの代わりに、Vagrantで動作させているLinux上でDockerを使い、開発環境を構築する方法をご紹介しています。

手順は、以下の3ステップになります。

  1. VirtualBoxとVagrantをインストールする
  2. mutagenでファイル同期する
  3. Dockerを起動する

VirtualBox と Vagrantをインストールする

Homebrewを使用しようして、必要なツールをインストールしていきます。

https://brew.sh/

VirtualBoxとVagrantとUbuntuのイメージををインストールします。

$ brew cask install virtualbox
$ brew cask install vagrant
$ vagrant box add ubuntu/xenial64

Dockerとmutagen(後述)用のvagrantプラグインをインストールします。

$ vagrant plugin install vagrant-disksize vagrant-hostsupdater vagrant-mutagen vagrant-docker-compose

vagrantで初期化します。

$ vagrant init ubuntu/xenial64

次に、Vagrantファイルを作成しますが、Railsプロジェクトのディレクトリに作成する必要はありません。もし、プロジェクトのgitに含めたくない場合は、Vagrant実行用のディレクトリを作成して、そこにVagrantファイルを作成すると良いでしょう。

Vagrantファイルの内容は以下のようになります。

Vagrant.configure('2') do |config|
  config.vm.box = 'ubuntu/xenial64'

  config.vm.hostname = 'my-app'

  config.vm.network :private_network, ip: '192.168.50.10'

  config.vm.network "forwarded_port", guest: 80, host: 80

  config.vm.provider :virtualbox do |vb|
    vb.gui = false
    vb.cpus = 4
    vb.memory = 8192
    vb.customize ['modifyvm', :id, '--natdnsproxy1', 'off']
    vb.customize ['modifyvm', :id, '--natdnshostresolver1', 'off']
  end

  config.disksize.size = '30GB'
  config.mutagen.orchestrate = true

  config.vm.synced_folder '### PATH_TO_PROJECT ###', '/home/vagrant/app', type: 'rsync',
                                                                                                              rsync_auto: true,
                                                                                                              rsync__exclude: ['.git/', 'node_modules/', 'log/', 'tmp/', 'vendor']

  config.vm.provision :docker, run: 'always'
  config.vm.provision :docker_compose
end

### PATH_TO_PROJECT ### の部分を、プロジェクトディレクトリの絶対パスに変更してください。

以上で、Vagrant+VirtualBoxの準備は完了です。

mutagenでファイル同期する

編集したファイルをMacとLinuxで同期させます。mutagenというツールで実現します。

以下のコマンドで、mutagenをインストールします。

$ brew install mutagen-io/mutagen/mutagen

mutagenの設定ファイルmutagen.ymlを作成します。作成する場所は、Vagrantfileと同じディレクトリにしてください。内容は以下のようになります。

sync:
  app:
    mode: "two-way-resolved"
    alpha: "### PATH_TO_PROJECT ####"
    beta: "my-app:/home/vagrant/app"
    ignore:
      vcs: true
      paths:
        - "/node_modules"
        - "/log"
        - "/tmp"
        - "/vendor"

### PATH_TO_PROJECT ### の部分を、プロジェクトディレクトリの絶対パスに変更してください。

これで、mutagenの設定は完了です。mutagenはVagrantのプラグイン経由で実行されます。

Dockerを起動する

Vagrantで起動したLinuxにログインします。

$ vagrant up
$ vagrant ssh

Unable to monitor filesystemというエラーが発生する場合があるので、以下のコマンドを実行しておき、防止します。

$ echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

Vagrantの中で、Dockerを起動します。以下のコマンドは、プロジェクトディレクトリにdocker-compose.ymlが存在している場合の例です。

$ cd app
$ docker-compose up

以上で、完了です。

体感的に、Docker for Macよりも高速に実行されていることが確認できると思います。

他の改善方法

Docker for Macのパフォーマンス改善に関する方法は、他にも以下のようなものがあります。

Macを使わずにLinux PCを使う

Macにこだわらなければ、LinuxPCを使うことも選択肢の一つです。移行コストが気にならなければ、この方法を選択できます。

docker-syncを使う

未検証ですが、docker-syncを使う方法もあるそうです。
https://github.com/EugenMayer/docker-sync/wiki

Dockerを使わない

そもそもDockerを使わない選択肢もあります。この方法は、チームのメンバー間で環境差異が出るのが懸念点です。しかし、フロントエンド開発であれば、ほとんど問題ないかもしれません。

フロントエンドの開発環境に Docker は不要(少なくともMacでは)
https://mizchi.hatenablog.com/entry/2019/04/07/074634

バックエンド開発については、DBなどのコンポーネントが必要な場合が多いため、Dockerはほぼ必須かと思います。

おわりに

Docker for Macのパフォーマンスは、開発効率にかなりの悪影響を及ぼすレベルです。開発を進める前に、改善することをおすすめします。

参考