オレオレ Ansible Best Practices 2015年1月版

# はじめに

2015年も始まって皆様いかがお過ごしですか。
俺は新プロジェクトの環境整備で毎日あーでもないこーでもないやってます。

というわけで、前の記事を書いてからずいぶん開いちゃったけど、決してカレンダーに乗り遅れたとか乗る気がなかったとかじゃなくて、単に忙しかっただけなんだけど、成人式で連休の今日、仕事しに来てるついでで今までの成果を整理しておこうかなと思ったわけで、重い腰を上げての Ansible オレオレベストプラクティスです。
Ansible のバージョンは今 1.8.2 っぽい。

# 概要

* 全体で百台未満クラスの１Webサービスプロジェクト用（そのもののプロジェクトで培った知見でコレを書いている）
* 丸コピーによる再利用性しか考慮していない（同列の別サービス展開時はフォルダ丸ごとコピーして設定を書き換えれば使えるようにしてある） 
* 論理NW分割
* 本番サーバは役割分割を明確にしてあるけど、開発環境、ステージング環境は大人の都合で混ぜ混ぜ
* 丸ごと github にうｐすれば終わりな気がするんだけど、さすがにちょっと。。。ｗ

# tree

わかる人はここだけ見ればいいはず。
(文字化けしたんで手で直したら使う罫線文字間違ったっぽいｗ)
いちいち書いてないけど、各フォルダの中身は省略しまくり。

<pre>
.  # Ansible を置くためのフォルダを作ってその下でまとめる
├ ansible.cfg  # [設定ファイル](http://qiita.com/raki/items/3f9230d98cf4b8e1d07a)
├ inventory
｜ ├ group_vars  # inventory file と同じ高さに group_vars フォルダ（Inventoryをフォルダ分けしたから）
｜ ｜ ├ all      # 全 role で上書きを必要とするデフォルト値を設定（他のファイルとdiff可能なようにしておく）
｜ ｜ ├ ifg_local   # Inventory File で Group を使ったらそれ用のファイルを作ると便利
｜ ├ host_vars      # hosts_vars も inventory file と同じ高さに必要
｜ ｜ ├ localhost   # group_vars で 設定した上で、マシン固有の設定を上書きする（同系列の別マシンの設定など）
｜ ├ local        # inventory file は論理NWごとに作る(localは開発メンバー用)
｜ ├ production   # 本番環境サーバ群
｜ ├ sandbox      # うちでは開発用
｜ ├ share        # 主に本番用のログや監視データ収集用のNW
｜ ├ staging      # 本番前のステージング環境
｜ └ vagrant      # Ansible 含め個人用の開発環境用（状況に応じていずれかの環境の設定とほぼ同じになる）
├ playbook
｜ ├ infra.yml    # インフラ用の随時実行用（ユーザ管理とか）
｜ ├ phase01.yml  # サーバ起動時に一回だけやる（SELinuxの設定とかファイルディスクプリタの設定とか。この後一回rebootしてる）
｜ ├ phase02.yml  # 言語環境を整える（Pythonはxbulid, Ruby は rbenv, PHPはremiでベタ。あと ant 入れてる）
｜ ├ phase03.yml  # システム監視用のツール入れてる（sysstat,logwatch,etckeeperとか）
｜ ├ phase09.yml  # 全サーバ共通の監視ツール類（munin,zabbix,fluentd）
｜ ├ ping.yml     # 初回接続テスト用。 ベタにタスクを書いて、使用してる varsファイルとか設定を echo させてる
｜ ├ servers_local.yml   # ローカル開発マシン用のタスク
｜ ├ servers_vagrant.yml # inventory にあわせて環境向けタスク
└ roles
    ├ ant
    ├ capistrano
    ├ etckeeper
    ｜ └ tasks
    ｜     └ main.yml
</pre>

これで、実行は（ansible.cfgが設定済みであること）下記のようにできる
<pre>
\# head ansible.cfg
[defaults]
hostfile       = ./inventory/local

\# 2015/07/24 先日Ansibleのバージョンアップをして 1.9.2 にしたら設定名が inventory になってたのでこっちでも可
\# inventory       = ./inventory/local

\# プレイブックコマンドにプレイブック渡すだけ
$ ansible-playbook playbook/ping.yml 

\# 実際にはこんな手順で確認してから実行してる。
$ ansible-playbook playbook/ping.yml -l 対象ホスト --list-hosts
$ ansible-playbook playbook/ping.yml -l 対象ホスト --list-tasks
$ ansible-playbook playbook/ping.yml -l 対象ホスト --tags=タグ --list-tasks
$ ansible-playbook playbook/ping.yml -l 対象ホスト --tags=タグ
</pre>


# 説明など

* なんで本家で説明がないのかわからないけど、ちょっとした規模になるとファイルが多くなって見にくくなるので、最初からトップディレクトリは ansible.cfg, inventoryフォルダ, playbookフォルダ, roles フォルダに分けておくといい
* inventory,playbook のフォルダ名は好きに決められる。短くしてもいいけど、他の慣れてないメンバー用にわかりやすい名前にした。実行時は補完が効くのでさほど面倒でもない
* roles,group_vars,host_vars はansible規定の名前にしておくことで自動読み込みさせるので変更しない
* 上に書いてるけど、inventoryフォルダを作ったら、group_varsとhost_varsはinventory file と同じ高さにする必要がある
* inventory ファイルのホスト名は短いサーバ名、管理できる単位にしておく、実際のホストのIP変換は /etc/hosts でやらせる。ローカルの vagrant 環境で仮の論理NWテスト後に実機に持っていった時に便利なので。
* playbook は特に目新しいことをしないけど、本番やステージング環境用のときは hosts をちゃんと縛っておくと後で問題になりにくいはず
* 後述のとおり、各機に対してインストール作業だけを行うPBを実行、それとは別に環境毎の設定値で設定を行うPBを実行、って形にすると管理もタスクも楽でいい。他のメンバーに説明するときにも簡単
* roles は基本的にインストール及びそれに付随する処理だけを書く。一度にいろいろやろうとしないほうが吉
* 極端な話 yum install だけならそれに越したことはない感じ。せいぜいログやデータディレクトリを用意してあげる必要があるとか、phpizeとかで手順が必要な場合とか、そのくらい。できるだけデフォルトでフラットな状態にするだけにする
* roles/servers_XX ってロールで、設定ファイルの書き換え等だけをさせる。group_vars や hosts_vars はここで主に使われる
* サーバプロセスの再起動等は出来るけどやらせないほうがタスクがすっきりしていい気がする。複数環境が乗ってるサーバでは下手に再起動するのもアレだし
* rolesにvars,defaultsフォルダを使えるけど、追いかけるのが大変になるので、使わないほうがいい気がする
* j2 で {{ my_val | default('デフォルト値') }} ってすればいいだけ。group_vars,host_vars で myval: 値を書けば上書きできる
* 理想的には１つのroleは数個のタスクとテンプレートで構成され、単独でデフォルト値が設定されて実行可能であり、group_vars,host_varsで上書き設定可能であるのが望ましい感じ

# 雑感とか

* OSを統一できるところで働いているので気にしていないけど、複数のディストリビューションで環境を作る場合は、AnsibleよりChefのほうが書き方を統一しやすくていいと思う。
* ssh まわりはちまちまはまることがあるけど、paramikoなのかそうじゃないのかを考えれば割とわかる
* with_itemsからのtemplateからのJ2展開は、エスケープに気を使う。

# あとがき

* Towerとかちょっと使ってみたいんだけど、そういう話が出来る人が近くにいないんだよね。
* Ansibleで、ってゆうよりも、サーバをどういう状態にセッティングするか、個々のプロセスやサービスの設定をどうするか、みたいな話をする場が欲しいな。
* 今やってるプロジェクトがリリースされたらこの記事の内容ももうちょっと進化してるはずなので、そしたらまた更新する予定。