「defaults/main.ymlに書いた値が呼び出し側で上書きされているのかどうか確認する方法がわからない」
Ansibleのroleを使い始めた現場でよく聞かれる問いです。roleは「再利用可能なPlaybookの部品」として設計されていますが、変数の渡し方を誤ると呼び出しのたびに本体を書き換えることになり、再利用の恩恵が消えます。
この記事では、roleへ変数を渡す3つの経路(roles:ブロックのvars・include_roleのvars・インベントリ経由)を比較し、defaults/main.ymlを「roleの公開インターフェース」として設計する考え方を実例で解説します。変数優先順位の全体マップ(22段階)はすでに別記事で扱ったため、本記事はrole呼び出し時の引数受け渡しに絞って掘り下げます。
実行環境: RHEL 9.4 / ansible-core 2.16.3 で動作確認済み
この記事のポイント
・defaults/main.ymlがroleの「公開インターフェース」になる
・roles:配下のvarsで呼び出し側から値をインライン渡しできる
・include_roleのvars:はタスクレベルで動的に渡す経路として使う
・変数が効いていない時はdebugモジュールとansible-inventoryで確認する
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜroleへの変数の渡し方が設計の要(かなめ)になるのか
roleとは、tasks・handlers・templates・defaultsといったファイル群をディレクトリ構造に沿ってまとめたPlaybookの「部品」です。nginxをセットアップするrole、Apacheを構成するroleのように、一度作れば複数のPlaybookから呼び出して使えます。ただし、この再利用性が成立するには「呼び出し側がroleに値を渡せる設計」になっていることが前提です。たとえば、nginx roleのListen Portを80番に固定してroleの中身に書いてしまうと、443番で使いたいPlaybookが出てきたとき、roleのtasks/main.ymlを書き換えるしかありません。
正しい設計は、Listen Portのような「呼び出しごとに変わりうる値」をdefaults/main.ymlに変数として置き、呼び出し側のPlaybookから値を渡す形にすることです。こうすることで、roleの本体(tasks/main.yml)は一切変更せずに、ポート番号だけを呼び出し側でコントロールできます。
「roleへの変数の渡し方」は、roleを部品として成立させるための設計上の境界線です。
defaults/main.yml──roleの公開インターフェースとして設計する
1. defaultsに書くべき値の基準
defaults/main.yml はAnsibleの変数優先順位の中で最も低い位置にあります。これは欠点ではなく「設計上の意図」です。優先度が低いということは、外のあらゆる場所(roles:のvars・group_vars・extra_vars)から上書きできるということを意味します。このため、defaults/main.ymlは「roleの動作に必要な変数と、呼び出し側が変えてよいデフォルト値の一覧」を置く場所として使います。
・defaults向き:Listenポート番号、最大接続数、パッケージバージョン、ログレベル
・defaults不向き:パスワードや秘密情報、role内の処理ロジックを壊す固定パラメーター
roleを使う側のエンジニアは、defaults/main.ymlを見ることで「このroleが受け付ける変数の一覧」を把握できます。APIでいえば「公開シグネチャ」にあたります。
# roles/nginx/defaults/main.yml --- nginx_listen_port: 80 nginx_worker_processes: auto nginx_access_log: /var/log/nginx/access.log nginx_error_log: /var/log/nginx/error.log nginx_document_root: /usr/share/nginx/html
2. role/vars/main.ymlとの使い分け
defaultsと混同されやすいのが、同じrole内にある vars/main.yml です。この2つの違いは一言でいえば「上書きを許可するかどうか」です。・defaults/main.yml:上書き可。呼び出し側が自由に変えてよい公開変数
・vars/main.yml:上書き不可に近い。role内部の固定値で、呼び出し側に変えさせたくない値
vars/main.yml はPlaybook varsより優先度が高い(変数優先順位の14位相当)ため、呼び出し側のvarsブロックで上書きしようとしても効きません。role内部の処理に使うパス文字列やファイル名の定数など、「外から触られると壊れる値」をvarsに置くのが正しい使い方です。
設計の判断基準:「この変数を呼び出し側に変えさせたいか?」→ YES → defaults、NO → vars。
呼び出し側からroleへ変数を渡す3つの経路
1. roles:ブロックのvarsでインラインに渡す
最もシンプルで可読性の高い方法です。Playbookのroles:セクションでrole名と一緒にvarsブロックを並べます。# site.yml(呼び出し側Playbook) --- - name: Webサーバーをセットアップする hosts: web_servers roles: - role: nginx vars: nginx_listen_port: 8080 nginx_worker_processes: 4 nginx_document_root: /var/www/myapp
複数の環境(本番・ステージング)で同じroleを異なる設定で呼ぶ時は、Playbookを環境別に分けて、この vars: ブロックの値を環境ごとに変えるパターンが読みやすく管理しやすいです。
2. include_role・import_roleのvarsでタスクレベルに渡す
tasks/main.yml内で別のroleを呼び出すときはinclude_roleまたはimport_roleを使います。この場合もvarsブロックで変数を渡せます。# tasks/main.yml(呼び出し元taskファイル) --- - name: nginxをセットアップする ansible.builtin.include_role: name: nginx vars: nginx_listen_port: "{{ app_port }}" nginx_worker_processes: "{{ ansible_processor_vcpus }}"
・import_role:Playbookのパース時(静的)に展開される。変数は固定値で渡す場合に向く
・include_role:実行時(動的)に展開される。{{ ansible_processor_vcpus }} のような実行時に確定する変数を渡す場合に必要
上記の例のようにfacts変数(ansible_processor_vcpus)を渡す場合は、include_roleを使う必要があります。import_roleでfacts変数を参照すると「undefined variable」エラーになることがあります。
3. インベントリ経由(group_vars・host_vars)からの経路
roles:のvarsやinclude_roleのvarsを使わず、インベントリのgroup_varsやhost_varsから変数を渡す方法もあります。# group_vars/web_servers.yml --- nginx_listen_port: 80 nginx_worker_processes: 2 # group_vars/staging.yml --- nginx_listen_port: 8080 nginx_worker_processes: 1
インベントリ経由の変数設計は「どのホストに何の値を使わせるか」の管理が主眼になります。複数roleにまたがって共通する変数(nginxとapacheの両方で参照するapp_portなど)はインベントリ側に置くのが向いています。
変数が効かない時のデバッグ手順
「varsに書いたのにrole内で期待する値にならない」というトラブルが起きた場合の確認手順です。ステップ1: debugモジュールで実際に適用された値を確認する
# roles/nginx/tasks/main.yml の先頭にdebugを追加 --- - name: 変数の最終値を確認する ansible.builtin.debug: msg: "nginx_listen_port={{ nginx_listen_port }}, worker={{ nginx_worker_processes }}" - name: nginx をインストールする ansible.builtin.dnf: name: nginx state: present
TASK [nginx : 変数の最終値を確認する] *** ok: [web01.example.com] => { "msg": "nginx_listen_port=8080, worker=4" }
$ ansible-inventory -i inventory/hosts --host web01.example.com { "_meta": { "hostvars": { "web01.example.com": { "nginx_listen_port": 8080, "nginx_worker_processes": 4, "ansible_host": "192.0.2.10" } } } }
よくある原因の一覧:
・vars/main.ymlに同名変数がある:vars/main.ymlはroles:のvarsより優先度が高い場合がある。defaults/main.ymlに移動する
・extra_vars(-e)で上書きされている:-eオプションは最高優先度。CI/CDのansible-playbook実行コマンドを確認する
・include_roleでimport_roleを使った:静的インポートではfacts変数が未解決のまま渡るケースがある。include_roleに変更する
・変数名のタイポ:AnsibleはYAMLの変数名の誤りをエラーにせず、defaultsの値を使って動く。debugで確認する
本記事のまとめ
| やりたいこと | 経路・方法 | 特徴 |
|---|---|---|
| roleのデフォルト値を定義する | defaults/main.yml |
最低優先度。外から自由に上書き可能 |
| role内の固定値を守る | vars/main.yml |
高優先度。呼び出し側から上書き困難 |
| Playbookからroleへ値をインラインで渡す | roles: - role: name / vars: |
最もシンプル。1ファイルで完結 |
| タスクレベルでroleへ値を渡す | include_role / import_role の vars: |
動的変数(facts)を渡すならinclude_role |
| 複数roleに共通する環境差分を管理する | group_vars / host_vars |
インベントリ側で一元管理。defaultsを上書き |
| 実際に適用された変数値を確認する | ansible.builtin.debug で msg: 出力 |
role内の先頭に仮置きして実行確認 |
「roleのdefaultsに書いて、呼び出し側のvarsで上書きする」という流れを一度実機で体験すると、設計の意図がはっきりわかります。
Ansible実践ハンズオンの詳細を見る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:AnsibleでVPCから作るAWS環境の自動化|ネットワークを先に用意してからEC2を並べる順序設計
- この記事の属するカテゴリ:Ansibleへ戻る

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