この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
渡辺です。
Ansibleのwit_items
のループは単一タスクしか繰り返すことができません。
今日は、複数のタスクをループさせる場合に役立つinclude
とloop_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_control
のloop_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 }}"
まとめ
include
とloop_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 }}"