Ansible での include の良い書き方

よくある書き方の問題点

例えば include_tasks でググってみると、こういう感じの書き方をよく見かけます。

### tasks/main.yml

- name: Include tasks (RedHat 6)
  include_tasks: install_redhat_6.yml
  when: ansible_os_family == 'RedHat' and ansible_distribution_major_version|int == 6

- name: Include tasks (RedHat 7)
  include_tasks: install_redhat_7.yml
  when: ansible_os_family == 'RedHat' and ansible_distribution_major_version|int == 7

- name: Include tasks (Amazon Linux)
  include_tasks: install_amazon.yml
  when: ansible_os_family == 'RedHat' and ansible_distribution == 'Amazon'

この書き方で各種ロールを運用していく中で、いろいろ悩みが出てきました。

  • ぱっと見で when がわかりにくい
  • OS・ディストロを追加するたびに include_tasks が増えていく
  • 例えば RedHat と CentOS で分けたいときに when が更にややこしくなる
  • どれにも当てはまらない場合のエラーハンドリングがしにくい

良い書き方

### tasks/main.yml

- name: Include tasks
  include_tasks: '{{ include_yml }}'
  loop_control:
    loop_var: include_yml
  with_first_found:
    - files:
      - 'install-d-{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml'
      - 'install-d-{{ ansible_distribution }}.yml'
      - 'install-f-{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml'
      - 'install-f-{{ ansible_os_family }}.yml'
      - 'install.yml'
      skip: false

ポイント

  • with_first_found を使う事で、基本的にファイル追加のみで OS・ディストロの追加ができる
  • ループ対象は条件がきついものが最初にあるので、 "RedHat 系だけど CentOS は特別な処理をしたい" 的な事に対応しやすい
  • 当てはまるものがない場合の動きを skip パラメタで指定できる
  • include した先でループ変数にデフォルトの item を使いたいだろう事を考慮し、 include_yml という変数名にしておく

例: Docker CE のインストール

  • RedHat 7 は公式リポジトリからインストール
  • Amazon Linux はアマゾンのリポジトリからインストール
### tasks/install-d-Amazon.yml

- name: Install docker
  yum: name=docker state=present

- name: Install pip
  yum: name=python27-pip state=present

- name: Install docker-py
  pip: name=docker-py state=latest
### tasks/install-f-RedHat-7.yml

- name: Install packages
  yum: name='{{ item }}' state=present
  with_items:
    - device-mapper-persistent-data
    - lvm2

- name: Install Docker CE repository
  get_url: >
    url='https://download.docker.com/linux/centos/docker-ce.repo'
    dest='/etc/yum.repos.d/docker-ce.repo'
    checksum='sha256:6650718e0fe5202ae7618521f695d43a8bc051c539d7570f0edbfa5b4916f218'

- name: Install docker-ce
  yum: name=docker-ce state=present

- name: Install pip
  yum: name=python-pip state=present enablerepo=epel

- name: Install docker-py
  pip: name=docker-py state=present

最後に

もちろん、include_tasks だけじゃなく include_vars 等にも使えます。
この書き方にしてから見通しがよくなって、運用しやすくなりました。