[Vagrant] Vagrant で複数のVM を立ち上げて、お互いに通信できるようにするには [VirtualBox]

Vagrant では、一つの BASE BOX イメージから、複数の VMを起動することができるようになってえらくステキです。

勿論、複数のイメージファイルを指定することもできますけれども、BASE BOX は素の状態にしておいて、各サーバは Chef の Role を使って識別して、構成できるようにするのが宗教的理由により優れていると判断しましたので、そのように構成してみようと至ったわけです。

今は、たまたま、ZABBIX2.2の環境を構成しようとしているのですが、ZABBIX の Webフロントエンドと、ZABBIX本体(+DB)を別々のサーバにして構成してみようというところから、この考えに至ったというか、今朝、[入門Chef Solo - Infrastructure as Code](http://www.amazon.co.jp/dp/B00BSPH158/)を読んでいたら、「Vagrant で、複数のVMを管理できるのか!!( ﾟдﾟ )ｸﾜｯ!! Vagrant やべぇ!!」となったので、試してみただけです。

宗教的とかいってゴメンなさい、思いつきです。

# 1.正攻法で複数のVMをVagrantで制御する方法
まず、まっとうに、複数の BOXを元にして、それぞれの VMを起動する方法です。
めでたいことに Vagrantのdocumentとして[MULTI-MACHINE](http://docs.vagrantup.com/v2/multi-machine/index.html)のところに、その記述があります。


```ruby:複数マシンの定義
Vagrant.configure("2") do |config|
  config.vm.provision "shell", inline: "echo Hello"

  config.vm.define "web" do |web|
    web.vm.box = "apache"
  end

  config.vm.define "db" do |db|
    db.vm.box = "mysql"
  end
end
```

複数定義しているところは、`config.vm.define` 部分ですね。それぞれ、`web` と `db` と関連づけられた VMを指定するようにしてあります。対象は次のとおりです。分かりやすいですね。

| 定義名 | 対象VM |
|---:|:---|
|web|apache|
|db|mysql|

このように指定することで、複数の VMを vagrantで制御できるようになります。
この時、`vagrant up` すると、全ての VMが起動します。
vagrant は `command` + `定義名` で個別の制御が可能です。従って、`vagrant up web` とすれば、`apache` VM のみを、`vagrant up db` とすれば `mysql` VM のみを起動することができます。`ssh` や `halt`も同様です。

## sshの定義
みなさまご存じの通り、vagrant では `vagrant ssh-config` にて、ssh の構成を自動的に作ってくれる、便利な機能がありやんす。
これのお陰で、`~/.ssh/config` が溢れんばかりになっているクズもいることでしょうが、これほど便利な機能もありません。コレのために vagrant を使っていると言っても過言ではありません。ウソです。

さて、このように複数VMの場合ではどうすれば良いか。
同じです。
`vagrant ssh-config web` とすれば、おめでたい感じで出てきますが、`--host` をつけると、対象の定義名を変更して割り当てることもできます。
例えば、`vagrant ssh-config web --host web.oshiire.to` なんていう風にすれば、このようになります。

```bash:~/.ssh/config
Host web.oshiire.to
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/sho/.vagrant.d/insecure_private_key
  IdentitiesOnly yes
  LogLevel FATAL
```

(Mavericks使用:`sho`ユーザの場合)

このようなおめでたい定義を、ssh コマンドで利用できるよう、`vagrant ssh-config web --host web.oshiire.to >> ~/.ssh/config` としておくと、`knife` をぶん回すときにも、`knife solo cook web.oshiire.to` なんて感じで使うことができて便利です。やったね、たえちゃん。

# 2.一つのboxから、複数の VMをVagrant で制御する方法
今日のメインはコレです。
実際に構成ファイルを見てもらった方が良いでしょう。どうぞ。

```ruby:1BOXで複数VMの定義
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "debian-7.4_c64"

  config.vm.define :web do | web |
  end

  config.vm.define :zabbix do | zabbix |
  end
```

もろに我が家での構成ファイルですが、`config.vm.define` の外で、`config.vm.box` を指定することで、この vm.boxを元に、必要なVMの数だけ VMがコピーされて利用できるようになります。
今回は 2つだけですが、4個も 10個も書けば、その分の VMが起動されて、あなたのマシンのリソースがなくなって大変なことになるでしょう。ぜひ、お試しください。

##VM間通信をできるようにするには
ぶっちゃけ、ここまでの話はどうでも良かったんです。そこら中に書いてあるので。
私がはまったのは、この先です。困ったことに、private_network 同士のVM間で通信できないのです。
イロイロと資料を見る限り、`xx.vm.network` で `hostonly` のネットワークを作れば、VM間での通信ができると、入門Chef にも多くのblogでも散見されました。しかし、うまくいかない。

どうしたもんかと、結局、Vagrant本家の[PRIVATE NETWORKS](http://docs.vagrantup.com/v2/networking/private_network.html)を見てみると、書いてあるじゃないですか。`virtualbox__intnet: true` しろよって。

ただ、これだけじゃあかんのですわ。
`virtualbox__` (ご丁寧に、安駄婆（あんだばあ）は二つって注釈付) prefix のものは、その指定した内容を、vitualbox provider へ送ることができるらしいです。んで、private な内部ネットワークを作る場合、virtualbox では、その `内部ネットワーク名` を指定する必要があるんです。で、その同一のネットワークでは疎通が可能になる「みたい」です。

従って、VM同士でネットワークをつなげたい場合、`virtualbox__intnet: "xxxx"`と共通の名前を付けましょうというのが、今日の一大事です。覚えて帰りましょう。

結果、我が家では次のように指定しています。みなさまも、どうぞご健勝ください。

```ruby:virtualbox__intnet
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  # All Vagrant configuration is done here. The most common configuration
  # options are documented and commented below. For a complete reference,
  # please see the online documentation at vagrantup.com.

  # Every Vagrant virtual environment requires a box to build off of.
  config.vm.box = "debian-7.4_c64"

  config.vm.define :web do | web |
    web.vm.hostname = "web"
    web.vm.network :private_network, ip: "192.168.33.10", virtualbox__intnet: "intnet"
  end

  config.vm.define :zabbix do | zabbix |
    zabbix.vm.hostname = "zabbix"
    zabbix.vm.network :private_network, ip: "192.168.33.20", virtualbox__intnet: "intnet"
  end
```

ついでなので、各VM に `xxx.vm.hostname` を使って、host名も定義しています。これで host名も変更されてステキです。どうぞ、ご利用ください。

※ 当環境は vagrant 1.4.3 + virtualbox 4.3.6 においてで、今後のversionによっては変更がなされるやも知れません。