ItamaeとVagrantで作るRails検証環境 on Ubuntu

# 概要
Railsで開発を行っていると、基本的な動作の検証を行いたくなることが度々あるのですが、
自前の環境がカスタマイズされすぎて、一般的な環境で成り立つのかわからないので、
検証できる環境を簡単に作れるようにしました。
今回は、RSpecの基本動作を検証したかったので、Railsは最小限の構成になっています（DBも設定していません）。

# 環境
## ローカル
- Mac OS X Yosemite 10.10.5
- Ruby 2.0.0p481（Yosemite標準）
- Vagrant
- VirtualBox

## 構築先
執筆時点のバージョンです。

- Ubuntu 16.04.1
- Ruby 2.3.1p112
- Rails 5.0.0.1

# 構築手順
何かよくわからんけど、とりあえず構築したいという人はこちらの手順を参照してください。
## リポジトリをclone
```
git clone https://github.com/AmatsukiKu/rails_experiment
```
予め必要なファイル群などをリポジトリに上げておいたので、
こちらを利用してください。

## Itamaeの準備
```bash
cd rails_experiment
bundle install --path vendor/bundle
```

## Vagrantの準備
```bash
brew update
brew install cask
brew cask install vagrant virtualbox
vagrant plugin install vagrant-vbguest vagrant-hosts vagrant-hostsupdater vagrant-triggers vagrant-itamae
```
Homebrewがインストールされていることを前提としています。

## Ubuntuイメージの準備
```bash
cd rails_experiment/vagrant
vagrant init ubuntu/xenial64; vagrant up --provider virtualbox
```

## Ubuntu側の設定
```bash
cd rails_experiment/vagrant
vagrant provision
```

## 動作確認
```bash
cd rails_experiment/vagrant
vagrant ssh
# ここからUbuntu内
cd rails_experiment
bundle exec rails s -b 0.0.0.0
```
この状態でMac側のブラウザでlocalhostにアクセスします。
<img width="1552" alt="hello_rails.png" src="https://qiita-image-store.s3.amazonaws.com/0/54957/6fb35df8-9b78-aaab-7a98-bac8bce6a833.png">


### RSpecの動作確認

```bash
cd rails_experiment
bundle exec rails generate controller Welcome index --assets=false
bundle exec rspec spec/controllers/welcome_controller_spec.rb
```

## 検証
好きにいじって、検証してください。

## 作業の終了
```bash
# Mac側
cd rails_experiment/vagrant
vagrant halt
```

## イメージの破棄
```bash
# Mac側
cd rails_experiment/vagrant
vagrant destroy
```

# 解説
## Itamae
[Itamae](https://github.com/itamae-kitchen/itamae)はChefやAnsibleに代表されるサーバー設定ツールの一つです。
設定ファイルをRubyで記述でき、機能がシンプルなのが特徴です。
今回は、Ubuntu上のRubyのインストールや、Railsの初期化といった作業の自動化に使いました。

```rails_experiment/recipe.rb 
package 'ruby2.3'

# nokogiriのインストールに必要
package 'build-essential'
package 'patch'
package 'ruby-dev'
package 'zlib1g-dev'
package 'liblzma-dev'

gem_package 'rails'

execute 'rails new' do
  not_if 'ls rails_experiment'
  command 'rails new rails_experiment -O -J -T -S'
  user 'ubuntu'
  cwd '/home/ubuntu'
end
execute 'append rspec-rails to Gemfile' do
  not_if 'grep rspec-rails Gemfile'
  command 'echo "gem \'rspec-rails\'" >> Gemfile'
  user 'ubuntu'
  cwd '/home/ubuntu/rails_experiment'
end
execute 'bundle install' do
  command 'bundle install'
  user 'ubuntu'
  cwd '/home/ubuntu/rails_experiment'
end
execute 'generate rspec:install' do
  not_if 'ls spec'
  command 'bundle exec rails generate rspec:install'
  user 'ubuntu'
  cwd '/home/ubuntu/rails_experiment'
end
```

Itamaeでは必要なリソースを記述することで、設定を行います。
リソースはいくつか種類があり、必要に応じて使い分けます。
上のコード中のpackage, gem_package, executeがそれに当たります。
リソースの種類は、[こちら](https://github.com/itamae-kitchen/itamae/wiki/Resources)にまとまっています。

上のコードでは、まず、Railsのインストールに必要なパッケージをインストールし、
その後、各コマンドによってRailsの初期化を行うことが記述されています。

## Vagrant
[Vagrant](https://www.vagrantup.com/)は仮想マシンを使って再生成可能な開発環境を簡単に作るためのツールです。
今回は、OSイメージのダウンロードやネットワークの設定などに使いました。
Vagrantで作った環境にはすぐsshできる、というのも利点の一つです。

```rails_experiment/Vagrantfile
Vagrant.configure('2') do |config|
  config.vm.box = 'ubuntu/xenial64'
  config.ssh.username = 'ubuntu'

  config.vm.provision :itamae do |itamae|
    itamae.recipes = ['../recipe.rb']
  end

  config.vm.network :forwarded_port, guest: 3000, host: 3080
  config.vm.network 'private_network', ip: '192.168.33.10', auto_config: true

  # 127.0.0.1:80をboxの中に転送する
  config.trigger.after [:provision, :up, :reload] do
    system('echo "
rdr pass inet proto tcp from any to 127.0.0.1 port 80 -> 127.0.0.1 port 3080
" | sudo pfctl -ef - > /dev/null 2>&1; echo "==> Fowarding Ports: 80 -> 3080"')
  end

  config.trigger.after [:halt, :destroy] do
    system("sudo pfctl -f /etc/pf.conf > /dev/null 2>&1; echo '==> Removing Port Forwarding'")
  end

  config.vm.provider "virtualbox" do |vb|
    vb.gui = false
    vb.customize ["modifyvm", :id, "--memory", "2048", "--cpus", "2", "--ioapic", "on"]
    vb.customize ["modifyvm", :id, "--natdnsproxy1", "off"] # VM DNS off
  end
end
```

vagrantの設定はVagrantfileというファイルに上のコードのようなものを記述します。

まず、上のコードでは、hashicorp公式のリポジトリからubuntu/xenial64というboxイメージを取得しています。

```
config.vm.box = 'ubuntu/xenial64'
```

これはUbuntuが公式にホスティングしているものになります。
Vagrantのboxイメージは、公式以外にも多くのユーザが便利なものを提供していますが、
今回は、まっさらな環境を使いたかったので公式のものを使いました。

次に、必要なネットワークの設定を行っています。

```
config.vm.network :forwarded_port, guest: 3000, host: 3080
config.vm.network 'private_network', ip: '192.168.33.10', auto_config: true

# 127.0.0.1:80をboxの中に転送する
config.trigger.after [:provision, :up, :reload] do
  system('echo "
rdr pass inet proto tcp from any to 127.0.0.1 port 80 -> 127.0.0.1 port 3080
" | sudo pfctl -ef - > /dev/null 2>&1; echo "==> Fowarding Ports: 80 -> 3080"')
end

config.trigger.after [:halt, :destroy] do
  system("sudo pfctl -f /etc/pf.conf > /dev/null 2>&1; echo '==> Removing Port Forwarding'")
end
```

Ubuntuの仮想マシンのプラベートIPアドレスの指定や、
ホストOSからのアクセスをゲストOSへ転送する設定が書かれています。
ここでのポイントとしては、[forwarded_portのホスト側に1024以下のポート番号を使えない](https://www.vagrantup.com/docs/networking/forwarded_ports.html#host)ことです。
そのため、ホストOS側の80番のアクセスを一度、3080番に転送しています。

# まとめ
今回は、RailsでのRSpecの動作検証のために簡単に用意できる環境を作成しました。
Railsのインストールの設定を変えれば、他の検証にも使えると思います。