Ansibleで複数ホストを管理するとき、ホスト名でファイル名を変えたい、他のサーバーのIPをconfigに埋め込みたい、特定グループにだけ条件分岐したい。こうした要求に応えるのが Magic Variables(特殊変数)です。
この記事では、AnsibleのMagic Variablesの概念から、
hostvars・groups・inventory_hostname を使った実践的な設計パターンまで体系的に解説します。「なんとなく動いている」Playbookを「意図を持って設計した」Playbookに変えるための設計入門として読んでください。
この記事のポイント
・Magic VariablesはAnsibleが自動で設定する組み込み変数で上書き不可
・inventory_hostnameでホスト名を、hostvarsで他ホストの変数を参照できる
・groupsとgroup_namesでグループ条件分岐やクロスホスト設定が実現できる
・gather_facts完了後に利用できる変数と事前利用可能な変数を区別して設計する
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜMagic Variablesが必要なのか|静的なPlaybookの限界
Ansibleを使い始めると、まずシンプルなPlaybookを書きます。しかしホスト数が増え、環境が複雑になるにつれ、次のような壁にぶつかります。・ホストごとに異なるファイル名を生成したい
・WebサーバーのconfigにデータベースサーバーのIPを自動的に埋め込みたい
・「本番グループのホストだけ」にある処理を実行したい
こうした要求に答えるために
vars でいちいち変数を定義していると、「変数の定義がPlaybookとInventoryの両方に散らばる」「ホストを追加するたびに複数箇所を書き換える」という問題が起きます。Magic Variablesを使えば、Ansibleが実行時に自動で設定する情報をそのまま活用できます。ホスト名・グループ情報・他ホストの変数といった「Ansibleがすでに知っていること」を、Playbookの中で再利用する設計が可能になります。
Magic Variablesの全体マップ|種類と役割の整理
Magic Variablesは大きく3種類に分類できます。| 変数名 | 種別 | 内容 |
|---|---|---|
inventory_hostname |
ホスト識別 | Inventoryに記述したホスト名(FQDNまたは短縮名) |
inventory_hostname_short |
ホスト識別 | 最初のドットより前の短縮ホスト名 |
ansible_host |
ホスト識別 | 実際の接続先IP/ホスト名(ansible_host変数で指定した値) |
hostvars |
クロスホスト参照 | 全ホストの変数を辞書形式で参照できる |
groups |
グループ情報 | グループ名→ホスト名リストの辞書 |
group_names |
グループ情報 | 現在のホストが属するグループ名のリスト |
play_hosts |
実行状態 | 現在のPlayで対象となるホスト名のリスト |
ansible_version |
実行環境 | Ansibleのバージョン情報の辞書 |
playbook_dir |
パス | Playbookファイルが置かれているディレクトリの絶対パス |
inventory_dir |
パス | Inventoryファイルが置かれているディレクトリの絶対パス |
vars セクションやInventoryで同名の変数を定義すると予期しない動作の原因になるため、上書きは厳禁です。inventory_hostnameとansible_hostで自ホスト情報を扱う
Magic Variablesの中で最もよく使うのがinventory_hostname です。Inventoryに記述したホスト名がそのまま入っています。以下のInventoryがある場合を例に説明します。
# hosts.ini [webservers] web01.example.com web02.example.com [dbservers] db01.example.com ansible_host=192.168.1.101
web01.example.com で実行されるタスクでは、inventory_hostname は web01.example.com、inventory_hostname_short は web01 になります。1. ホスト名を使ったファイル生成パターン
ホストごとにユニークなファイル名を生成したい場合、inventory_hostname を直接使えます。- name: ホスト固有の設定ファイルを配置する template: src: nginx.conf.j2 dest: /etc/nginx/conf.d/{{ inventory_hostname_short }}.conf owner: root mode: '0644'
web01.conf / web02.conf のようなホスト固有ファイルが生成されます。vars に hostname: web01 と手書きする必要はありません。2. ansible_hostとinventory_hostnameの違い
混乱しやすいポイントです。inventory_hostname はInventoryの記述名、ansible_host は実際のSSH接続先です。たとえば
db01.example.com ansible_host=192.168.1.101 と定義されている場合:・
inventory_hostname → db01.example.com(Inventoryでの論理名)・
ansible_host → 192.168.1.101(SSHの実際の接続先)ログファイル名にはInventoryの論理名、実際の疎通確認にはansible_hostを使うというように、用途に合わせて使い分けます。
hostvarsで他ホストの変数を参照する設計パターン
hostvars は、Ansible実行中のすべてのホストの変数を辞書で持ちます。これを使うと、WebサーバーのPlaybookにDBサーバーのIPを自動埋め込みといったクロスホスト参照が実現できます。1. 他ホストのIPアドレスをconfigに埋め込む
Webサーバーのconfigにデータベースサーバーの接続先を設定する典型的なユースケースです。# templates/app.conf.j2 [database] host = {{ hostvars['db01.example.com']['ansible_host'] }} port = 3306
db01.example.com ansible_host=192.168.1.101 と定義されていれば、host = 192.168.1.101 が自動生成されます。DBサーバーを移設してInventoryを変えるだけで全Webサーバーの設定が更新されます。2. gather_factsとhostvarsの関係
重要な設計上の注意点があります。hostvars に他ホストのfacts(ansible_default_ipv4 等)を含めるには、そのホストでfactsが収集済みである必要があります。# Play 1: DBサーバーのfactsを先に収集する(tasks不要・gather_factsだけ実行) - hosts: dbservers gather_facts: yes tasks: [] # Play 2: WebサーバーでDBのfactsを参照する - hosts: webservers tasks: - name: DBサーバーのIPをconfigに埋め込む template: src: app.conf.j2 dest: /etc/app/app.conf vars: db_ip: "{{ hostvars[groups['dbservers'][0]]['ansible_default_ipv4']['address'] }}"
この設計パターンをAnsibleの実機環境で体験したい方は、>> Ansibleハンズオン講座の詳細を見る をご覧ください。
groupsとgroup_namesでグループ情報を動的に使う
groups と group_names を使うと、Inventoryのグループ構成に基づいた動的な条件分岐や繰り返し処理が可能になります。1. group_namesで「このホストはどのグループか」を判定する
group_names は、現在のホストが属するすべてのグループ名のリストです。when 条件でグループ判定ができます。- name: 本番グループのみfirewalldを有効化する service: name: firewalld state: started enabled: yes when: "'production' in group_names" - name: ステージングではデバッグパッケージを追加する dnf: name: gdb state: present when: "'staging' in group_names"
2. groupsでグループ内の全ホストを参照する
groups['グループ名'] はそのグループに属するホスト名のリストを返します。Jinja2テンプレート内でグループ全体をループする場合に使います。# templates/haproxy.cfg.j2 backend webservers {% for host in groups['webservers'] %} server {{ host }} {{ hostvars[host]['ansible_host'] }}:80 check {% endfor %}
groups['webservers'] を動的に参照するため、Inventoryに新しいWebサーバーを追加するだけでHAProxyの設定ファイルが自動更新されます。3. groups['all']で全ホストを確認する
Ansibleには事前定義のグループall(全ホスト)と ungrouped(グループ未所属のホスト)が常に存在します。# 全ホストのホスト名一覧を出力する(デバッグ用) - debug: msg: "管理対象の全ホスト: {{ groups['all'] }}"
Magic Variablesを使う際のトラブルシュート
【エラー1】「'hostvars' object has no attribute 'xxx'」
対象ホストがInventoryに定義されていないか、gather_factsが実行されていない場合に発生します。・Inventoryに該当ホストが存在するか確認する:
ansible-inventory --list・gather_facts: yes のPlayを先行して実行し、factsを収集済みにする
・デフォルト値を使う:
{{ hostvars[host]['ansible_host'] | default('未設定') }}【エラー2】inventory_hostnameの値がIPアドレスになっている
Inventoryにホスト名でなくIPアドレスで記載されていると、inventory_hostname もIPアドレスになります。論理名(db01等)でInventoryを定義し、実際の接続先は ansible_host= で指定する書き方を徹底しましょう。# NG: IPアドレスで直接記載(inventory_hostnameがIPになる) [webservers] 192.168.1.10 192.168.1.11 # OK: 論理名 + ansible_host で接続先を分離する [webservers] web01 ansible_host=192.168.1.10 web02 ansible_host=192.168.1.11
【エラー3】group_namesに期待するグループが入っていない
Inventoryのグループ定義が[children] 経由の場合、子グループ経由のホストにも親グループ名は group_names に含まれます。Inventoryの階層構造と group_names の実際の値を debug モジュールで確認しましょう。- debug: var: group_names
本記事のまとめ
AnsibleのMagic Variables(特殊変数)を使いこなすことで、Inventoryに追加したホストを自動認識し、ホスト固有の設定生成やクロスホスト参照が可能になります。| やりたいこと | 使うMagic Variable |
|---|---|
| Inventoryのホスト名をファイル名に使う | inventory_hostname / inventory_hostname_short |
| 他ホストのIPや変数をconfigに埋め込む | hostvars['ホスト名']['変数名'] |
| グループメンバーをループして設定を生成する | groups['グループ名'] |
| このホストが特定グループに属するか判定する | group_names(whenで条件分岐) |
| Playbookのディレクトリをパスで参照する | playbook_dir / inventory_dir |
Ansible実践ハンズオンの詳細を見る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:AnsibleをGitHub Actionsに組み込む設計入門|SSH SecretsとWorkflowでPush→自動デプロイを実現する方法
- この記事の属するカテゴリ:Ansibleへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます