Rails + Docker Compose な環境を Docker for Mac から Vagrant  に移行する

# Docker for Mac を捨てたい

とある Rails プロジェクト (ここでは仮に `kemurikusa` プロジェクトとする) では、Rails サーバや Action Cable, Delayed Job, PostgreSQL を Docker Compose で動かすようにしている。僕のマシンは Mac なので、Docker を動かすのに Docker for Mac を使っている。しかし Docker for Mac を使っていて 2 つの致命的な問題に遭遇した。

ひとつは「com.docker.hyperkit プロセスの CPU 使用率が 150 〜 300% という高数値のままになってしまう」という問題だ。

[docker/for-mac » Issue #1759 » High CPU Utilization of Hyperkit in Mac](https://github.com/docker/for-mac/issues/1759)

上記の issue でも様々な議論がなされているが、僕の環境ではついぞ根本解決しなかった。

もうひとつはホストとコンテナ間のファイル共有が遅いという問題だ。

[docker/for-mac » Issue #77 » File access in mounted volumes extremely slow](https://github.com/docker/for-mac/issues/77)

これを解決するために [docker-sync](https://github.com/EugenMayer/docker-sync) というツールを使っていた。このツールではホストのファイルを直接マウントする代わりに、専用の外部ボリュームを用意して、そのボリュームとローカルを `rsync` などのツールを使って同期する仕組みだ。しかし、同期のタイミングにどうしてもラグが生じてしまうのがストレスだった。他にも設定ファイルで [cached](https://docs.docker.com/docker-for-mac/osxfs-caching/#cached) を使うという方法もあるが、docker-sync よりもパフォーマンスは劣っていた。

以上により Docker for Mac を使い続ける意思を完全に失ってしまった :sob:

# Vagrant への移行

## はじめに

Docker for Mac 以外の方法を模索していた結果 Vagrant で Linux 環境を構築して、そこで Docker Compose を動かすことにした。その結果、ホスト (Mac) とゲスト (Linux) のファイル共有の速度も速く、VirtualBox プロセスの CPU 使用率も落ち着いている。ゲスト OS は軽量と噂の CoreOS を採用した。

## 手順

前提として [VirtualBox](https://www.virtualbox.org/) と [Vagrant](https://www.vagrantup.com/) をインストールしておく必要がある。また `docker-compose.yml` から docker-sync に関する記述を消す。

```diff:docker-compose.yml
-      - src-sync:/src:nocopy
+      - .:/src

-  src-sync:
-    external: true
```

CoreOS に対応した `Vagrantfile` は [coreos/coreos-vagrant](https://github.com/coreos/coreos-vagrant) で提供されている。まず [ここ](https://github.com/coreos/coreos-vagrant/blob/master/Vagrantfile) から `Vagrantfile` をダウンロードして、Rails プロジェクトである `kemurikusa` プロジェクトのルートに配置する。

次に `Vagrantfile` を次のように書き換える。

🔽 VM のメモリを増やす。さもないと `bundle install` 時に Nokogiri のインストールで失敗した。

```diff:Vagrantfile
-$vm_memory = 1024
+$vm_memory = 2048
```

🔽 ポートフォワードの設定を行う。3000 は Rails、28080 は Action Cable のポート。

```diff:Vagrantfile
-$forwarded_ports = {}
+$forwarded_ports = { 3000 => 3000, 28080 => 28080 }
```

🔽 ホスト (Mac) の `kemurikusa` プロジェクトとゲスト (CoreOS) の `/home/core/kemurikusa` と同期する。

```diff:Vagrantfile
-      #config.vm.synced_folder ".", "/home/core/share", id: "core", :nfs => true, :mount_options => ['nolock,vers=3,udp']
+      config.vm.synced_folder ".", "/home/core/kemurikusa", id: "core", :nfs => true, :mount_options => ['nolock,vers=3,udp']
```

🔽 `Vagrantfile` の `(1..$num_instances).each` のブロック内のどこかに次の行を追加する。

```rb:Vagrantfile
config.vm.provision :shell, path: 'vagrant/provision.sh'
```

🔽 `kemurikusa` プロジェクトの `vagrant/provision.sh` に次のシェルスクリプトを配置する。このシェルスクリプトはゲスト (CoreOS) に docker-compose をインストールするためのもので、初回の `vagrant up` 時にのみ実行される。

```bash:vagrant/provision.sh
DOCKER_COMPOSE_VERSION="1.23.2"
mkdir -p /opt/bin
curl -s -L https://github.com/docker/compose/releases/download/$DOCKER_COMPOSE_VERSION/docker-compose-`uname -s`-`uname -m` > /opt/bin/docker-compose
chmod +x /opt/bin/docker-compose
docker-compose -v
```

ここまでで準備完了だ。あとは `vagrant up` を実行して VM を起動する。その後 SSH で VM にログインし、思う存分 docker-compose コマンドを実行すればいい :relaxed:

🔽 ホスト (Mac)

```bash
$ vagrant up
$ vagrant ssh
```

🔽 ゲスト (CoreOS)

```bash
$ cd kemurikusa
$ docker-compose up -d
```

# 参考

* [Docker for MacからVagrant + CoreOSに切り替えた](https://qiita.com/Ucan/items/545ce4d8e32580091bc9)
* [Mac上でDocker起動だけVagrant内で行い開発作業はすべてホスト側でするための手順](https://qiita.com/keik/items/1745f0726487760fb05f)