Ansibleのincludeとloop_varで複数のタスクを適切な変数名でループする

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

渡辺です。

Ansibleのwit_itemsのループは単一タスクしか繰り返すことができません。 今日は、複数のタスクをループさせる場合に役立つincludeloop_varを紹介します。

with_itemsは単一タスクしかループできない

例えば、複数のシステムユーザを作成する時、ユーザ毎にタスクを作成したならば、ユーザ数のタスクが必要です。 可読性が悪いだけでなく、コピペの弊害は修正作業に大きな影響を与えます。

- debug:
  msg: "user=user1"
- debug:
  msg: "user=user2"

このような場合、Ansibleでは with_itemsを使うことでタスクを複数回実行できます。

- debug:
    msg: "user={{ item.name }}"
  with_items:
    - user1
    - user2

ところが、with_itemsは単一タスクをループするため、複数のタスク、例えばユーザ作成とグループ作成をループさせることはできません

このため、ループをタスクの数だけ行うことになります。

- name: user
  debug:
    msg: "user={{ item.name }}"
  with_items:
    - name: user1
      group: A
    - name: user2
      group: B
- name: groups
  debug:
    msg: "group={{ item.group }}"
  with_items:
    - name: user1
      group: A
    - name: user2
      group: B

変数はvarsなどに追い出せますが、いけてません。

次のようなイメージで定義できると幸せになれます。

# ここから
- name: user
  debug:
    msg: "user={{ item.name }}"
- name: groups
  debug:
    msg: "group={{ item.group }}"
# ここまでをループさせたい
  with_items:
    - name: user1
      group: A
    - name: user2
      group: B

複数のタスクをループさせたい場合includeを利用する

includeは外部ファイルに定義されたタスクを取り込む機能です。 Playbookが肥大化してきた時にファイルを分割するために利用したり、検証環境と本番環境で異なるタスクを実行させた場合に利用することができます。

- include: inner-tasks.yml

includeするファイルにはタスクを定義します。

# inner-tasks.yml
- debug:
    msg: "Hello"
- debug:
    msg: "World"

includeもまたwith_itemsでループ可能です。 したがって、次のように記述すればinner-tasks.ymlが2回実行されます。

- include: inner-tasks.yml
 with_items:
    - hoge
    - huga

ループ変数はitemで参照できます。 次のように書き換えれば、ループ変数を利用できるでしょう。

# inner-tasks.yml
- debug:
    msg: "Hello"
- debug:
    msg: "{{ item }}"

しかし、includeされるファイルでitemは変数名としていけてません。

ループ時の変数を定義するloop_var

loop_controlloop_varを利用すると、ループ時の変数を制御可能です。

- include: inner-tasks.yml
 with_items:
    - hoge
    - huga
  loop_control:
    loop_var: user

これでitemではなくuserを変数名として利用可能です。

# inner-tasks.yml
- debug:
    msg: "Hello"
- debug:
    msg: "{{ user }}"

まとめ

includeloop_varを利用することで、複数のタスクを適切な変数名でループさせることができます。 PlaybookやRoleの可読性向上には必須テクニックなので必ず覚えておきましょう。

最後にサンプルコードです。

---
# loop_control.yml.yml
- hosts: localhost
  connection: local
  gather_facts: False
  tasks:
    - include: inner.yml
      with_items:
        - name: user1
          group: A
        - name: user2
          group: B      	
      loop_control:
        loop_var: user
---
# inner.yml
- name: user
  debug:
    msg: "user={{ user.name }}"
- name: group
  debug:
    msg: "group={{ user.group }}"