こんにちは、 @dz_ こと大平かづみです。
Prologue - はじめに
マシン間で ssh 通信するとき、/etc/hosts
を用意すると、IPアドレスを調べる手間が省けたり、shell でタブ補完ができたりなど何かと便利ですよね。
Ansible でちょちょいと作れるようになったので、共有します!╭( ・ㅂ・)و̑ グッ
検証環境の準備
検証用マシンは、 Azure 上につくりました。つかった ARM テンプレートをこちらに用意しましたので、ご興味あればご自身のアカウントでもお試しいただけます。
また、Ansible 実行環境については別途作りましたが、お手軽に使いたい場合は Azure Cloud Shell でも Ansible を利用できます。ぜひお試しください♪
ポイント
さて、先にいくつかポイントをご紹介します。
run_once
で1回だけ処理する
複数対象があっても、1回だけ処理したい場合に使います。 delegate_to
と組み合わせて、特定のホストだけで処理したい場合にも利用できます。
ansible_play_hosts
でホスト一覧を取得する
ansible_play_hosts
を利用すると、そのとき実行中のホスト一覧を取得できます。
groups.all
でも全ホストを取得できますが、グループ分けしてる場合は不都合があるので、 ansible_play_hosts
が便利と思います。
また、 batch
ごとの対象一覧を取得したい場合は、
ansible_play_batch
を使えるそうです。詳しくは下記ドキュメントをご参照ください。
- Magic Variables, and How To Access Information About Other Hosts - Variables — Ansible Documentation
jinja2 フィルタ関連
default()
フィルタ
default()
フィルタは、対象の変数が定義されtない場合に初期値を設定してくれます。
今回は、 _nodes | default([])
とすることで、ループの最初で _nodes
が定義されていなくても空のリストが設定されるようにしました。
リストの結合は +
ついフィルタを探しがちですが、リストは +
で結合します。
なお、 dict
を結合する場合は combine()
を利用できます。
検証
これらのポイントをもとに、下記のサンプルで検証しました。短いコードで、さっくり作れます。
サンプル
hosts
ロール
---
- name: Set node information
set_fact:
_nodes: "{{ _nodes | default([]) + [{'hostname': hostvars[item].ansible_hostname, 'address': hostvars[item].ansible_eth0.ipv4.address}] }}"
run_once: yes
with_items: "{{ ansible_play_hosts }}"
when:
- hostvars[item].ansible_eth0 is defined
- name: Distribute hosts file
become: yes
template:
src: hosts.j2
dest: /etc/hosts
owner: root
group: root
mode: 0644
backup: yes
{% for node in _nodes %}
{{ node.hostname }} {{ node.address }}
{% endfor %}
インベントリと playbook
vm-ubuntu
vm-centos
---
- name: All
hosts: all
roles:
- hosts
実行結果
ansible-playbook -i inventory/all create_hosts.yml
PLAY [All] **************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************
ok: [vm-ubuntu]
ok: [vm-centos]
TASK [hosts : Set node information] *************************************************************************************
ok: [vm-ubuntu] => (item=vm-ubuntu)
ok: [vm-ubuntu] => (item=vm-centos)
TASK [hosts : Distribute hosts file] **************************************************************************************
changed: [vm-ubuntu]
changed: [vm-centos]
PLAY RECAP **************************************************************************************************************
vm-centos : ok=2 changed=1 unreachable=0 failed=0
vm-ubuntu : ok=3 changed=1 unreachable=0 failed=0
それぞれ、ちゃんと /etc/hosts
ができました!
[user@vm-centos ~]$ cat /etc/hosts
vm-ubuntu 10.0.0.4
vm-centos 10.0.0.5
[user@vm-ubuntu ~]$ cat /etc/hosts
vm-ubuntu 10.0.0.4
vm-centos 10.0.0.5
Epilogue - おわりに
この方法を編み出す前は、結構ダサい作り方をしていてもどかしかったのですが、リストの結合など jinja2 のフィルタに慣れてきたおかげで改善することができました!