これからAnsibleを勉強する際におさえておきたいこと

# 概要

これからAnsibleを勉強される方で以下のポイントをおさえていれば、効率的に勉強できるかと思います

# 入り口

入り口はやはり体系的に情報がまとまっている書籍がお勧めです

- [Ansible徹底入門](https://www.amazon.co.jp/dp/B06XRSF9HX/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)  ←私はこれから入りました
- [Ansible実践ガイド](https://www.amazon.co.jp/dp/B01NAH7NAA/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)
- [初めてのAnsible](https://www.oreilly.co.jp/books/9784873117652/)

# 公式ベストプラクティス

各種リソースのファイル構成や命名規則などが記載されています
それ以外はトライ＆エラーで自分たちにあったモノを見つけていくことになります

最低限公式のベストプラクティスを読みましょう
https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html

さくらインターネットさんが公開している
「[実践！Ansibleベストプラクティス（前編）](https://knowledge.sakura.ad.jp/3084/)」
「[実践！Ansibleベストプラクティス（後編）](https://knowledge.sakura.ad.jp/3086/)」

Think IT
「[より実践的なPlaybookを作り上げる](https://thinkit.co.jp/article/9871)」

Qiita
「[Ansible オレオレベストプラクティス](https://qiita.com/yteraoka/items/5ed2bddefff32e1b9faf)」

# それなりのシステム規模になるなら

**必ず命名規則を作りましょう**
Ansibleに限らず規模が大きくなるとソース管理が課題になります
一定の規約を設けて管理することをお勧めします

規約例)

```markdown:code_policy.md

- タスクやプレイブック内で宣言した変数は**アンダースコア**から開始する変数名にすること(`_xxx`)
- `register`の変数名は`_result_xxx`とする
- 変数名、ロール名、playbook名、ファイル名、タスク名の命名規則はスネークケースとする(Ansibleの規約)
- 変数名の開始文字列に **`ansible_`を使用してはならない**(Ansibleの予約変数名)
- jinja2テンプレートはファイル名に`j2`を含めること(区別するため)
- 環境ごとに変数の階層分けする場合は、以下のように命名すること
    - 本番用：`prd`
    - 本番検証用：`prd_dev`
    - システム管理用(ansible、zabbix)：`sys`
    - ステージング環境の場合は、ファイル名に`prd`（本番）、`dev`（開発）
- YAMLファイルの先頭行は`---`を必須
- 変数ファイルはYAMLファイルを用いる(JSONはコメントを記載できないため、不採用)
- 機密情報（パスワード、アクセストークンなど）は情報漏えいを防ぐために**ansible vault**で暗号化する（作成方法は別紙参照）
- タスク名の先頭はそのタスクが属性を表すものとする<br/>
    例）<br/>
    ```
    # AWS関連の場合
    tasks/aws_xxx.yml
    # アプリ関連の場合は
    tasks/app_xxx.yml
    ```
- 実行ログでどのタスクなのかがわかるように`name`を付与する
- whenで同一変数に対して複数のor条件を指定する場合は、`in list`を用いること<br/>
    ```
    # NG
    - debug:
        msg: "test"
      when: myvar == "test1" or myvar == "test2" or myvar == "test3"

    # OK
    - debug:
        msg: "test"
      when: myvar in ["test1", "test2", "test3"]
    ```
- whenのand条件の場合は、以下のようにリスト形式で記載すること<br/>
    ```
    - debug:
        msg: "test"
      when:
        - myvar == "test1"
        - myvar2 == "test2"
        - myvar3 == "test3"
    ```
- jinjaテンプレート内のコメントは`{#- hogehoge -#}`を使用すること<br/>
    ```
    - set_fact:
        _hoge: >-
          {#- hogeを作成 -#}
    ```
- AWSリソースのタグキーはスネークケースとし、各単語の最初を大文字とする<br/>
    固有名詞や略語は、すべて大文字で可とする
    ```
    Name: hoge
    APP_Version: 5.1.1
    ```

## 自作モジュール
- モジュール名の接頭語に`hoge_`とすること
- 冪等性を担保するような実装にすること
    （すでに状態を満たしている場合は、処理をしない）
- 適宜にコメントを残すこと（特にビジネス条件にかかわる部分）
```

# すでにDockerを使っているなら

環境をすぐに破棄することができるDockerコンテナで勉強すると効率的
また、複数台や種類（Centos、Ubuntuなど）の環境も容易に準備できる点も魅力
Qiita「[Docker内でAnsibleの勉強をしよう](https://qiita.com/comefigo/items/34209c391962ab0c8f1b)」


# 認証情報を扱うならば

**必ずAnsible Vaultで暗号化しよう**
これで認証情報もソースコードにコミットしても安心

https://docs.ansible.com/ansible/devel/user_guide/vault.html

# 対話形式のインストーラを扱うならば

**expectモジュールを使いましょう！**
忘れずに実行環境でpythonのpexpectをインストール

ハマリポイントに気を付けてください
[【小ネタ】Ansible expect モジュールの罠](https://ceblog.mediba.jp/post/155987719127/%E5%B0%8F%E3%83%8D%E3%82%BFansible-expect-%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%81%AE%E7%BD%A0)

# 楽したい。既存コードを参考にしたい

**[Ansible Galaxy](https://galaxy.ansible.com/home)を使用しましょう！**
さまざまなコードが公開されていて、[ansible-galaxy](https://docs.ansible.com/ansible/latest/reference_appendices/galaxy.html#the-command-line-tool)コマンドですぐに使用できる

# 実運用でAnsibleを使用するならば

**AWXもしくはAnsible Towerを必ず導入しましょう**
GUIでAnsibleを操作でき、実行履歴、実行権限の制御、他システム連携が容易なRestAPIなどが利用できる
機能的にAWX=Ansible Towerであるが、サポート有や安定性が優れているのがAnsible Towerです
経済的に余裕がある場合は是非Ansible Towerの導入を検討してください

参考：
- 「[Docker版AWXの構築方法](https://qiita.com/comefigo/items/8ea716f8cf2510a9c15e)」
- 「[高可用性のAWXをAWSで構築する方法](https://aws.amazon.com/jp/quickstart/architecture/awx/)」
- 「[AWX17.xをクラスタ(HA)構成にする方法](https://qiita.com/comefigo/items/fb0e904fea609f46508b)」

## API経由で渡される変数は処理中に上書きできない！

**AWXやAnsible TowerのAPI経由で渡される変数はextra vars扱い（最優先の変数）で処理中にその変数を上書きすることができない**
ただし、存在しないキーを追加したり、変更することはできる
ローカルで動いたが、AWXやTower上で動かないことがあるので要注意！

※[変数の優先順位](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable)

# 変数

ある程度慣れてくると動的に変数を作るケースが増えます
そんな時に「[これだけ覚えとけばもう怖くないAnsibleの（動的）変数](https://qiita.com/comefigo/items/cd91aeb568141d30b03b)」

# 自作モジュール

たいていのことはAnsibleで提供されているが、自作しなければならない時は怖気ずに「[Ansibleのモジュール開発](https://dev.classmethod.jp/server-side/ansible/ansible-develop-module-basis/)」を順に読んでいきましょう
非常に簡単にできる！

参考：[aws向けAnsible自作モジュールを作る](https://qiita.com/comefigo/items/26b44a9f4fbd7e80cd89)

# デフォルトはAll or Nothingではない

Ansibleのタスク実行は同一タスクを複数ホストに対して並列処理されます
デフォルトの設定では**すべてのホストがエラーにならないと処理が中断しない**
なので、デフォルトのままだと**どれかのホストでエラーが発生してもスルー**されますので、危険です！

all or nothingにするためには、エラーの許容量を`max_fail_percentage`で定めることができる
必ず設定しておくことをお勧めします！
ただし、操作対象のホストに到達不可の場合はエラーと見なさないので、`any_errors_fatal`を利用しましょう！


https://docs.ansible.com/ansible/latest/user_guide/playbooks_delegation.html?highlight=max_fail_percentage

# APIコール系のモジュールには必ずリトライ処理（もしくはパラメータ）を追加しましょう！

APIをコールして何かする系のモジュールでは、コール先がコール制限（1秒間にコールできる数）やネットワークの品質によるエラーになることが割とあります。そのたびに処理が中断されるのもつらいので、冪等性を担保しつつリトライ処理を実装しましょう！（※ここで言う冪等性はリトライ処理した分だけリソースが追加されないようにということです）

以下の3つの対策

1. 自作モジュールの場合は、リトライ処理をモジュール内に実装
2. 公式モジュールの場合は、`retries`パラメータが用意されているのあれば、設定しましょう！
3. [until](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#retrying-a-task-until-a-condition-is-met)を用いてリトライ処理も可能

# 開発環境

VSCodeで開発するならば「[Ansible開発環境はこれで決まり！ for VSCode](https://qiita.com/comefigo/items/31588ebf13a856f1e9e3)」でOK（特にWindowsユーザにおすすめです）
Dockerを使用しますが、Dockerのことを意識せずに使える

# これから始めるならAnsible 2.10.xを使いましょう！

2.10.x未満と2.10.xでモジュールの構成がガラっと変わっています。

AWSのEC2のモジュールを例に

2.9.xまでは[ec2モジュール](https://docs.ansible.com/ansible/2.9/modules/ec2_module.html)

```
- ec2:
    key_name: mykey
    instance_type: t2.micro    
```

2.10.xから[amazon.aws.ec2モジュール](https://docs.ansible.com/ansible/latest/collections/amazon/aws/ec2_module.html)

```
- amazon.aws.ec2:
    key_name: mykey
    instance_type: t2.micro
```

2.9.xまでは多くのモジュールがAnsibleのリポジトリでかんりされていましたが、それらをモジュールごとに分離されました。
AWS関連のモジュールは[こちら](https://github.com/ansible-collections/amazon.aws)で管理するようになりました。
一応2.10.xで2.9.xのモジュール名も動作するようですが、すべてが動作保証されているわけではないので、これから始めるのであれば2.10.xで覚えたほうがよいでしょう！

参考1：[Ansible 2.9→2.10の変更点まとめてみた](https://dcn-f.hatenablog.com/entry/2020/05/24/172114)
参考2：[Ansible 2.10 の変更点: 付属モジュールのAnsible Collectionへの移行](https://qiita.com/pwdtnx/items/8093c7c60dda738fd817)

# Python3で始めましょう！

Python2のサポートが切れているため、AnsibleもPython3対応が必要です！
基本的にAnsibleが動作する環境と操作対象端末でPython3の導入が必須になります。

※Python2で動作しなくなるわけではなく、あくまでサポート切れしているので組織内で対応を決めて対応しましょう！

参考：[AnsibleをPython2.xからPython3.xに対応させる手順とトラブルシューティング](https://qiita.com/comefigo/items/766d42100356bdea8ff8)

# AWSのEC2接続用SSMプラグインを考えているなら要注意！

普段使いならEC2にSSH接続しますが、認証情報の管理をすべてAWSに統合し、SSH鍵の管理から解放する意図でSSMプラグインに切り替えるのも一つの選択肢です。ただし、同時接続ノード（30以上）が多い場合は、SSMの利用はお勧めしません。
理由としては、SSM接続時にAWS APIをコールするのですが、そのAPIコールレートの制限に抵触し、エラーになります。


# 不安！聞ける人がいない

大丈夫！[日本のAnsibleユーザコミュニティ](https://ansiblejp.slack.com/)(Slack)がありますので、お気軽に質問してください！
レスポンスもよく、安心の日本語で回答してくれます