はじめてのvagrant-aws

`GW`は`Vagrant`で`AWS`を操作してリア充になりたかったので、やったことをメモ。
`AWS`自体ほぼ初めて触るので、使い方の確認も兼ねてます。
`VPC`やら`EBS`についてはいずれやりたいと思います。
`ec2-cli`もお勉強が必要かな。

参考文献：
書籍「実践Vagrant」
[vagrantではじめるクラウド開発環境（AWS編）](http://qiita.com/msykiino/items/1a8c8157978abff51229)

# 環境
ホストOS：Windows 7 Standard 64bit
Vagrant：1.5.0
コンソール：Git Bash 1.8.3

# 準備

## AWSアカウントの作成
かつあい

## vagrantユーザの作成
1. `Service > Deployment & Management > IAM`に移動
2. 左のメニューの`Users`に移動し、`Create New Users`をクリック
3. `vagrant`と入力して`Create`をクリック
4. 完了画面が表示されるので、`Access Key Id`と`Secret Access Key`を控えた上で`Close Window`をクリック
5. 左のメニューの`Groups`に移動し、`Create New Group`をクリック
6. `vagrant`と入力して`Continue`をクリック
7. `Power User Access`のところの`Select`をクリック
8. `Continue`をクリック
9. `Create group`をクリック
10. `Users`に移動し、`vagrant`ユーザを選択して右画面下の`Groups`タブを選択し、`Add user to groups`をクリック
11. `vagrant`をチェックして`Add to Groups`をクリック

## Security Groupの作成
1.`Service > Compute & Networking > EC2`に移動
2.`NETWORK & SECURITY > Security Groups`に移動
3.`Create Security Group`をクリック
4.グループ情報について下記のように入力

| 項目名 | 値 |
|:-----------|:------------|
| Security group name | vagrant |
| Description | vagrant security group |
| VPC | デフォルト（*がついている項目） |

5.`Inbound`タブを選択して`Add Rule`をクリックし、下記のルールを追加

| Type | Protocol | Port Range | Source |
|:-----|:---------|:-----------|:-------|
| SSH | TCP | 22 | Anywhere |
| HTTP | TCP | 80 | Anywhere |
| HTTPS | TCP | 443 | Anywhere |

6.`Create`をクリック

## SSHの鍵を作成
1.`Service > Compute & Networking > EC2`に移動
2.`NETWORK & SECURITY > Key Pairs`に移動
3.`Create Key Pair`をクリック
4.`vagrant`と入力して`Create`をクリック　→　`vagrant.pem`をダウンロード
5.`~/.ssh`に`vagrant.pem`を格納

## Vagrant、Chefのインストール
かつあい

## rsyncのインストール
`rsync`をインストールしないと、`Chef-solo`実行時にレシピを転送できなくてエラーになる。
`VirtualBox`が対象だと`rsync`がなくても動作するけど、AWSは駄目らしい。

1.`Cygwin`をインストール（[インストーラのURL](http://cygwin.com/install.html)）
2.`C:\cygwin64\bin`ディレクトリから下記のファイルを`C:\Program Files (x86)\Git\bin`ディレクトリにコピー

* rsync.exe
* cygiconv-2.dll
* cygintl-8.dll
* cygpopt-0.dll
* cygwin1.dll

3.`Cygwin`が不要の場合はアンインストール

# Vagrantの設定

## プラグイン`vagrant-aws`と`vagrant-omnibus`と`dotenv`をインストール
`vagrant-aws`は`AWS`プロバイダを利用するためのプラグイン。
`vagrant-omnibus`はゲストOSにChefをインストールするためのプラグイン。
`dotenv`はカレントディレクトリの`.env`ファイルに値の宣言をすることで、環境変数として読み込むことができるGem。
アクセスキーなどを`Vagrantfile`に直接書かずに外部ファイル化できる。社内プロキシの設定などもこれで定義したほうがよさそう。

```bash
$ vagrant plugin install vagrant-aws
Installing the 'vagrant-aws' plugin. This can take a few minutes...
Installed the plugin 'vagrant-aws (0.4.1)'!

$ vagrant plugin install vagrant-omnibus
Installing the 'vagrant-omnibus' plugin. This can take a few minutes...
Installed the plugin 'vagrant-omnibus (1.4.1)'!

$ vagrant plugin install dotenv
Installing the 'dotenv' plugin. This can take a few minutes...
Installed the plugin 'dotenv (0.11.1)'!
```

## `~/vagrant-aws`ディレクトリを作成
以降はここで作業。

## クックブックを作成
Apacheをインストールするクックブックを作成する。

```bash
$ knife solo init .
Creating kitchen...
Creating knife.rb in kitchen...
Creating cupboards...
Setting up Berkshelf...

$ knife cookbook create -o site-cookbooks apache2
** Creating cookbook apache2
** Creating README for cookbook: apache2
** Creating CHANGELOG for cookbook: apache2
** Creating metadata for cookbook: apache2
** Creating specs for cookbook: apache2
```

```rb:~/vagrant-aws/site-cookbooks/apache2/recipes/default.rb
#
# Cookbook Name:: apache2
# Recipe:: default
#
# Copyright 2014, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#
package "httpd"

service "httpd" do
  action [:enable, :start]
end
```

## `~/vagrant-aws/.env`にAWSの認証情報を記載

```rb:~/vagrant-aws/.env
# providerのデフォルトをAWSに変更
VAGRANT_DEFAULT_PROVIDER="aws"

# AWSの認証情報
AWS_SSH_USERNAME="ec2-user"
AWS_SSH_KEY="~/.ssh/vagrant.pem"
AWS_ACCESS_KEY_ID="＜ユーザ作成時のAccess Key Id＞"
AWS_SECRET_ACCESS_KEY="＜ユーザ作成時のSecret Access Key＞"
AWS_KEYPAIR_NAME="vagrant"
AWS_SECURITY_GROUP="vagrant"
```

## `~/vagrant-aws/Vagrantfile.chef`にSSLの設定を記載
本設定をしないと、chef_soloでのプロビジョニング時に警告が発生する。
詳細はハマったことのメモを参照。

```rb:~/vagrant-aws/Vagrantfile.chef
Chef::Config.ssl_verify_mode = :verify_peer
```

## `Vagrantfile`の作成

1.Vagrantfileの初期化

```bash
$ vagrant init dummy https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box
```

2.Vagrantfileの編集
`vagrant init`で出力されたコメントは割愛。

```rb:~/vagrant-aws/Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

# .envの情報を読み込み
Dotenv.load

# 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|
  config.vm.box       = "dummy"
  config.vm.box_url   = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"

  config.vm.provider :aws do |provider, override|
    provider.access_key_id          = ENV['AWS_ACCESS_KEY_ID']
    provider.secret_access_key      = ENV['AWS_SECRET_ACCESS_KEY']
    provider.keypair_name           = ENV['AWS_KEYPAIR_NAME']

    # EC2インスタンスの設定
    provider.region                 = "ap-northeast-1"
    provider.availability_zone      = "ap-northeast-1a"

    # Amazon LinuxのAMIを指定
    # 今回はEC2のIMAGES > AMIsで検索したAMIを指定
    provider.ami                    = "ami-c9562fc8"

    provider.instance_type          = "t1.micro"
    provider.instance_ready_timeout = 120
    provider.terminate_on_shutdown  = false

    provider.security_groups        = [ ENV['AWS_SECURITY_GROUP'] ]
    provider.tags                   = {
      "Name"        => "vagrant-aws",
      "Description" => "Boot from vagrant-aws",
    }

    # sudoをttyでログインしているユーザからも実行できるようにする
    # 自作AMIを用意する際にはこの設定をあらかじめしておく
    provider.user_data = <<-USER_DATA
    #!/bin/sh
    echo "Defaults    !requiretty" > /etc/sudoers.d/vagrant-init
    chmod 440 /etc/sudoers.d/vagrant-init
    USER_DATA

    # AWSへの接続ユーザおよび秘密鍵の指定
    override.ssh.username = ENV['AWS_SSH_USERNAME']
    override.ssh.private_key_path   = ENV['AWS_SSH_KEY']

    override.vm.synced_folder ".", "/home/ec2-user/vagrant", disabled: true
  end

  # chefのインストール／アップデート
  config.omnibus.chef_version = :latest

  # chef soloの設定
  config.vm.provision :chef_solo do |chef|
    chef.custom_config_path = "Vagrantfile.chef"
    chef.cookbooks_path     = ["cookbooks/", "site-cookbooks/"]
    chef.add_recipe "apache2"
  end
end
```

## EC2インスタンスの作成＋起動＋プロビジョニング

```
$ vagrant up
Bringing machine 'default' up with 'aws' provider...
[fog][WARNING] Unable to load the 'unf' gem. Your AWS strings may not be properl
y encoded.
==> default: HandleBoxUrl middleware is deprecated. Use HandleBox instead.
==> default: This is a bug with the provider. Please contact the creator
==> default: of the provider you use to fix this.
==> default: Warning! The AWS provider doesn't support any of the Vagrant
==> default: high-level network configurations (`config.vm.network`). They
==> default: will be silently ignored.
==> default: Launching an instance with the following settings...
==> default:  -- Type: t1.micro
==> default:  -- AMI: ami-c9562fc8
==> default:  -- Region: ap-northeast-1
==> default:  -- Availability Zone: ap-northeast-1a
==> default:  -- Keypair: vagrant
==> default:  -- User Data: yes
==> default:  -- Security Groups: ["vagrant"]
==> default:  -- User Data:     #!/bin/sh
==> default:     echo "Defaults    !requiretty" > /etc/sudoers.d/vagrant-init
==> default:     chmod 440 /etc/sudoers.d/vagrant-init
==> default:  -- Block Device Mapping: []
==> default:  -- Terminate On Shutdown: false
==> default:  -- Monitoring: false
==> default:  -- EBS optimized: false
==> default: Waiting for instance to become "ready"...
==> default: Waiting for SSH to become available...

（中略）
```

無事Apacheをインストールしたインスタンスが作成されました。

## SSHで接続

```bash
$ vagrant ssh
[fog][WARNING] Unable to load the 'unf' gem. Your AWS strings may not be properly encoded.

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2014.03-release-notes/
1 package(s) needed for security, out of 18 available
Run "sudo yum update" to apply all updates.

[ec2-user@*** ~] $ rpm -q httpd
httpd-2.2.27-1.2.amzn1.x86_64
```

## 複数のインスタンスを構築
```rb:~/vagrant-aws/Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

Dotenv.load

# 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|
  config.vm.box       = "dummy"
  config.vm.box_url   = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"

  config.omnibus.chef_version = :latest

  # １つ目のインスタンス
  config.vm.define :node01 do |node|
    # インスタンス毎に個別に設定したい内容を記載
    configure_node(node) do |aws, override|
      aws.ami           = "ami-c9562fc8"
      aws.instance_type = "t1.micro"
      aws.tags          = {
        "Name"        => "aws-node01",
        "Description" => "Boot from vagrant-aws",
      }
    end

    node.vm.provision :chef_solo do |chef|
      chef.custom_config_path = "Vagrantfile.chef"
      chef.cookbooks_path     = ["cookbooks/", "site-cookbooks/"]
      chef.add_recipe "apache2"
    end
  end

  # ２つ目のインスタンス
  config.vm.define :node02 do |node|
    configure_node(node) do |aws, override|
      aws.ami           = "ami-c9562fc8"
      aws.instance_type = "t1.micro"
      aws.tags          = {
        "Name"        => "aws-node02",
        "Description" => "Boot from vagrant-aws",
      }
    end

    node.vm.provision :chef_solo do |chef|
      chef.custom_config_path = "Vagrantfile.chef"
      chef.cookbooks_path     = ["cookbooks/", "site-cookbooks/"]
      chef.add_recipe "apache2"
    end
  end

  # AWS認証設定など、全インスタンス共通の設定を集約
  def configure_node(node, &block) 
    node.vm.provider :aws do |aws, override|
      aws.access_key_id          = ENV['AWS_ACCESS_KEY_ID']
      aws.secret_access_key      = ENV['AWS_SECRET_ACCESS_KEY']
      aws.keypair_name           = ENV['AWS_KEYPAIR_NAME']
      aws.region                 = "ap-northeast-1"
      aws.availability_zone      = "ap-northeast-1a"
      aws.instance_ready_timeout = 120
      aws.terminate_on_shutdown  = false

      aws.security_groups        = [ ENV['AWS_SECURITY_GROUP'] ]
      aws.user_data = <<-USER_DATA
      #!/bin/sh
      echo "Defaults    !requiretty" > /etc/sudoers.d/vagrant-init
      chmod 440 /etc/sudoers.d/vagrant-init
      USER_DATA

      override.ssh.username         = ENV['AWS_SSH_USERNAME']
      override.ssh.private_key_path = ENV['AWS_SSH_KEY']

      override.vm.synced_folder ".", "/home/ec2-user/vagrant", disabled: true

      block.call(aws, override)
    end
  end
end
```

# その他メモ
## `Instance ID`をローカルで取得

```bash
# config.vm.defineで指定した名称を指定
$ cat .vagrant/machines/node01/aws/id
```

# ハマったところのメモ

## インスタンスは作成できるが、Chefのクックブックを転送できない
`rsync`をインストールする。`VirtualBox`だと`rsync`がなくても`chef_solo`でプロビジョニングできるが、`AWS`だとエラーになる。

## `SSL validation of HTTPS requests is disabled.`というWARNメッセージが出力される

chef_solo実行時に下記のような警告メッセージが出力される。

```
[2014-05-05T03:12:59+00:00] WARN:
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

SSL validation of HTTPS requests is disabled. HTTPS connections are still encrypted, but chef is not able to detect forged replies or man in the middle attacks.

To fix this issue add an entry like this to your configuration file:

  # Verify all HTTPS connections (recommended)
  ssl_verify_mode :verify_peer

  # OR, Verify only connections to chef-server
  verify_api_cert true

To check your SSL configuration, or troubleshoot errors, you can use the `knife ssl check` command like so:

  knife ssl check -c /tmp/vagrant-chef-1/solo.rb

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
```

[この記事](https://mistymagich.wordpress.com/2014/04/11/vagrant%E3%81%AEchef-solo%E3%81%AEprovision%E4%B8%AD%E3%81%AB%E3%80%8Cssl-validation-of-https-requests-is-disabled-%E3%80%8D%E3%81%A8%E8%AD%A6%E5%91%8A%E3%81%8C%E8%A1%A8%E7%A4%BA%E3%81%95%E3%82%8C/)を参考にして対応しました。

## `[fog][WARNING] Unable to load the 'unf' gem. Your AWS strings may not be properly encoded.`というWARNメッセージが出力される

[この記事](http://stackoverflow.com/questions/19666226/warning-with-fog-and-aws-unable-to-load-the-unf-gem)によると`vagrant plugin install unf`で`unf`をインストールすれば解決すると記載されていますが、
やってみたところ下記のエラーが発生しました。

```
$ vagrant plugin install unf
Installing the 'unf' plugin. This can take a few minutes...
Installed the plugin 'unf (0.1.4)'!

$ vagrant provision
[fog][WARNING] Unable to load the 'unf' gem. Your AWS strings may not be properly encoded.
C:/Users/ユーザ名/.vagrant.d/gems/gems/unf_ext-0.0.6-x86-mingw32/lib/unf_ext.rb:6:in `require': cannot load such file -- unf_ext.so (LoadError)
```

`unf_ext.rb`を確認したところ、`lib/Rubyのバージョン/ext_unf.so`を読み込もうとしているところで例外が発生している。
`~/.vagrant.d/gems/ruby`を見るとRubyのバージョンは2.0.0なのに対し、
`~/.vagrant.d/gems/gems/unf_ext-0.0.6-x86-mingw32/lib`ディレクトリの下には1.8と1.9しかないのが原因っぽい。
Rubyのバージョンを下げればいいのかな？

とりあえず`chef_solo`は動くので、`vagrant plugin uninstall unf`で`unf`をアンインストールしました。