Vagrantでloopを利用して沢山の仮想マシンを定義する　

VagrantfileはRubyのDSLなのでそれなりに構文を利用して設定ファイルを記述できます。例えば、複数のアプリケーション・サーバーやデータベース・サーバーを起動、プロビジョニングをする際にホストごとに仮想マシンをdefineするのではなく、`each`を利用して一気に沢山設定します。

今回のサンプルは、以下の構成です。

 - アプリケーション・サーバーは1つのEC2インスタンス
     - サーバー内部ではDockerコンテナとして幾つかのアプリケーションが動作
 - データベース・サーバーは複数のEC2インスタンス
     - アプリケーション・サーバー内部で動作をしているコンテナが接続をする
 - サーバーのプロビジョニングにはAnsibleを利用する
     - playbookの詳細な記述方法とかは省略しますが、Vagrantと組み合わせた時にgroupを正しく設定する方法くらいは残しておきます。

### Vagrantfile

今回の話のネタはこれがほとんどですが。


```ruby
# -*- mode: ruby -*-
# vi: set ft=ruby :

# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  access_key = ENV['AWS_ACCESS_KEY'] # 環境変数からAWSの認証情報を取ってきます
  access_secret = ENV['AWS_SECRET_KEY']
  number_ob_db = 5 # 同時に起動をするDBサーバーのEC2インスタンスの数
  config.vm.box = "dummy"
  config.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"

  # アプリケーション・サーバーの設定
  config.vm.define "ap" do |ap|
    ap.vm.provider :aws do |aws, override|
        aws.access_key_id = access_key
        aws.secret_access_key = access_secret
        aws.keypair_name = "SECRET_KEY_PAIR"
        aws.region = "ap-northeast-1"
        aws.ami = "AMI_ID"
        aws.availability_zone = "ap-northeast-1a"
        aws.instance_type = "m3.large"
        aws.security_groups = ["APSERVER_SECURITY_GROUP"]
        aws.user_data = "MY_USER_DATA"
        override.ssh.username = "USER"
        override.ssh.private_key_path = "PRIVATE_KEY"
        aws.tags = {
          "Name" => "ap_server"
        }    
    end
  end
  
  # データベース・サーバーの設定
  (1..number_ob_db).each do |i| # eachが使える
    config.vm.define "db-#{i}" do |node|
      node.vm.provider :aws do |aws, override|
          aws.access_key_id = access_key
          aws.secret_access_key = access_secret
          aws.keypair_name = "SECRET_KEY_PAIR"
          aws.region = "ap-northeast-1"
          aws.ami = "AMI_ID"
          aws.availability_zone = "ap-northeast-1a"
          aws.instance_type = "c1.medium"
          aws.security_groups = ["DBSERVER_SECURITY_GROUP"]
          aws.user_data = "MY_USER_DATA"
          override.ssh.username = "USER"
          override.ssh.private_key_path = "PRIVATE_KEY"
          aws.tags = {
            "Name" => "db-#{i}"
          }
      end
    end
  end

  # プロビジョニングの設定. groupsをアプリケーション・サーバーとデータベース・サーバーで変えておく
  config.vm.provision "ansible" do |ansible|
    ansible.extra_vars = {
      "docker_registyr_backet_name" => "backet_name",
      "docker_registry_aws_access_key" => access_key,
      "docker_registry_aws_secret_key" => access_secret
    }
    ansible.groups = {
      "ap" => ["ap"],
      "db" => (1..number_ob_db).map { |e| "db-#{e}" } # この辺りがRubyっぽい
    }
    ansible.playbook = "playbook.yml"
  end
end
```


### Playbookの設定

groupsを変えているので、`playbook.yml`を対応させます。


```yaml
---
# アプリケーション・サーバーの内容
- name: Setup Application Host
  hosts: ap
  remote_user: USER
  sudo: yes

  roles:
    - docker
    - registry
    - application

# データベース・サーバーの内容
- name: Setup Database Host
  hosts: db
  remote_user: USER
  sudo: yes

  roles:
    - setup_db
```


Ansibleのディレクトリの配置などは[Best Practices — Ansible Documentation](http://docs.ansible.com/playbooks_best_practices.html)などを参考にしてみてください。

### サーバーの起動

最後に`vagrant up ap db-1 db-2 db-3 db-4 db-5 --provider aws`とするとサーバーの起動とプロビジョニングが自動で実施されます。

便利ですね。