はじめてのAnsible #1 入門編

Ansible便利ですよね。 一度設定ファイルを作ってしまえばあとはコマンド一発で同様のサーバ環境が作れます。対象サーバも一度に何台でもまとめて設定できるのも便利。最近では人間が手作業で実行する日々の運用でも活躍するシーンが出てきました。サーバのみならずクライアント環境に対しても利用できちゃいます。

Ansibleのようなソフトウェアを構成管理ツールと呼びます。同様の物にChefPuppetなど色々ありますが、管理対象のマシンはPythonが入っていれば他に余計なソフトウェア(Agent)をインストールしなくて良いのがAnsibleの特徴でもあり良いところです。

というわけで、ここしばらくサボって使わないでいたらすっかり使い方を忘れてしまったので再入門と相成りました。以前はVagrantとセットで利用していたのですが、今回はmacOS上でPlaybookを実行し、Linuxサーバの構成管理を行います。

ちょっと文量が多くなってしまったので何回かに分けてお話する予定です。今回は基本的な利用方法になります。

インストール

管理対象のサーバ(Linux)

今回はAWS Lightsail上にインスタンスを作成、AmazonLinuxを選択しました。構成管理を行うサーバにはPythonがインストールされており、SSHでログインできるユーザーを作成すれば準備完了です。

Python3

yum等で適当に3系をインストールします。

$ sudo yum install python36 python36-debug python36-devel python36-libs python36-pip python36-test python36-tools python36-lit python36-setuptools python36-virtualenv

$ python3 --version
Python 3.6.8

$ which python3
/usr/bin/python3

今回は3.6.8が入りました。またPythonがインストールされたパスをメモして置いてください。あとで使います。

SSHでログイン可能なユーザーを作成

AWSでインスタンスを作成した際のデフォルトユーザーであるec2-userを利用しても良いのですが、Ansible専用ユーザーを作成しておくのが安全です。今回はansiblemanという名前のユーザーを作成します。

管理者権限のあるユーザーで、新規にユーザーを作成しします。

$ sudo useradd -m ansibleman

SSHでログインできるようPlaybookを実行する端末で作成した公開鍵を所定の場所に保存します。パーミッションの設定をお忘れなく。

$ sudo su - ansibleman

$ mkdir ~/.ssh
$ vi ~/.ssh/authorized_keys
ssh-rsa drftgyhuji..(中略)..ghjkmh ansibleman@mac

$ chmod 0700 ~/.ssh
$ chmod 0600 ~/.ssh/authorized_keys
$ exit

Ansible内でsudoコマンドを利用する場合はvisudoで以下の行を追加しておきます(管理者権限のあるユーザーで実行してください)。

$ sudo visudo
ansibleman    ALL=NOPASSWD: ALL

パスワードの入力を必須にすることもできますし、wheelグループに追加する方法でも大丈夫です。このあたりの設定はお好みでどうぞ。ただパスワードの入力を必須にするとAnsibleでもパスワードの管理を行う必要が出てくるため、ちょっと面倒なことになるのでご注意を。

ここまで終わったら、手元のTerminalなどからログインすることが可能か試してみてください。

Playbookを実行する側(macOS)

今回はmacOS上にインストールします。HomeBrewで一発です。

$ brew install ansible

今回入ったのは2.8.0でした。

$ ansible --version
ansible 2.8.0
  config file = None
  configured module search path = ['/Users/katsube/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/Cellar/ansible/2.8.0/libexec/lib/python3.7/site-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 3.7.4 (default, Jul  9 2019, 18:13:23) [Clang 10.0.1 (clang-1001.0.46.4)]

その他のOSでのインストール方法はAnsibleの公式サイトを参照ください。yumdnfなどの構成管理ツールを利用するケースが多く手軽に入れることができます。 docs.ansible.com

以上で準備は整いました。あっという間です。

最初の一歩

まず最初に接続先情報の定義を行い、Ansibleから無事に接続できるかテストを行います。

ansible.cfgの準備

適当なディレクトリを作成し、その中にAnsibleの設定ファイルansible.cfgを準備します。ゼロから書くのは大変面倒なのでGitHub上にあるAnsibleのリポジトリから雛形をもらってきます。

$ mkdir ~/ansible1st && cd ~/ansible1st
$ wget https://raw.githubusercontent.com/ansible/ansible/devel/examples/ansible.cfg

適当なエディタでansible.cfgを開き、以下のinventory=から始まる行を追加します。右辺の値の名称は何でも良いです。

[defaults]

# some basic default values...

#inventory  = /etc/ansible/hosts
inventory   = ./inventory

接続先のサーバ情報の定義

ansible.cfginventoryで指定したディレクトリを作成し、その中に適当な名前のファイルを作成します。ここではproductionという名前で作成しました。

$ mkdir inventory && cd inventory
$ vi production

このときファイルに.iniなどの拡張子を付けたくなりますが、付けてはなりません。ハマります。(ハマりましたw)

ホスト情報

このファイルへ実際にPlaybookで管理したいサーバの情報をini形式で定義していきます。

[servers]
example.com

[servers]とある箇所はサーバをグルーピングするための物です。名称は何でも構いません。example.comとある箇所はIPアドレスでもOKです。

以下のように複数のホストやグループを同時に定義することもできます。

[web]
web1.example.com
web2.example.com
web3.example.com

[db]
master.db.example.com
slave1.db.example.com
slave2.db.example.com

接続情報

ホスト情報の下のあたりに、今度は接続情報を記述します。内容は見ての通りでポート番号やユーザー名、秘密鍵の場所、最後にPythonのパスを定義しておきます。

[servers]
example.com

[servers:vars]
ansible_port=22
ansible_ssh_user=ansibleman
ansible_ssh_private_key_file=~/.ssh/id_rsa
ansible_python_interpreter=/usr/bin/python3

複数のグループに対して、接続情報をまとめて定義したい場合は[servers:vars][all:vars]とします。

[web]
web.example.com

[db]
db.example.com

[all:vars]
ansible_port=22
ansible_ssh_user=ansibleman
ansible_ssh_private_key_file=~/.ssh/id_rsa
ansible_python_interpreter=/usr/bin/python3

もちろんwebとdbでユーザーが異なる場合は、それぞれ定義してやります。

動作テストしてみる

ここまでの設定が正しく動くか実験してみます。現在の構成は以下の通り。

~/📁 ansible1st
    📒 ansible.cfg
   📁 inventory
      📒 production

ファイルproductionの内容は以下です。

[servers]
example.com

[servers:vars]
ansible_port=22
ansible_ssh_user=ansibleman
ansible_ssh_private_key_file=~/.ssh/id_rsa
ansible_python_interpreter=/usr/bin/python3

ここまで用意できたらいざ動作テストです。以下のmacOS上で次のコマンドを実行。環境によっては起動や初期化でちょっと時間がかかります。Pythonで作られていることもあり動作速度はあまり期待しない方が良いです。

$ cd ~/ansible1st
$ ansible servers -m ping
example.com | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

serversinventory/productionで定義したグループの名前です。指定したグループ内のサーバすべてにpingを実行するコマンドになります。上記のようにホスト名の横にSUCCESSと表示されれば成功です。もし何らかの設定を間違えている場合はこの段階でエラーや警告が表示されます。

  • 複数のグループを定義した際に、すべてのグループに対して実行する場合はansible all -m pingとします
  • カレントディレクトリにansible.cfgが存在している状態で実行してください

はじめてのPlayBook

ansibleコマンドで各種設定を行うことも出来るのですが、まとまった処理を行う場合には「Playbook」と呼ばれる機能を利用します。Playbookは実行したい処理をYAMLで定義したもので、一定のルールに従って記述するだけですので、慣れてしまえばプログラムほど難しくはありません。

HelloWorld

では簡単なPlaybookを作成してみます。ansible1stディレクトリ直下にplaybook.ymlという名前で以下の内容のファイルを作成します。

- hosts: servers
  remote_user: ansibleman
  tasks:
    - name: Write date
      shell: date >> ansible.log

ここではserversグループのサーバ群に対して、date >> ansible.logコマンドを実行します。nameはメモのような物で実際の処理とは関係ありませんが、Ansibleにより処理が成功したか失敗したか表示されるタイミングで利用されますので人間が見てわかるものを記入します。

shellと書かれている部分はAnsibleでは モジュール と呼ばれている部分です。様々な機能のモジュールが最初から用意されており、必要に応じて使い分けていきます。ここではLinux上のシェルで動作させるコマンドをそのまま記述します。同様の機能にcommandモジュールがありますがこちらはリダイレクトやパイプの利用ができません(不便な反面、安全と言えます)。

なおYAMLは意外とフォーマットが細かく決まっているので記述する際には注意してください。

実行する

現在の構成は以下の通りです。

~/📁 ansible1st
    📒 ansible.cfg
    📒 playbook.yml
   📁 inventory
      📒 production

では先ほど作成したplaybook.ymlを実行してみます。実行するコマンドはansibleではなくansible-playbookになります。

$ cd ~/ansible1st
$ ansible-playbook playbook.yml

PLAY [servers] *************************************************************************************

TASK [Gathering Facts] *****************************************************************************
ok: [example.com]

TASK [Write date] **********************************************************************************
changed: [example.com]

PLAY RECAP *****************************************************************************************
example.com: ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

結果表示は見たままで、すべてのタスクでfailedなどの異常が出ていないかを見ます。実行結果も確認しておきます。サーバを覗いてホームディレクトリにansible.logが作成されていたら成功です。

$ ls
ansible.log

$ cat ansible.log 
20191010日 木曜日 18:57:44 JST

Playbookは一度だけ実行する物もあれば、何度も実行する物もあります。後者の場合、なるべくすべてのタスクがokになることを目指してPlaybookを作成するのがAnsibleの流儀のようです。

さて、ここまでできればあとは応用です。この先はいかにPlaybookの書き方をマスターするかというお話になります。

YAMLの基本的な文法

YAMLの基本的な記述方法はプログラマーのための YAML 入門 (初級編)に非常に分かりやすくまとめられていますので、こちらを一読ください。ここでは主要なところだけかいつまんでまとめておきます。

YAMLはもう理解している場合には次の項目へスキップしてください。

データ型

基本的にYAMLのパーサーが自動的に判定してくれますので、特に意識する必要はありません。ただ必ず文字列として扱いたい場合にはダブルコーテーションなどの引用符で囲ってあげる必要があります。

YAML では、以下のデータ型を自動的に判別します。

  • 整数
  • 浮動小数点
  • 真偽値 (true, yes, false, no)
  • Null値 (null, ~)
  • 日付 (yyyy-mm-dd)
  • タイムスタンプ (yyyy-mm-dd hh:mm:ss [+-]hh:mm)
これら以外は文字列として認識されます。また引用符「’」や二重引用符「”」で囲むと、強制的に文字列として認識されます。

プログラマーのための YAML 入門 (初級編)より

配列

先頭にハイフン(-)をつけると「配列」になります。

- りんご
- バナナ
- パイナップル

半角スペース2個分のインデントを設けることでネスト(入れ子)することができます。ネストする際には空の要素が先頭に必要にる点に注意です。

- フルーツ
- 
  - りんご
  - バナナ
  - パイナップル

注意点としては、以下のような書き方は、意図しない動きになります。前者は空の要素もネストされており、後者は空のネストが無いパターンです。

- フルーツ
  - 
  - りんご
- フルーツ
  - りんご

パーサーによるかもしませんがsyntax errorにはならず単なる文字列として扱われますので、誤りに気が付きにくい箇所です。

ハッシュ

コロン(:)でキーと値を挟むことでハッシュ(連想配列)になります。コロンのあとにはスペース1個以上を書きます。

りんご: Apple
バナナ: Banana
パイナップル: Pineapple

ハッシュもインデントすればネスト(入れ子)が可能です。

フルーツ: 
  りんご: Apple
  バナナ: Banana
  パイナップル: Pineapple

ハッシュの配列

配列の要素としてハッシュを持つには以下のようにします。

- name: りんご
  en: Apple
- name: バナナ
  en: Banana
- name: パイナップル
  en: Pineapple

ここまで来るとどこかで見たような形式になってきましたねw

インデント

YAMLはインデントの制約が非常に厳しいです。インデントはスペースのみでタブの利用はできません。通常スペース2個で1インデントとなります。

この階層構造が崩れるといとも簡単にsyntax errorとなってしまいます。試しに以下のようにわざとスペース1個分ずらして実行してみます。

- hosts: servers
  remote_user: ansibleman
  become: yes
  tasks:
    #-- 2行目のshellをスペース1個ずらしてみる --#
    - name: Write date
       shell: date >> ansible.log

実行すると無事に?エラーが発生し処理を行うことができませんでした。

$ ansible-playbook playbook.yml 
ERROR! Syntax Error while loading YAML.
  mapping values are not allowed in this context

The error appears to be in '/home/katsube/ansible1st/playbook.yml': line 6, column 13, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

    - name: Write date
       shell: date >> ansible.log
            ^ here

ansibleではなく何らかのプログラミング言語のパーサーを利用している場合、エラーではなく単なる文字列として解釈される場合もあります。

Playbookを使っていて遭遇するエラーの大半こういった単純な書式のミスの場合が多いので、エディターに書式をチェックしてくれるプラグインを入れると非常に楽になります。

コメント

以下の例のように行頭に#を付けると行末までがコメント扱いになります。

#-----------------------------------------------------
# はじめてのPlaybook
#-----------------------------------------------------
- hosts: servers
  remote_user: ansibleman
  tasks:
   #-- 現在時刻をファイルに記録 --#
    - name: Write date
      shell: date >> ansible.log

エスケープしたい場合には文字列として引用符(ダブルコーテーションなど)で囲うか、バックスラッシュを利用します。

- "引用符の中なら #コメントにならない"
- バックスラッシュでエスケープすれば \#文字列として扱われる

Playbookの基本的な文法

Playbookを書く上での流儀のお話です。

パラメーター

Ansibleのモジュールにはパラメータが設定できます。例えばファイルをコピーするcopyモジュールに、コピー元やコピー先のパスを指定するといったものです。プログラミングで言う「引数」、HTMLのタグで言えば「属性」みたいな物ですね。

パラメータの書式は主に以下の2種類の書き方ができます。

- hosts: servers
  remote_user: ansibleman
  tasks:
   #-- A) ファイルをコピー --#
    - name: Write date
      copy:
        src: ./foo.txt   # コピー元
        dest: ~/foo.txt  # コピー先

   #-- B) ファイルをコピー --#
    - name: Write date
      copy: src=./foo.txt  dest=~/foo.txt

上記の例ではどちらも同じ意味になります。 パラメータは複数指定することが可能ですが、大量に指定する場合には前者を利用した方が可読性が上がります。あとはお好みで使い分ければ良いかと思います。なお通常、パラメータを記述する順番にとくに指定はありません(=srcとdestが逆になっていても問題ない)。

変数

Ansible内で変数を利用できます。以下の例のようにvarで変数を新たに定義し、利用する際には{{ 変数名 }}とします。

以下の例では変数filenameを作成し、shellモジュール内で利用しています。

- hosts: servers
  remote_user: ansibleman
  become: yes
  vars:
    filename: ansible.log
  tasks:
    - name: Write date
      shell: date >> {{ filename }}

注意点としてはvarsで変数を定義する際に、別の変数を参照する際には引用符で囲う必要があります。

  vars:
    log_dir: foo/bar
    log_file: hoge.txt
    log_path: "{{ log_dir }}/{{ log_file }}"

この引用符を外すとsyntax errorとなり停止します。

ERROR! Syntax Error while loading YAML.
  found unacceptable key (unhashable type: 'AnsibleMapping')

The error appears to be in '/home/katsube/ansible1st/playbook.yml': line 6, column 12, but may
be elsewhere in the file depending on the exact syntax problem.

またAnsibleが定義する変数とかぶってしまうため、変数名の冒頭にansible_という文字列はつけないようにします。

ループ

Ansible2.5以降はloop、それよりも古いバージョンではwith_itemsを利用することでループ処理を行うことができます。

例えば以下の例では3つのファイルをそれぞれ別のタスクでコピーしています。

- hosts: servers
  remote_user: ansibleman
  become: no
  tasks:
    - name: copy file A
      copy: src=a.txt dest=~/
    - name: copy file B
      copy: src=b.txt dest=~/
    - name: copy file C
      copy: src=c.txt dest=~/

これは次のように書き換えることができます。

- hosts: servers
  remote_user: ansibleman
  become: no
  tasks:
    - name: copy file A - C
      copy: src={{ item }} dest=~/
      loop:
        - a.txt
        - b.txt
        - c.txt

loopに配列を指定することで上から順番にモジュールを実行してくれます。モジュールを定義する箇所では変数{{ item }}で値を受け取ることができます。

また以下のようにハッシュの配列を渡すともう少し複雑なことが可能になります。

- hosts: servers
  remote_user: ansibleman
  become: no
  tasks:
    - name: copy file A - C
      copy: src={{ item.src }} dest={{ item.dest }}
      loop:
        - { src: a.txt, dest: ~/ }
        - { src: b.txt, dest: ~/ }
        - { src: c.txt, dest: ~/ }

ここに上げた例であればwith_itemsでも同様の処理が可能です。loopwith_itemsはほぼほぼ同じ動作になりますが、階層の深い配列を渡した際の互換性が損なわれています。詳しくは公式ドキュメントComparing loop and with_*の項目を参照ください。

条件分岐

whenを利用することでif文のような条件分岐が可能になります。

以下の例では変数DEBUGの値が真(true)のときにのみshellモジュールを実行します。

- hosts: servers
  remote_user: ansibleman
  become: no
  vars:
    DEBUG: false
  tasks:
    - name: write date when if debug mode
      shell: date >> debug.txt
      when: DEBUG == true

比較演算子として以下のような物が用意されています。

  • ==, !=, <, >, <=, >=
  • and, or
    • when DEBUG == true or USER == "admin"といった形で条件式を連結できます。
  • in, not in
    • when USER in [admin, root]といった形でOR条件の式を簡潔に記述できます。

以前は変数に真偽値が入っている場合== trueは省略できたのですが、将来的に明示的に記述する仕様に変更になるようで現在では警告メッセージが表示されます。

ブロック

前述のwhenでは一度にひとつのタスクに対してのみ条件を設定していましたが、blockを利用すれば複数のタスクにまとめて設定することも可能です。

- hosts: servers
  remote_user: ansibleman
  become: no
  vars:
    DEBUG: true
  tasks:
    - block:
      - name: write date when if debug mode
        shell: date >> debug.txt
      - name: write memory when if debug mode
        shell: free -h >> debug.txt
      when: DEBUG == true

whenを記述するインデントの階層に注意してください。

よく使うモジュール

become - 管理者権限で実行する

管理者権限(root権限)で各種処理を実行したい場合は、becomeyesを指定します。

- hosts: servers
  remote_user: ansibleman
  become: yes
  tasks:
    - name: Write date
      shell: date >> ansible.log

もしくは各タスクに個別に付加することも可能です。

- hosts: servers
  remote_user: ansibleman
  tasks:
    - name: Write date
      shell: date >> ansible.log
      become: yes

becameする際の具体的な処理をbecome_method(su, sudo)で、root以外のユーザーに変更したい場合にはbecome_userを利用します。

- hosts: servers
  remote_user: ansibleman
  become: yes
  become_method: sudo
  become_user: apache
  tasks:
    - name: Write date
      shell: date >> ansible.log
  • 以前はその名の通りsudoというキーワードでしたが、1.9以降からbecomeに変更になりました。

copy - ファイルをコピー

copyを使うとPlaybookを実行する側にあるファイルを、管理対象のサーバへコピーできます。あらかじめ用意した設定ファイルを転送したい場合など便利です。

- hosts: servers
  remote_user: ansibleman
  become: yes
  tasks:
    - name: Copy Apache Config file (VirtualHost)
      copy:
        src: conf/apache/vhost.conf
        dest: /etc/httpd/conf.d/vhost.conf
        owner: apache
        group: apache

この例では以下のように~/ansible1st/conf/apache/vhost.confにあるファイルを、サーバ側の/etc/httpd/conf.d/vhost.confへコピーしています。

~/📁 ansible1st
    📒 ansible.cfg
    📒 playbook.yml
   📁 inventory
      📒 production
   📁 conf
      📁 apache
         📒 vhost.conf ★

パラメーターや実行例は公式ドキュメントなどを参照ください。

lineinfile - ファイル中の文字列を検索置換

既存の設定ファイル等の一部を置換した方が手っ取り早い場合はlineinfileを利用します。もちろんshellでsedコマンドなどを利用しても良いのですが、Ansibleのモジュールに用意されている物を利用しておくと、実行する環境が変化したり、コマンドの利用方法が変わった場合も互換性を維持してくれることが期待できます。

単純な検索置換

以下の例ではApacheの設定ファイルhttpd.confのDocumentRootをデフォルトの物から変更しています。

- hosts: servers
  remote_user: ansibleman
  become: yes
  tasks:
    - name: Edit httpd.conf
      lineinfile:
        dest: /etc/httpd/conf/httpd.conf
        regexp: '^DocumentRoot "/var/www/html"'
        line: 'DocumentRoot "/web/public"'

destのファイル内をregexpで検索しlineに置換します。regexpは検索条件に正規表現を利用できます。

複数同時に検索置換

複数箇所、同時に置換したい場合はwith_itemsloopを利用するとスッキリと書けます。

- hosts: servers
  remote_user: ansibleman
  become: yes
  tasks:
    - name: Edit httpd.conf
      lineinfile:
        dest: /etc/httpd/conf/httpd.conf
        regexp: "{{item.regexp}}"
        line: "{{item.line}}"
      with_items:
        - { regexp: '^Listen 80$', line: 'Listen 8080' }
        - { regexp: '^DocumentRoot "/var/www/html"', line: 'DocumentRoot "/web/public"' }

パラメーターや実行例は公式ドキュメントを参照ください。

yum - パッケージ管理

ApacheやMySQLなどミドルウェアのインストールに管理ソフトを利用することが多いと思いますが、Ansibleからももちろん利用できます。

インストール/削除/更新

その名の通りyumを指定します。nameにインストールしたいパッケージ名、stateにpresentを指定するとインストールされていなければ新規にインストール、インストール済みであれば何もしません。

- hosts: servers
  remote_user: ansibleman
  become: yes
  tasks:
    - name: Install Apache
      yum: name=httpd state=present

削除したい場合はstateの値をremovedにするだけです。

yum: name=httpd state=latest security=yes

またlatestにするとインストールされていなければ新規インストール、すでにインストールされており更新版が存在すればアップデートしてくれます。セキュリティアップデートのみ対応したい場合はさらにsecurity=yesのパラメーターを追加します。

yum: name=httpd state=latest security=yes

同時に複数のパッケージを処理

一度に複数のパッケージを処理したい場合は複数のタスクを書いても良いのですが、with_itemsloopを利用するとスッキリします。

- hosts: servers
  remote_user: ansibleman
  become: yes
  tasks:
    - name: Install Apache
      yum: name={{ item }} state=present
      with_items:
        - httpd
        - httpd-tool
        - httpd-devel
        - httpd-manual

service - サーバの起動状態を操作

serviceを利用するとApacheやMySQLなどのサーバの起動状態をコントロールできます。

起動/再起動/リロード/停止

nameに対象のサーバ、stateにstartedを指定すると、サーバが起動していなかった場合に起動します。

- hosts: servers
  remote_user: ansibleman
  become: yes
  tasks:
    - name: Start Apache
      service: name=httpd state=started

再起動はstateにrestartedを指定します。

service: name=httpd state=restarted

リロードしたい場合はstateにreloadedを指定します。サーバを起動したままで設定ファイルを読み込み直したいときに使うやつです。

service: name=httpd state=reloaded

同様にサーバを停止する場合にはstateにstoppedを。

service: name=httpd state=stopped

OS起動時に自動的に開始する

いわゆるchkconfig onを設定することができます。

- hosts: servers
  remote_user: ansibleman
  become: yes
  tasks:
    - name: chkconfig on Apache
      service:
        name: httpd
        enabled: yes

その他の情報やパラメーターは公式ドキュメントを参照ください。

その他

VSCode用プラグイン

VisualStudioCodeを利用している場合、マイクロソフト謹製のプラグインが用意されています。 https://marketplace.visualstudio.com/items?itemName=vscoss.vscode-ansiblemarketplace.visualstudio.com

またRedhat社から提供されているYAML用の便利プラグインもオススメです。 marketplace.visualstudio.com

警告メッセージ

Pythonのパスを指定していない

以下の警告が表示されても動作するのですが、気持ちが悪いので潰しておきます。

[WARNING]: Platform linux on host example.com is using the discovered Python interpreter at /usr/bin/python, but future installation of another
Python interpreter could change this. See https://docs.ansible.com/ansible/2.8/reference_appendices/interpreter_discovery.html for more
information.

明示的にPythonのパスが設定されていない場合に起こるようなので、Inventory用のファイルにansible_python_interpreterの項目を追加することで表示されなくなります。

[servers:vars]
ansible_python_interpreter=/usr/bin/python3

デフォルトのPython(/usr/bin/python)が2系の場合、3系で動かしたいといった際にもこの指定を行う必要があります。

whenで比較演算子を使っていない

例えば以下のようなwhenの条件を書いてしまうと警告が出ます(途中端折ってます)

  vars:
    isdebug: true
  tasks:
    - name: write date when if debug mode
      shell: date >> debug.txt
      when: isdebug

具体的には以下のメッセージが表示されます。警告なので動きはするのですが気持ち悪いので修正します。

[DEPRECATION WARNING]: evaluating isdebug as a bare variable, this behaviour will go away and you might need to add |bool to the expression in the
 future. Also see CONDITIONAL_BARE_VARS configuration toggle.. This feature will be removed in version 2.12. Deprecation warnings can be 
disabled by setting deprecation_warnings=False in ansible.cfg.

修正はいたって簡単でwhenに明示的に比較演算子を記述します。

  vars:
    isdebug: true
  tasks:
    - name: write date when if debug mode
      shell: date >> debug.txt
      when: isdebug == true

これまでは問題なかったのですが今後は厳密になるようですね。

続く

次回はPlaybookを分割する方法についてです。

blog.katsubemakito.net

参考ページ

初めてのAnsible

初めてのAnsible

Amazon