入門がてらansibleで環境ごとのhttpdのconfデプロイ分けをローカル実行してみた

## 概要
ansible触ってみたのでまとめてみる。
httpdのインストール、起動設定、環境別でconfを配置、httpd reload、をローカル実行する例です。
サーバ立てたら、ansible環境準備して、コマンド一発(devかstgのオプションつけて)で所望の環境できたらいいなと。

## 導入編
### 基礎知識を集める
「ansible 入門」とかでググった記事を幾つか読む
[Ansible 入門 - Qiita](http://qiita.com/ArimaRyunosuke/items/1f9d840311584d8160bc)
[AnsibleでとりあえずのLAMP環境してみる - yk5656 diary](http://d.hatena.ne.jp/yk5656/20150710/1436918643)
[Role を使ったAnsibleのチュートリアル ｜ Developers.IO](http://dev.classmethod.jp/server-side/ansible/tutorial-ansible-with-role/)

少なくとも、以下があればいいらしい。

- ansible環境
- Inventoryファイル(サーバ情報が記載されたファイル)
- playbookファイル(タスク情報がかかれたファイル)

Inventoryファイルを省略してなんとか1ファイルで管理できないか?
と奮闘したけど再現できなかったし、非推奨らしい。
(fabricみたいにコマンド実行時のオプションでなんとかならんかと)

事例はあるっぽい。
[【Ansible】Inventoryファイルを利用せずにansibleコマンドを実行する ｜ Developers.IO](http://dev.classmethod.jp/server-side/ansible/ansible-without-inventory/)

### インストール
インストールはyumかsudo経由。
手元の環境はpyenv+virtualenvでディレクトリごと環境切ってるので、pipから導入した。

```lang:sh

# yumから
$ sudo yum install epel-release
$ sudo yum install ansible
# こっちだと後述のInventoryファイル(/etc/ansible/hosts)は自前でできるらしい

# pipから(python事前に環境ある前提)
$ pip install ansible

```

## やってみた
Inventoryファイル準備
(defaultだと/etc/ansible/hostsが読まれるらしい)

```lang:/home/hoge/ansible/hosts

[all]
localhosts ansible_connection=local

```

Playbook準備

```lang:/home/hoge/ansible/main.yaml
---
- hosts: localhosts
  sudo: yes
  tasks:
  - name: install httpd
    yum: name=httpd state=present
  - name: start httpd service
    service: name=httpd state=started enabled=yes
  - name: setup stg conf file
    template: src=stg-hoge.j2 dest=/etc/httpd/conf.d/hoge.conf
    notify: httpd restart
    when: conf_env == "stg"
  - name: setup dev conf file
    template: src=dev-hoge.j2 dest=/etc/httpd/conf.d/hoge.conf
    notify: httpd restart
    when: conf_env == "dev"
  - name: httpd start confirm
    wait_for: port=80 delay=1
  handlers:
    - name: httpd restart
      action: service name=httpd state=reloaded
```

環境ごとconf用のテンプレ準備
(今回はサンプルなので別になんでもいい)

```lang:bash
# /home/hoge/ansible以下にそれぞれ
$ cat dev-hoge.j2
<VirtualHost *:80>
  DocumentRoot /www/public/dev-html
  ServerName www.example.com
</VirtualHost>
$ cat stg-hoge.j2
<VirtualHost *:80>
  DocumentRoot /www/public/stg-html
  ServerName www.example.com
</VirtualHost>

```

実行してみる

```lang:bash

# どのplaybookを実行するか、sudoパスを訊くか?、実行変数指定、Inventoryファイル指定してる
$ ansible-playbook main.yaml --ask-sudo-pass --extra-vars "conf_env=stg" -i hosts

SUDO password:

PLAY [localhosts] *************************************************************

GATHERING FACTS ***************************************************************
ok: [localhosts]

TASK: [install httpd] *********************************************************
ok: [localhosts]

TASK: [start httpd service] ***************************************************
ok: [localhosts]

TASK: [setup stg conf file] ***************************************************
ok: [localhosts]

TASK: [setup dev conf file] ***************************************************
skipping: [localhosts]

TASK: [httpd start confirm] ***************************************************
ok: [localhosts]

PLAY RECAP ********************************************************************
localhosts                 : ok=5    changed=0    unreachable=0    failed=0

$ ansible-playbook main.yaml --ask-sudo-pass --extra-vars "conf_env=dev" -i hosts
SUDO password:

PLAY [localhosts] *************************************************************

GATHERING FACTS ***************************************************************
ok: [localhosts]

TASK: [install httpd] *********************************************************
ok: [localhosts]

TASK: [start httpd service] ***************************************************
ok: [localhosts]

TASK: [setup stg conf file] ***************************************************
skipping: [localhosts]

TASK: [setup dev conf file] ***************************************************
ok: [localhosts]

TASK: [httpd start confirm] ***************************************************
ok: [localhosts]

PLAY RECAP ********************************************************************
localhosts                 : ok=5    changed=0    unreachable=0    failed=0

```

devかstgかをコマンド実行時のオプションで打ち分けで来てるのでめでたしめでたし。

## playbookの解説
### 今回やったこと

"hosts"という環境単位に、それに紐づく"tasks"を実行

"hosts"にはsudoするか?とか指定できる。

```lang:main.yaml
# localhostsにsudoで実行する
- hosts: localhosts
  sudo: yes
```

- "tasks"には"name"ごと各タスクに名前をつけて、その下に実際の所望の状態を記載する。
  - これらをmoduleと呼び、今回はyum、service、template、wait_forなど利用
  - 参考:[All Modules — Ansible Documentation](http://docs.ansible.com/ansible/list_of_all_modules.html)

```lang:main.yaml
# httpdインストールしてプロセス起動と自動起動を有効にするまで
  tasks:
  - name: install httpd
    yum: name=httpd state=present
  - name: start httpd service
    service: name=httpd state=started enabled=yes
  ...
```

templateではjinja2のファイル(.j2)を参照
その下にはnotifyでそのタスクで変更が生じた場合の次のタスク?とか、そもそもwhenでどの状況なら実行するか?の分岐を指定できる

```lang:main.yaml
### stgの場合のconf配置
  - name: setup stg conf file
    template: src=stg-hoge.j2 dest=/etc/httpd/conf.d/hoge.conf
    notify: httpd restart
    when: conf_env == "stg"

```

notifyで指定した"httpd restart"はヘルパータスクのようにhandlersとして指定

```lang:main.yaml
# handlerとして"httpd restart"を定義
  handlers:
    - name: httpd restart
      action: service name=httpd state=reloaded

```

### 今後できそうなこと

- main.yamlの中にvarsで変数も埋め込める
- main.yamlは各taskを別ファイルにしてinculudeして再利用性をあげられる
- roleでchefっぽく規約に従ったファイル構造にすれば自動で読み込んでくれる
- moduleはbashとかで自作もできるらしい
- chefのdatabag的なのは[Vault](http://docs.ansible.com/ansible/playbooks_vault.html)というのを使えばいいらしい
- sudoじゃなくてrootじゃないと実行できない、とかいう悲しい環境でもできるっぽい

参考:
[Ansible の Playbook を使ってみる - akishin999の日記](http://d.hatena.ne.jp/akishin999/20130815/1376520672)
[Ansible モジュール作成のイロハ - ヌーラボ [Nulab Inc.]](https://nulab-inc.com/ja/blog/backlog/ansible-module-1/)
[ansibleでパスワード認証&suでのroot実行 - Qiita](http://qiita.com/tkr0429/items/90743891b6a1c09ab61d)

## 所感
ぱぱっとやりたいことはできたけど、まだ入門レベルなので今後はどうかなと。

- いい?ところ
  - 2ファイルとか最小でできるのはよい
  - chefの様に謎コマンドたくさんで混乱しない?(ansibleとansible-playbookコマンドとかあるけど...)
- わるい?ところ
  - Inventoryファイルはやっぱり省略可能にして欲しい
  - 結果が"OK"だけでよくわからない。ファイル変更したら差分とか欲しい。
  - 小規模は気楽だけど、やっぱ大規模だと大丈夫かな?感
  - (ansible関係ないけど)できたコードはgitなりでどう管理すると運用便利かな?とふと
- 今回なぜchefを使わないか?
  - ファイル構成とか複雑なので簡単に始めるなら1ファイルで構成を管理したかった(できなかったけど)
  - 単純にrubyよりpythonのが考え方が慣れてるから
  - chefばっかりだとあれなので、他のにも手を出しといた方が頭の体操的にはいいかなと

以上。