最近のAnsibleの使い方(2017末〜2018年初頭)

## Ansibleおじさん化

ここ半年ほど、やたらとAnsibleばかり書いています。プロダクトコードは全く書いておらず、完全にAnsibleおじさんと化しています。

主に環境構築を行うためのPlaybook/Roleを作成しています。

色々やる間に何回か大きな方向転換を行い、なんとなく軌道に乗ってきた感があるので、一度自分の考えを整理するのと合わせて書いてみます。

以降では、以下のような前提に立って記載しています。

-   Ansible 2.4
-   Ansibleを実行するhostはAmazon linux

## ディレクトリ構成

ディレクトリ構成は、基本的に [Ansibleのベストプラクティス](http://docs.ansible.com/ansible/latest/playbooks_best_practices.html) に従っています。ただ、厳密にやると辛いので、実際には以下のようにしています。

```
├── ansible.cfg
├── decrypt.sh
├── encrypt.sh
├── hosts
├── playbooks
│   ├── common.yml
│   ├── ap-server.yml
│   ├── database.yml
│   ├── deployer.yml
│   └── batch.yml
├── requirements.txt
├── roles
├── run-test.py
├── site.yml
└── test
```

playbooksに置いているplaybookは、全てsite.ymlにinclude\_playbookされており、実際に実行する場合は以下のようになります。

```shell
$ ansible-playbook -i [対象ホスト] site.yml
```

また、原則として全部のtaskにtagを設定しているので、 `-t` を利用して、特定のtask/roleだけ実行できるようにしています。

## group\_varsの戦略

今いるプロジェクトは、本番・検証環境がかなり多いという特性があります。そのため、一ファイルに全部書く、というのは結構厳しいです。

現状は以下のような構造にしています。（hosts以下は前述と一緒です）

```
├── ansible.cfg
├── decrypt.sh
├── encrypt.sh
├── hosts
│   ├── prod
│   │   ├── prod1
│   │   ├── prod2
│   │   ├── prod2
│   │   └── prod2
│   └── verify
│       ├── verify1
│       ├── veirfy2
│       └── verify3
├── playbooks
│   ├── common.yml
│   ├── ap-server.yml
│   ├── database.yml
│   ├── deployer.yml
│   └── batch.yml
├── requirements.txt
├── roles
├── run-test.py
├── site.yml
└── test
```

こういう構成にすることで、以下のような効果を狙っています。

-   環境毎のinventoryを管理できる
-   環境毎、group毎の変数管理が（ある程度）わかりやすい
-   似た環境でもあえて分けることで、環境毎に変更内容が独立させられる
    -   group_vars以下がいい感じに肥大していくのとトレードオフですが。。。

## vaultを使う

Ansible自体はそれなりに利用していましたが、ansible-vaultは利用したことがありませんでした。ただ、今回は利用しないとむしろ管理が面倒になりそうでした。

-   環境が多い上に、諸事情でRDBのパスワードをAnsibleで持っておく必要がある
-   SSHでのアクセスが公開鍵ではなく、パスワード認証（・・・）
-   いくつか作成するユーザーのパスワードを保存する必要がある

ansible-vaultの対象ファイルを増やしすぎると、変更時とかに面倒＋時間がかかるので、以下のように（しようと）しています。

```yaml
# secrets.yml
---

secrets:
  user_secret_key: hogehoge

# main.yml
user_secret_key: '{{secrets.user_secret_key}}'
```

## roleのdefaultsに全部のvariableを書く

roleの内、何らかのvariableを渡す必要がある場合、 **必ず** defaults/main.yml にデフォルト値を記載するようにしています。

-   roleで利用する変数は `defaults/main.yml` を見ればわかる
-   `defaults/main.yml` に説明を書くことで、将来のドキュメントにもなる

後、roleで利用するvariableは、 **必ずrole名をprefixにする** というルールにしています。基本、metaで依存を設定しているroleを除いて、変数のoverrideを防ぐ目的でこんなルールにしています。

> プロジェクト外で共有するようなroleでは無いため、わざと暗黙的な依存を作らないように、できるだけそれぞれで独立するようにしています。無論、実質的に依存が存在するroleもありますが、それはplaybookで明示的に記載することでカバーしています。

## ansible-playbookはJenkins（とか）から実行させる

Ansible自体の実行は、個々人のPCからは行わないようにしています。（role/playbookの作成中は当然除く）

ではどうするか、ということでみんな大好きJenkinsおじさんの登場です。Jenkinsにansible-vaultのpassword fileを配置し、Githubから対象のリポジトリをpullしてansible-playbookを実行させるような感じにしています。また、ビルドパラメータとPipelineを使って、以下のようなことをできるようにしています。

-   stage（本番・検証）を選択できるように
-   対象の環境を選択できるように
-   実行するtagを指定できる。Pipelineのinputを使って、実行対象のtask一覧を確認してから実行させるようにしている

基本みんなWindows PCということもあり、変に辛い思いをするくらいなら、Ansibleの実行はJenkins！とすることで、誰でも実行できる＋実行履歴を見られるという効果がありました。

もっとちゃんとやるんであれば、Ansible Towerなどを導入したほうがいいんではないか・・・とは思います。ただ、現状は環境構築くらいしか利用していないので、これくらいでもなんとかなっています。

## Dockerでroleのテストを行う

Ansibleでは、公式でdockerのconnectionを行うためのpluginが用意されているので、これを利用して、Docker + Amazon linux imageでテストを実行できるようにしています。

```yaml
---

- hosts: "[コンテナの名前]"
  connection: docker
  gather_facts: False
  roles:
    - role: ...
```

Dockerコンテナは、事前に起動しておく必要があります。dockerモジュールを利用すれば、テスト用のplaybookだけで完結すると思いますが、後始末とかが面倒なので、スクリプトで実行しています。

こんな感じでroleを実行した後、 [Testinfra](https://testinfra.readthedocs.io/en/latest) を利用してテストケースを流せるようなスクリプトを作成しています。

実際にやってみると、結構ちゃんとテストできます。Ansible自体がべき等であることを求めてくるので、テストもさっくりと書くことができます。

ちなみに、 [Serverspec](http://serverspec.org/) ではなくTestinfraを利用しているのは、現状Rubyを利用するのがNGになっているためです。（PythonはOK）

## 改善の道のりは長い

それなりに色々とやっている感じですが、個人的にはまだまだ満足していません。というか、Roleの書き方に統一感がないとか、暗黙知になってしまっている部分が多いので、そのへんの改善が必要です。

しかし、環境構築をAnsibleに全振りし、Jenkinsから実行できるようにしたおかげで、

-   誰かがいないと動かせない、ということが激減
-   新しい環境が増えても、group\_varsだけ確認すればOK

という感じになりました。プロジェクトの特性とアプリの作り上、環境構築がやたらと多いので、これは助かった感じになっています。

しかし、まだ手作業のぬくもりが残っている部分があるので、そういった部分も巻き取っていきたいと思います。

## 参考サイト

[Laying out roles, inventories and playbooks](https://leucos.github.io/ansible-files-layout)

[Ansibleのインベントリファイルでステージを切り替える](https://qiita.com/NewGyu/items/5de31d76d2488ab27ed6)

[Ansibleを使い出す前に押さえておきたかったディレクトリ構成のベストプラクティス](http://sechiro.hatenablog.com/entry/2015/01/06/Ansible%E3%82%92%E4%BD%BF%E3%81%84%E5%87%BA%E3%81%99%E5%89%8D%E3%81%AB%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%8B%E3%81%A3%E3%81%9F%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF)

[ansibleで実行対象を切り替える方法](http://tdoc.info/blog/2014/05/30/ansible_target_switching.html)