Ansible LintによるPlaybookのチェック方法
こんにちは、株式会社SHIFT、自動化エンジニアの水谷です。
AnsibleのPlaybookはYAML形式のテキストファイルなのですが、同じ目的のPlaybookを記述するにしても、書く人によっては使うモジュールが違ったり、細かい表記方法が異なることがよくあります。期待通り動けばそれで良い、という考え方もありますが、後々のメンテナンスや、グループ内外で再利用することを考えると、記述方法がある程度統一されていたほうが良いでしょう。また、なるべくバグを生まない(生みにくい)記述方法で書いていくことは、最終的には全体の工数を削減するポイントになったりもします。
一般的にコードの静的解析ツールを“lint”と呼んだりしていて、いろいろなプログラム言語用のlintがあるのです、実はAnsibleにもこれが用意されています。Ansible用のlintは、 “Ansible Lint”と呼ばれており、これを使えばPlaybookの記述に怪しいところがないかを調べたり、決めたルールに従って書かれているかどうかをチェックしたりできます。
今回はそのAnsible Lintについて書いてみたいと思います。
Ansible Lintのインストール方法
まずは、Ansible Lintをインストールしましょう。インストールはpipで簡単にできます。Ansibleがすでにインストールされている環境であれば、pipも入っているはずですから、エラーになることも少ないでしょう。
pip install ansible-lint
インストールが終了したら、念のためバージョン表示をさせて、Ansible Lintが動作することを確認しましょう。
ansible-lint --version
Ansible Lintの使い方
Ansible Lintの一番簡単な使い方は、引数にPlaybookのファイルパスを指定して実行するだけです。これで、約30項目のデフォルトチェック項目でPlaybookをチェックしてくれます。
簡単な例として、下のようなPlaybook(ファイル名はsite.yml)をチェックしてみます。
---
- name: test ansible
hosts: all
gather_facts: no
tasks:
- name: copy a file
win_copy:
src: "{{ filename1}}"
dest: c:\temp\
- name: copy another file
win_copy:
src: "{{ filename2 }}"
dest: c:\temp\
when: flag == True
以下のコマンドを実行します。
ansible-lint site.yml
結果は、このように2つの問題点が指摘されました。
1つ目は、最初のwin_copyモジュールの呼び出しで、srcに”{{ filename1}}”と指定していますが、よく見ると”1”と”}}”の間にスペースがありません。実際にはスペースが無くても動作するのですが、変数名の前後にスペースを1つ入れることがルールとなっているようです。
2つ目は、“when: flag == True”の行が問題となっています。これは、TrueまたはFalseを持つ変数をwhenで使うときは、TrueやFalseと比較するのではなく、“when: flag”(あるいは“when not flag”)のように記述することがルールになっているからです。
なお、PlaybookがYAMLとして正しく解釈できるか、あるいは存在しないモジュールを使用していないか、などの問題については、“--syntax-check”を付けて実行すれば見つけてくれますので、まずはこちらを実行するべきですね。
ansible-playbook -i hosts site.yml --syntax-check
デフォルトのルール
Ansible Lintのデフォルトルールは、以下のコマンドで表示できます。
ansible-lint -L
しかし、これでは内容が分かりにくいので、以下のページで確認するのが良いと思います。
https://docs.ansible.com/ansible-lint/rules/default_rules.html
ルールはAnsible Lintのバージョンが上がるにつれて、増えていきます。現時点(2020年8月)で最新のバージョン4.2.0では、32個のルールがデフォルトで用意されています。
特定のルールの除外方法
場合によっては、すべてのデフォルトルールが適応されてほしくない場合があります。たとえば、上の例であれば、2つ目のチェックは不要という場合、-xコマンドラインオプションの後にルールIDを指定することでこのチェックを除外することができます。
ルールIDは、上で実行した結果に“[601]”と書いてあるこの数字です。また、上のサイトにもIDが書かれています(“E601”などとあるその“601”がID)。
ansible-lint -x 601 site.yml
これで、1つ目のエラーのみが表示されるようになりました。
また、除外は個々のルールIDだけでなく、ルールタグで指定することもできます。例えば、モジュールに関するルールは4つあり、それぞれ401、402、403、404のIDを持っています。そしてこれらのルールには“module”というタグがついていますので、-x moduleとすることで、これら4つのルールはすべて適応されなくなります。
なお、タグを調べるには、ansible-lint -Tと実行すると、どのタグにどのルールIDが含まれるかが分かります。
また、.ansible-lintというテキストファイルを作成し、以下のように記述しておくことでもルールの除外ができます。毎回コマンドラインで指定するのは面倒ですし、たくさんのルールを除外したい場合は特に、コマンドラインに記述するよりこちらのほうが便利ですね。
skip_list:
- 601
- module
.ansible-lintでこまかな調整
先ほど.ansible-lintファイルに除外するルールを記述する方法を書きましたが、このファイルではこれ以外にもAnsible Lintの動作を変更する設定が記述できます。それらを紹介してみたいと思います。
exclude_path:
ルールチェックを除外したいディレクトリを指定します。ここに列挙したディレクトリはチェックされません。
exlude_path:
- ./roles/dummyrule/
- ./roles/installChrome/test/
tags:
skip_list:の逆で、適応したいルールをタグで指定します。
tags:
- idiom
- module
parseable:
結果を後からパースしやすい1行1結果の形式で表示(出力)します。
parseable: True
これ以外にもまだありますので、詳しくはこちらをご覧ください。
https://docs.ansible.com/ansible-lint/configuring/configuring.html
noqaによるFalse positiveの回避
最後に、静的チェックツールにつきもの(?)の、正しい記述なのにチェックに引っかかってしまうケースへの対応方法を紹介します。
Playbookにおいて、Ansible Lintによるチェックを避けたい行に # noqa [ルールID]を記述しておけばOKです。例えば、上の例でルール601のチェックを受けなくするには、以下のようにします。
- name: copy another file
win_copy:
src: "{{ filename2 }}"
dest: c:\temp\
when: flag == True # noqa 601
CI/CDでAnsibleを使って環境構築を行う場合などでは、Playbookを実行する前にAnsible LintでPlaybookをチェックしてから実行すると良いと思います。また、今回は書きませんでしたが、Pythonのコードで独自のルールを作成することもできます。
Ansible Lintは、Ansibleをしっかり使っていく上では、かなり有用なツールですので、Ansibleをガッツリ使っていこうという方は、是非Ansible Lintも合わせて使ってみてください。
――――――――――――――――――――――――――――――――――
お問合せはお気軽に
https://service.shiftinc.jp/contact/
SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/
SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/
SHIFTの導入事例
https://service.shiftinc.jp/case/
お役立ち資料はこちら
https://service.shiftinc.jp/resources/
SHIFTの採用情報はこちら
https://recruit.shiftinc.jp/career/