単一 Playbook のすすめ

# はじめに

この記事は[Ansible Advent Calendar 2019](https://qiita.com/advent-calendar/2019/ansible)の4日目の記事です。
[Ansible を始めた5年くらい前](https://qiita.com/search?utf8=%E2%9C%93&sort=&q=ansible+user%3Araki)は一生懸命冪等性の高い[共通ロールを書くことに注力してた](https://github.com/officel?utf8=%E2%9C%93&tab=repositories&q=ansible&type=&language=)けど、最近は単一の仕事をする Playbook を推してる、という話をします。

role ≈（Macのニアイコールってこれなの？≒とは違うの？） Playbook って便利だよって話です。それな！って思う人は以下読まなくても大丈夫。あと role 至上主義の人も読まなくて大丈夫ｗ

# 共通ロール

みんな大好き [Ansible Galaxy](https://galaxy.ansible.com/home) ですが、帯に短し襷に長し、ということはよくあります。
自作の非公開roleを作ってるところも多いと思います。
結果的に、inventory や vars 等を駆使して、ぱっと見どこで何が起きてるのかはよくわかんないけど、Playbook になってるから大丈夫でしょ、みたいな危険な状態にあるところも少なくないのではないでしょうか。
お手元の playbook について、チームメンバーが全員理解してほいほい叩けるようになっていますか？本当に？
そんなにあれこれする機能は実際に必要？絶対に？
サンプルに書いてあった通りに使ってるだけで、本来の設定見逃してない？大丈夫？
OSのバージョンアップに合わせて when 句書き直したりファイル追加したりしてない？面倒じゃない？

# 単一 Playbook のすすめ

Ansible role のメリットや素晴らしさを否定するつもりは毛頭ないのですが、前述のように、使いもしない別ディストリビューションのためのコードが入っていたり、タスク実行時点でどんな値になっているのか判断しにくい状態（defaultとvarsがroleにあってinventoryにも変数があるような）で、実行に対する心理的安全性は確保できると思いますか？

OSS的に多数の人に使われているから安心なコード？何が起きてるのか自分で把握してないのに？本当に？

書いた自分はわかってるから、チームメンバーがそれを理解しないのはその人のせい？

チームメンバーが書いたやつだし実行して問題が起きても自分の責任じゃない？いつか自分がメンテしなきゃいけないかもしれないのに？

というわけで、最近は role はまったく書かずに、一仕事するためだけの playbook をよく書いています。

role の task のうち、必要なものだけをストレートに実行するだけの playbook です。

role から task の特定のディストリ部分だけ抜き出してきて　playbook のタスクに貼った、と認識して概ね間違いないです。

# メリット

- 読めば何が起きるのか把握しやすい（あっちこっち飛ばさない。ストレートに実行する。自分で使うディストリビューションに合わせて書いてある。そういうレベルでしか書かない）
- テストが書きやすい（必要なら自分の中でチェック書けば済む。サーバの出来上がりは別途specで書けばいい）
- やることしか書かないので、無駄がない（よくわかってない別ディストリビューションのお作法は今は必要ない）
- 実行方法についてのメモが残しやすい（コメントで自身のファイルに書いておくと後で便利）
- （使用しているディストリビューションに差がないなら）使い回しがきく
- 設定ファイルを配置する（files/*とかを配置する）を1つ用意しておくと便利
- 特定のサーバ向け Playbook が欲しいなら、サーバ名.yml を書いて、import_playbook すればOK。設定値をサーバ名.ymlに書いちゃうのも安全安心で個人的にはおすすめ。実行時にその値になるはずだし。
- プロジェクト用のインフラリポジトリがある場合に、コピペして置いておけば困ることはほぼない（複数のプロジェクトで一斉にソフトウエアバージョンアップを強制するとかアホな事案でもない限り）


# デメリット

- 全サーバをペット化していて、どの子にどのplaybookがあたっているのかを管理したい場合にはちょっと不向き（それこそサーバ用playbook書けばいいけど）
- サービス再起動系のタスクを追加しておきたい（でかい role にありがちなアレ）は実現しにくい
- 全プロジェクトで流用して管理したい、というのにはむいてない（理想的共通化プロジェクトにはむいてない）
- 対象製品（サービス）のバージョンアップや設定変更による本家 Galaxy role への追従は手動になる（そもそも気づけなくなりがち）

# メリデメとはちょっと違う話

- これまでのペットなサーバ構築と違って、packer でゴールデンイメージを作成してオートスケーリングで使用する場合には、packer 向けに import_playbook か必要なだけ ansible 実行を継ぎ足せばいい
- 稼働中のインスタンスに playbook を充てるのはユーザ追加等の運用だけで十分
- この場合、呼び出されている playbook のファイル名自体で何をしようとしているかがわかるととても楽
- 読めばわかる、的な複雑怪奇なroleを管理するより単一のファイルで完結できるほうが心理的な負担は少ないし、なにより引き継ぎが楽

# 実際には

- playbook フォルダを複数切ってる（インストール用とか設定ファイル用、packer用とか）
- galaxy role で複雑な設定をしないといけないツールは使用しないようになった（正確には DataDog Agent だけ残ってるけど。それ以外のツールは yum 等のパッケージマネージャか github からDLして入れる感じに整ってきた（だからこそ単一 playbook でそれぞれ分離ができてるのかも）
- role 適用でインストールして設定も送り込んでサービス再起動して、みたいなのがなくなった。インストール用 playbookあてて、必要なら設定ファイル配置用の playbook をあてて、で終わりにする感じ。何が起きるか、ではなく、何を配置したか、で考えられる
- もっとも、既存のプロジェクトはそうなってないし、レトロ開発が続いてるところはまだまだあるけれども

# 最後に

大雑把にフォルダ構成はこんな感じ。ちなみに ansibleディレクトリの隣は terraform ディレクトリ。

```
├─ ansible
   ├── files
   ├── inventories
   │   └── aws
   ├── logs
   ├── packer
   ├── playbooks
   ├── playbooks_aws
   ├── playbooks_packer
   ├── playbooks_install
   ├── playbooks_conf
   ├── playbooks_tools
   └── roles
```

# おまけ

公開はしてないのでリポジトリにはないけど、こんな感じってゆう例。

Amazon Linux 2 を使った常に最新を反映させる packer 向け ansible プロビジョナの playbook。

```
ansible $ cat playbooks_packer/base.yml

- name: base AMI
  hosts: all
  become: true
  gather_facts: yes

  vars:
    install_package:
      - git
      - 省略

  tasks:
    - name: Install packages
      yum:
        name: "{{ install_package }}"
さらに省略

- import_playbook: ../playbooks_tools/datadog.yml
- import_playbook: ../playbooks_tools/kubectl.yml
- import_playbook: ../playbooks_tools/aws_iam_authenticator.yml
```