Ansibleで各サーバーごとに異なるサービスやパッケージを自動起動・インストールしたいとき、`host_vars` に配列変数を定義してタスクでループさせたいですよね。
でも、いざ試してみると変数がうまく展開されなかったり、`{{ item }}` を書くとエラーが出たりして詰まることがあります。
この記事では、`host_vars` に配列変数を定義して `loop`(旧 `with_items`)でループさせる方法を、具体的なYAMLコードと合わせて解説します。
目次
Ansibleのhost_varsとは
Ansibleにはホストごとに変数を管理する仕組みとして `host_vars` ディレクトリがあります。
inventory/
├── hosts # インベントリファイル
└── host_vars/
├── server1.yml # server1 専用の変数
└── server2.yml # server2 専用の変数
この `host_vars/<ホスト名>.yml` に変数を書いておくと、対象ホストにのみ変数が適用されます。サーバーごとに設定を出し分けたいときに非常に便利な仕組みです。
host_varsに配列変数を定義する
要件の整理
- server1 に自動起動させたいサービス:`httpd`、`postfix`
- server2 に自動起動させたいサービス:`httpd`、`postfix`、`mysql`
サーバーごとにリストが異なるため、`host_vars` にそれぞれ配列変数として定義します。
host_vars/server1.yml
service_on:
- httpd
- postfix
host_vars/server2.yml
service_on:
- httpd
- postfix
- mysql
loopでhost_vars変数をループさせる(Ansible 2.5以降推奨)
タスクファイルの書き方
`roles/service_on/tasks/main.yml` を以下のように記述します。
- name: 各サービスを自動起動に設定する
ansible.builtin.service:
name: "{{ item }}"
state: started
enabled: yes
loop: "{{ service_on }}"
become: yes
これで `service_on` に定義された配列が1要素ずつ `{{ item }}` に展開され、各サービスに対して `service` モジュールが実行されます。
with_itemsでの書き方(旧バージョン・後方互換)
Ansible 2.4以前のバージョン、もしくは既存PlaybookのメンテナンスのためにAnsible 2.5以降でも `with_items` を使い続けることはできます。
- name: 各サービスを自動起動に設定する
ansible.builtin.service:
name: "{{ item }}"
state: started
enabled: yes
with_items: "{{ service_on }}"
become: yes
| 比較 | `loop` | `with_items` |
|---|---|---|
| 対応バージョン | Ansible 2.5以降推奨 | 全バージョン(非推奨) |
| フラット化 | なし | リストを自動フラット化する |
| 公式推奨 | 推奨 | 非推奨(将来削除予定) |
よくあるエラーと対処法
エラー1: `name` フィールドのクォート忘れ
エラーになるコード(NG)
- name: 各サービスを起動する
ansible.builtin.service:
name: {{ item }} # ← クォートがない!
state: started
loop: "{{ service_on }}"
エラーメッセージ(例)
ERROR! We were unable to read either as JSON nor YAML, these are the errors we got from each:
修正後(OK)
- name: 各サービスを起動する
ansible.builtin.service:
name: "{{ item }}" # ← ダブルクォートで囲む
state: started
loop: "{{ service_on }}"
エラー2: loop変数が文字列として渡されている
`host_vars` で配列を定義しているつもりが、実際には文字列になっているケースです。
NG(文字列として定義されてしまう例)
# host_vars/server1.yml
service_on: "httpd postfix" # スペース区切りの文字列になっている
OK(正しいYAML配列)
# host_vars/server1.yml
service_on:
- httpd
- postfix
まとめ
Ansibleの `host_vars` に配列変数を定義して `loop` でループさせるポイントをまとめます。
- ✅ `host_vars/<ホスト名>.yml` にYAMLの配列形式(`– 要素名`)で変数を定義する
- ✅ タスクでは `loop: “{{ 変数名 }}”` と書く(Ansible 2.5以降推奨)
- ✅ `name: “{{ item }}”` などの変数展開は必ずダブルクォートで囲む
- ✅ `with_items` は非推奨なので、新規作成時は `loop` を使う
`host_vars` を活用してサーバーごとに変数を管理することで、Playbookをシンプルかつ可読性の高い状態に保てます。一度覚えると、Ansibleのベストプラクティスな構成がグッと使いやすくなります。ぜひ活用してみてください。
インフラの自動化・構成管理でお困りごとがあれば、お気軽にご相談ください。