[Ansible] Vagrantで構築した仮想マシンに対してAnsibleを試した時のメモ

ChefやPuppetに比べて使い方が簡単であると評判なAnsibleを試してみましたので、忘れないうちに構築までの手順のメモとして残しておくことにします。 
環境構築について私の理解が不十分であるところもあるので、間違い等がありましたらご指摘お願いします。


# 環境

* OS（ホスト）：CentOS 6.5
* OS（VM）：CentOS 6.5

# VM環境の構築

Ansibleを試す環境を簡単に構築＆破棄できるよう、利用するノードはVMとしました。 
そしてVirtual Boxを直接使うのは面倒そうなので、Virtual Boxを簡単に扱うためによく使われてるVagrantを用いてVMを構築します。 
Vagrantを利用することで、Virtual Boxを直接使う時に比べて簡単な操作でVMを構築することができます。

## Vagrantのインストール

Vagrantをインストールする手順を示します。
<ol><li>最新版のrpmのURLを確認 
[Vagrant公式ページ](https://www.vagrantup.com/)から最新版のVagrantパッケージのURLを確認します。 私がVagrantをインストールした時のパッケージの最新版は `https://dl.bintray.com/mitchellh/vagrant/vagrant_1.7.2_x86_64.rpm` にありました。
</li><li>インストール
yumで先程確認したVagrantの最新版をインストールします。

```sh
$ yum install https://dl.bintray.com/mitchellh/vagrant/vagrant_1.7.2_x86_64.rpm
```

</li><li>Vagrantがインストールされたことの確認
Vagrantがインストールされたことを確認します。
ここでは、Vagrantのバージョンを確認するコマンドを実行しています。 

```sh
$ vagrant version
Installed Version: 1.7.2
```
</li></ol>

## VM環境の設定

Ansibleの管理対象とするVM環境を以下の手順で設定します。
<ol><li>作業用ディレクトリの作成 
Ansibleを実行するための作業用ディレクトリを作成します。

```sh
$ cd ~/
$ mkdir ansible
$ cd ansible
```

</li><li>Vagrantの初期化
Vagrantを初期化し、環境構成ファイルVagrantfileを作成します。
`名称` には指定した `box` に対する固有の名前（任意に設定可能）をつけ、 `box` には、Vagrantに必要な仮想マシンのテンプレート（boxファイル）を指定します。

```sh
$ vagrant init [名称] [box]
``` 
今回VM環境に使うCentOS 6.5なら以下のようになります。`名称`は適当で良いですが、今回は **centos6.5_ansible** としました。

```sh
$ vagrant init centos6.5_ansible http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-6.5_chef-provisionerless.box
```
</li><li>Vagrantfileの編集
特に何も考えず、 **3台のVMを起動** するようにVagrantfileを編集しました。

```sh
$ cp Vagrantfile Vagrantfile.orig
$ diff Vagrantfile
```

```diff
15c15,29
< config.vm.box = "centos6.5_ansible"
---
> config.vm.define :node1 do |node|
> node.vm.box = "centos6.5_ansible"
> node.vm.network :private_network, ip: "192.168.100.10"
> end
>
> config.vm.define :node2 do |node|
> node.vm.box = "centos6.5_ansible"
> node.vm.network :private_network, ip: "192.168.100.11"
> end
>
> config.vm.define :node3 do |node|
> node.vm.box = "centos6.5_ansible"
> node.vm.network :private_network, ip: "192.168.100.12"
> end
>
```

</li></ol>

## VMの起動
VMを起動します。

```sh
$ vagrant up
```

VMが起動できたことを確認してみましょう。

```sh
$ vagrant status
Current machine states:

node1 running (virtualbox)
node2 running (virtualbox)
node3 running (virtualbox)
```

これでVMが起動できていることは確認できましたので、VMにログインしてみましょう。 
今のままではVagrantで構築したVMへ直接 `ssh` コマンドでログインできないので、 **vagrantコマンドのssh** を使ってログインする必要があります。

```sh
$ vagrant ssh node1
(vagrantで作成した仮想マシン)
```

# Ansibleを使ってみる

Ansibleを利用するVM環境が用意できましたので、Ansibleを使ってみましょう。

## Ansibleのインストール

Ansibleのインストールはyumで行います。 

```sh
$ yum install ansible
```

## Ansible管理対象のノードを設定

　
<ol><li>hostsファイルの作成
Ansibleには **インベントリファイル** というものがあり、Ansibleの管理対象のノードを列挙します。 
ここでは、 `hosts` というファイル名でインベントリファイルを作成します。 

```sh
$ cd ~/ansible
$ touch hosts
```
今回作成したhostsファイルの内容を以下に示します。

```sh
[ansible-nodes]
192.168.100.10 ansible_ssh_user=vagrant ansible_ssh_private_key_file=.vagrant/machines/node1/virtualbox/private_key
192.168.100.11 ansible_ssh_user=vagrant ansible_ssh_private_key_file=.vagrant/machines/node2/virtualbox/private_key
192.168.100.12 ansible_ssh_user=vagrant ansible_ssh_private_key_file=.vagrant/machines/node3/virtualbox/private_key
```
今回は、先程作成した3台のVMを `ansible-nodes` グループとして指定しています。 
秘密鍵を指定する `ansible_ssh_private_key_file` に `~/.vagrant.d/insecure_private_key` を指定する記事が多くありますが、次に続くAnsibleによるpingの動作確認において、 **Vagrantのバージョンが比較的新しいとPermission Denied** なってしまいますので注意が必要です。
また、理由は分からないのですが、第1フィールドにはホスト名ではなく **IPアドレス** を直接書く必要があるそうです。
**ホスト名を書いてしまうとPermission Denied** となってしまいます。 
（参考：[Vagrant 1.7+でSSH接続エラーが出た場合の対処](http://mawatari.jp/archives/solution-of-vagrant-ssh-connection-error)）

</li><li>sshコマンドで直接ログインできるように設定 
前述したように、現状では `vagrant ssh` コマンドでしかVagrantで構築したVMへログインできません。 
これは非常に面倒なので `ssh` コマンドで直接ログインできるようにします。

```sh
$ cp ~/.ssh/config ~/.ssh/config.orig
$ vagrant ssh-config > ~/.ssh/config
```

</li></ol>

## Ansibleの動作確認

　
<ol><li>pingの実行
Ansibleの動作確認を行うため、pingを実行してみます。 

```sh
$ ansible -i hosts ansible-nodes -m ping
192.168.100.10 | success >> {
"changed": false,
"ping": "pong"
}

192.168.100.11 | success >> {
"changed": false,
"ping": "pong"
}

192.168.100.12 | success >> {
"changed": false,
"ping": "pong"
}
```

</li><li>インストール対象がインストールされていないことの確認 
せっかくなので、Ansibleを使って何かインストールしてみましょう。 
私が構築したVMには `gcc` と `gdb` がインストールされていなかったので、これらをインストールすることにします。 
最初にそれぞれの各VMで `gcc` と `gdb` がインストールされていないことを確認します。

```sh
$ ssh node1
$ which gcc
/usr/bin/which: no gcc in (/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/vagrant/bin)
$ which gdb
/usr/bin/which: no gdb in (/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/vagrant/bin)

$ ssh node2
$ which gcc
/usr/bin/which: no gcc in (/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/vagrant/bin)
$ which gdb
/usr/bin/which: no gdb in (/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/vagrant/bin)

$ ssh node3
$ which gcc
/usr/bin/which: no gcc in (/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/vagrant/bin)
$ which gdb
/usr/bin/which: no gdb in (/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/vagrant/bin)
```

</li><li>Playbookの作成 
Ansibleには **Playbook** と呼ばれる、Chefのレシピと似たようなものがあります。 
Playbookには、対象マシンに対してどういった操作を行うのかを記述していきます。 
今回は `gcc` と `gdb` をインストールするため、 `playbook.yml` を以下のように作成しました。 

```yaml
---
- hosts: ansible-nodes
  sudo: yes
  tasks:
    - name: install gcc
      yum: name=gcc state=installed
    - name: install gdb
      yum: name=gdb state=installed
```

</li><li>Ansibleを使ってインストール
作成したPlaybookを用いて、`gcc` と `gdb` のインストールを行ってみます。 

```sh
$ ansible-playbook -i hosts playbook.yml

PLAY [ansible-nodes] **********************************************************

GATHERING FACTS ***************************************************************
ok: [192.168.100.12]
ok: [192.168.100.11]
ok: [192.168.100.10]

TASK: [install gcc] ***********************************************************
changed: [192.168.100.11]
changed: [192.168.100.10]
changed: [192.168.100.12]

TASK: [install gdb] ***********************************************************
changed: [192.168.100.10]
changed: [192.168.100.11]
changed: [192.168.100.12]

PLAY RECAP ********************************************************************
192.168.100.10 : ok=3 changed=2 unreachable=0 failed=0
192.168.100.11 : ok=3 changed=2 unreachable=0 failed=0
192.168.100.12 : ok=3 changed=2 unreachable=0 failed=0
```

</li><li>インストールされたことの確認 
`gcc` と `gdb` が正常にインストールされたことを確認します。 

```sh
$ ssh node1
$ which gcc
/usr/bin/gcc
$ which gdb
/usr/bin/gdb

$ ssh node2
$ which gcc
/usr/bin/gcc
$ which gdb
/usr/bin/gdb

$ ssh node3
$ which gcc
/usr/bin/gcc
$ which gdb
/usr/bin/gdb
```

Playbookで指定した `gcc` と `gdb` がインストールされていることを確認できました。

</li></ol>

# 後始末

最後に今回使った環境を破棄します。 
Vagrantを用いれば一瞬です。
<ol><li>仮想マシンの停止 

```sh
$ vagrant halt
```

</li><li>仮想マシンの削除

```sh
$ vagrant destroy
```

</li></ol>

# 最後に

Vagrantで構築したVMに対して、構成管理ツールAnsibleを用いてソフトをインストールしてみました。 
Ansibleの設定はこの例を見ていただければわかるように、非常にわかりやすいです。 
Ansibleがどこまでできるのかわかっていませんが、環境構築を手軽に済ませたい人は使うことを検討する価値は十分にありそうです。 
今後はAnsibleでどこまでできるのか調査することに加えて、ChefやPuppetも利用して使い心地を確かめてみたいですね。


# 参考情報
* [Ansible チュートリアル](http://yteraoka.github.io/ansible-tutorial/)
* [CentOSにVagrantをインストールする](http://tmpla.info/installation-of-vagrant-in-centos/)
* [VagrantとDockerとAnsibleで環境自動構築！（全編：vagranとAnsible編）](http://blog.shinofara.xyz/archives/183/)
* [不思議の国のAnsible - 第1話 -](http://demand-side-science.jp/blog/2014/ansible-in-wonderland-01/)
* [Vagrant ssh-configでvagrant sshを快適にする](http://qiita.com/Sanche/items/43d615beef05cd9417e2)
* [Vagrant 1.7+でSSH接続エラーが出た場合の対処](http://mawatari.jp/archives/solution-of-vagrant-ssh-connection-error)
* [VirtualBoxとVagrantで開発環境を構築](http://www.webcyou.com/?p=4632)
* [AnsibleでDockerのコンテナを構築する](http://qiita.com/nmatayoshi/items/58183cba4d98a151b806)