Ansibleのrole引数設計|呼び出し側からroleへ変数を渡す経路と既定値の置き場所

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Ansible > Ansibleのrole引数設計|呼び出し側からroleへ変数を渡す経路と既定値の置き場所
「roleを再利用したいのに、呼び出すたびに本体のYAMLを書き換えている」
「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で確認する


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

なぜ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

この形式では、nginx_listen_portが8080に上書きされ、defaults/main.ymlの80番は使われません。指定しないnginx_access_logなどはdefaultsの値がそのまま使われます。

複数の環境(本番・ステージング)で同じ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 }}"

include_role と import_role の違いは評価タイミングにあります。
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

環境ごとのサーバーグループに対して変数をまとめて適用したい場合、インベントリ経由が適しています。ただし、group_varsはdefaults/main.ymlより優先度が高いため、roleのデフォルト値は必ず上書きされます。

インベントリ経由の変数設計は「どのホストに何の値を使わせるか」の管理が主眼になります。複数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" }

ステップ2: ansible-inventoryでホストの最終変数を確認する

$ 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" } } } }

このコマンドはインベントリから適用される変数(group_vars・host_vars)を確認できます。roles:のvarsは実行時に適用されるため、ここには現れません。「インベントリ側では正しい値になっているのにrole内で別の値になる」場合は、vars/main.ymlに同名の変数が定義されていないか確認してください。

よくある原因の一覧:
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内の先頭に仮置きして実行確認
defaults/main.ymlをroleの公開インターフェースとして設計し、呼び出し側はroles:のvarsかinclude_roleのvarsで必要な値だけを上書きする——この設計パターンを守ることで、roleの再利用性が実際に機能するようになります。

「roleのdefaultsに書いて、呼び出し側のvarsで上書きする」という流れを一度実機で体験すると、設計の意図がはっきりわかります。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の運用経験を持つ現役エンジニアが基礎から教えます。
Ansible実践ハンズオンの詳細を見る >>

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。