VagrantでAnsible超初歩ハンズオン

## 対象者
- 今回の記事は下記ような人を対象としています。
    1. ansibleが何なのか、どういったものなのかをある程度理解をしている
    2. 誰かが構築したansibleを触ったことがある
    3. 自身では、まだansibleを構築したことない人



自分もまだ触り始めて半年も経ってない(というか自分で環境構築とか始めたのはつい1ヶ月くらい前くらいからです...)<br>ので、ベストプラクティスとかよくわかっていなかったり、誤った情報を書いてしまっているかもしれないので、何かあればご指摘の程宜しくお願い致します:bow:

## ハンズオン開始
### <font color="red">環境情報</font>

|種類|バージョン|
|:--:|:--:|
|OS|centos6.7|
|ansible|2.3.1.0|
|python|2.6.6|


### <font color="orange">CentOS環境構築</span>
#### Ansible環境
- 今回はvagrantを使用して、CentOS環境を構築します。

1. Vagrant boxの確認

    ```
    $ vagrant box list  
    ```
    - 上記コマンドを実行してCentos6.5のvagrant boxが無ければ手順の2番へ、Centos6.7のvagrant boxが既にある方は2番を飛ばして下さい。
        - <font color="red">※コマンドを実行して出てくるvagrant boxの名前はvagrant boxを追加するときに任意に設定するものなので必ずしも**Centos6.7**という名前とは限りません</font>

1. Centos6.7のvagrant boxを追加する
    
    ```
    $ vagrant box add centos6.7 https://github.com/CommanderK5/packer-centos-template/releases/download/0.6.7/vagrant-centos-6.7.box
    ```
    - ※`vagrant box add`の後に任意のboxの名前を付けている

1. Vagrant初期化

    ```
    $ vagrant init centos6.7    
    ```
1. Vagrantfile修正
    - `vagrant init`するとVagrantfileが実行したディレクトリに生成されるので下記のように修正する
    
    ```diff:Vagrantfile
  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  - # config.vm.network "private_network", ip: "192.168.33.10"
  + config.vm.network "private_network", ip: "192.168.33.10"
    ```

1. Vagrant起動&ログイン
    
    ```
    $ vagrant up
    $ vagrant ssh
    ```

#### Ansible実行対象
- 実際の運用に近づけるために、今回はAnsibleの実行対象用のvagrantの環境も作る

1. Vagrant初期化

    ```
    $ vagrant init centos6.7    
    ```
1. Vagrantfile修正
    - `vagrant init`するとVagrantfileが実行したディレクトリに生成されるので下記のように修正する
    
    ```diff:Vagrantfile
  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  - # config.vm.network "private_network", ip: "192.168.33.10"
  + config.vm.network "private_network", ip: "192.168.33.11"
    ```

1. Vagrant起動&ログイン
    
    ```
    $ vagrant up
    $ vagrant ssh
    ```

### <font color="gold">Ansibleインストール
1. EPELリポジトリの追加
    
    ```
    $ sudo -y yum install epel-release
    ```
1. Ansibleインストール

    ```
    $ sudo yum -y install ansible
    ```

1. Ansible実行対象のvagrant環境にAnsibleの公開鍵を登録する
    - Ansibleサーバから対象のvagrant環境にSSHでノンパスでログインできるようにするため、公開鍵を送る
        - 対象サーバは`192.168.33.11`

    ```
    $ ssh-keygen -t rsa
    $ ssh-copy-id vagrant@192.168.33.11
    ```

1. 接続確認
    - 下記コマンドを実行してパスワードを聞かれることなくログインできたらOK
    
    ```
    $ ssh vagrant@192.168.33.11
    ```

### <font color="MediumSeaGreen">inventoryファイル作成</font>
- 対象のサーバを記述するファイル

1. ansibleルートディレクトリー及び、iventoryディレクトリを作成する
    
    ```
    $ mkdir ansible ; cd $_
    $ mkdir inventory ; cd $_    
    ```

1. 対象サーバのIPアドレスをhostsファイルに記載する
    - inventoryディレクトリ配下にhostsファイルを作成し対象サーバのIPを記載する
        - ※今回は`192.1683.33.11`

    ```ini:ansible/inventory/hosts
    [target]
    192.168.33.11
    ```
    - 上記の`[target]`は`target`という**グループ**に`192.168.33.11`という**ホスト**を属させている。

1. 疎通確認
    - ansibleのルートディレクトリに移動して、ansibleコマンドを実行する

    ```
    $ cd ~/ansible
    $ ansible all -i hosts -m ping
    192.168.33.11 | SUCCESS => {
        "changed": false,
        "ping": "pong"
    }
    ```
    - `-i {inventoryファイル名}`でinventoryファイルを指定している
    - all を指定した場合、-i で指定したhostsに記載されているホスト全部が対象となる
    - `-m {モジュール名}`でモジュールを指定している

### <font color="blue">Playbookを作成</font>
- 大きく分けて、playbookには3つの事を定義する
    1. target
        - **どこに**・**誰が**実行するか
    2. vars
        - 変数を指定する(taskで使用する)
            - <font color="red">※実際はplaybookではなく変数用のディレクトリ・ファイルを作成して、共通化することがほとんど</font>(所感)
    3. task
        - どんなことをするかモジュール使って記述する

1. 変数を定義
    - group_vars/targets.ymlというファイルを作成する

    ```
    $ mkdir group_vars ; cd $_
    $ vi targets.yml
    ```
    - 下記を記載
    
    ```yml:ansible/group_vars/targets.yml
    message: "Hello Ansible!"

    tokyo:
      edogawa:
        population: 68,2400
      katsushika:
        population: 44,4400

    ```
    - ※内容については特に意味はないです
1. playbookの定義
    - 今回はdebugモジュールを使用してmsgに格納した文字列を対象サーバで出力するタスク

    ```yml:ansible/test.yml
    - hosts: target
      user: vagrant
      tasks:
        - name: output message.
          debug: msg="{{ message }}"

        - name: output population downtown
          debug: msg="I was born {{ item.key }}, with a population {{ item.value.population }} people"
          with_dict: "{{ tokyo }}"  
    ```

### <font color="Violet">Playbook実行</font>
1. ansibleのルートディレクトリでansibleを実行する
    - `ansible-playbook -i inventory/hosts test.yml`
        - `-i {inventoryファイル名}`で対象のホストを指定
        - test.ymlは実行するplaybookを指定している。
        - playbookの中で対象のホストをtargetというグループを指定しているので、おのずと変数もtarget.ymlを読み込むようになっている<br><font color="red">※Ansibleでは決まったディレクトリなどから情報を**暗黙的に取得**するため、依存関係を理解しておく必要がある。</font>

    ```
    $ cd ~/ansible
    $ ansible-playbook -i inventory/hosts test.yml

    PLAY [target] ***********************************************************************************************************************************************************************

    TASK [Gathering Facts] **************************************************************************************************************************************************************
    ok: [192.168.33.11]

    TASK [output message.] **************************************************************************************************************************************************************
    ok: [192.168.33.11] => {
        "msg": "Hello Ansible !"
    }

    TASK [output population downtown] ***************************************************************************************************************************************************
    ok: [192.168.33.11] => (item={'key': u'edogawa', 'value': {u'population': 68,2400}}) => {
        "item": {
            "key": "edogawa",
            "value": {
                "population": 68,2400
            }
        },
        "msg": "I was born edogawa, with a population 68,2400 people"
    }
    ok: [192.168.33.11] => (item={'key': u'katsushika', 'value': {u'population': 44,4400}}) => {
        "item": {
            "key": "katsushika",
            "value": {
                "population": 44,4400
            }
        },
        "msg": "I was born katsushika, with a population 44,4400 people"
    }
   
    PLAY RECAP **************************************************************************************************************************************************************************
    192.168.33.11              : ok=3    changed=0    unreachable=0    failed=0
    ```

#### ちょっと解説
`output message.`というtaskではdebugモジュールを使って、変数`message`を出力しているだけですが、ディクショナリ形式で書いた`tokyo`の使い方ですが、このタスクは`tokyo`変数の値を`with_dict`で要素の数だけループして取り出しながらdebugモジュールでメッセージを出力していきます。<br>ループ毎に取り出された要素は`item`という定義済み変数に格納され、処理中に使うことができます。<br>
↓こんな感じに要素が格納されている

```
(
  item={
         'key': u'edogawa', 
         'value': {
                    u'population': 68,2400
                  }
       }
 )
```
このとき`tokyo`直下にある都市名は`item.key`で取得でき、都市名の下に持たせている人口数は`item.value.population`で取得されます。<br>今回だとループ毎にそれぞれ下記のような値が取得できる

1. 一回目のループでは`item.key == "edogawa"`、`item.value.population == 68,2400`
1. 二回目のループでは`item.key == "katsushika"`、`item.value.population == 44,4400`


## 終わりに
- 超初歩的なハンズオンだが、少なくても変数を使わなければ2ファイルで実装できてしまう.....!!

```
.
├── group_vars
│   └── target.yml
├── inventory
│   └── hosts
└── test.yml
```

今回はただ、対象サーバで文字列を出力するだけのタスクになってしまいましたが、実際はyumやshell等のモジュールで色んなもののインストールとかをtaskに落とし込んで、コマンド1つで全部やってくれるのでとても楽です。<br>是非、[他のモジュール](http://monogusa.wiki.fc2.com/wiki/Ansible%E3%81%A7%E3%82%88%E3%81%8F%E4%BD%BF%E3%81%86%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB)を見てローカル環境で試してみてください!

---

あと、ちょっと近いうちに実践に近いものを書く予定です
roleとかtagsとか..暗号・復号化とか...