Ansibleの変数優先順位と設定スコープを整理する|vars・defaults・group_vars・host_varsの使い分け

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Ansible > Ansibleの変数優先順位と設定スコープを整理する|vars・defaults・group_vars・host_varsの使い分け
「インベントリに変数を書いたのに、なぜかPlaybookの値で上書きされてしまう」
「roleを別プロジェクトに流用したら、意図しない値で動いてインフラを壊しかけた」

Ansibleの変数トラブルで時間を取られた経験はないでしょうか。こうした問題の多くは、Ansibleが持つ「22段階の変数優先順位」を把握していないことが原因です。変数をどこに書くかによって、どの値が最終的に使われるかが変わる——これがAnsible変数設計の核心です。

この記事では、Ansible変数の定義場所ごとの優先順位、group_vars・host_varsで環境差分を管理するパターン、roleのdefaults/varsの使い分けを実際のYAMLとコマンド出力を交えて解説します。
「変数をどこに書くべきか」の判断基準を身につければ、環境ごとの設定ミスや予期しない上書きを大幅に減らせます。

この記事のポイント

・Ansible変数は22段階の優先順位を持ち、extra_vars(-e)が最高優先度
・group_vars/host_varsでステージング・本番の環境差分を安全に管理できる
・roleのdefaults(上書き可)とvars(固定)を使い分けるのが設計の基本
・debugモジュールと-vオプションで変数の実値をその場で確認できる


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

なぜAnsibleは「変数を書く場所」を意識する必要があるのか

シェルスクリプトではスコープの概念は比較的シンプルですが、Ansibleには変数を定義できる場所が非常に多く存在します。インベントリファイル、group_vars、host_vars、Playbookのvars、roleのdefaults/vars、vars_files、set_fact、extra_vars(-eオプション)——これらすべてが同じ変数名で値を定義できます。

ここで重要なのは、「後から定義した方が勝つ」という単純なルールではなく、定義した場所によって優先順位が固定されているという点です。この優先順位を理解せずに変数を書くと、意図しない値が使われてデバッグに時間を費やすことになります。

私が現場のセミナーでよく見かけるのが、「Playbookのvarsセクションに本番のIPアドレスを書いたが、インベントリのgroup_varsにも同じ変数があって、なぜか本番に向かなかった」というケースです。これはPlebook varsがgroup_varsより優先度が高いため、インベントリ側の値が無視された結果です。

以降で優先順位の全体像を整理します。

22段階の変数優先順位——低い順から把握する

Ansibleの公式ドキュメントには22の変数定義場所が優先度順に列挙されています。すべてを覚える必要はありませんが、「どのグループに属するか」を理解しておくことが重要です。

1. 優先度が低いグループ(roleのdefaultsとinventory系)

最も優先度が低いのはroleのdefaults/main.ymlです。ここに書いた値はあらゆる場所から上書きできるため、「外部から変更させる想定のデフォルト値」を置く場所として機能します。

次にinventory系の変数が続きます(inventoryファイルのhost変数・group変数、group_vars/all、group_vars/[group]、host_vars/[host]の順)。

優先度の低い順(抜粋):
・1位: role defaults(role/defaults/main.yml)
・2~7位: inventory系変数(グループ変数 → ホスト変数の順で上がる)
・8~10位: facts(ansible_facts)・set_fact

実行環境確認: RHEL 9.4 / ansible-core 2.16.3 で動作確認済み

# 現在の変数値をdebugモジュールで確認する例 $ ansible web01.example.com -m debug -a "var=http_port" -i inventory/hosts ok: [web01.example.com] => { "http_port": "80" }

2. 優先度が中程度のグループ(playbook vars・include系)

PlaybookのVarsセクション(vars:ブロック)、vars_filesで読み込んだファイル、include_varsで動的に読み込んだ変数は、inventory系より優先度が高くなります。

このグループに属する優先度(抜粋):
・vars_prompt
・PlaybookのVarsセクション(playbook vars)
・include_varsタスクで読み込んだ変数
・set_factタスクで設定した変数(register経由も同等)
・roleのvars/main.yml(defaultsより上、playbook varsより下)

注意点として、role/vars/main.ymlはrole defaultsより優先度が高く、inventory系よりも高い位置にあります(実際には14番目前後)。そのため「roleのvarsに書いた値はインベントリから上書きできない」という設計上の特性を持ちます。

3. 最高優先度(extra_vars -e)

22段階の最上位に位置するのが-eオプションで渡すextra_varsです。コマンドラインから渡した値はあらゆる変数定義を上書きします。

・22位(最高): extra_vars(-e オプション)

# extra_varsで環境を指定する例 $ ansible-playbook site.yml -e "env=production" -e "app_version=2.5.1" # 変数ファイルごと渡す場合 $ ansible-playbook site.yml -e "@secrets/production.yml"

group_vars・host_varsで環境ごとの値を切り替える

実務でAnsibleを使う場面では、「開発環境と本番環境で異なるDBのホスト名や接続ポートを使いたい」というケースが必ず発生します。これを安全に実現するのがgroup_varsとhost_varsです。

1. group_vars・host_varsのディレクトリ構造

group_varsとhost_varsはインベントリファイルと同じディレクトリ、またはPlaybookルートに配置します。

# 推奨ディレクトリ構造 inventories/ ├── production/ │ ├── hosts # 本番ホスト定義 │ ├── group_vars/ │ │ ├── all.yml # 全グループ共通変数 │ │ └── webservers.yml # webserversグループ固有変数 │ └── host_vars/ │ └── web01.yml # web01固有の変数 └── staging/ ├── hosts # ステージングホスト定義 ├── group_vars/ │ ├── all.yml │ └── webservers.yml └── host_vars/

2. 本番とステージングで値を分ける実践例

# inventories/production/group_vars/webservers.yml http_port: 80 db_host: db.prod.example.com db_name: myapp_production max_connections: 200

# inventories/staging/group_vars/webservers.yml http_port: 8080 db_host: db.stg.example.com db_name: myapp_staging max_connections: 50

Playbookから参照する側は変数名をそのまま使えます:

# tasks/configure.yml(Playbook側は変数名のみ記述、環境を意識しない) - name: Apacheのポート設定 ansible.builtin.lineinfile: path: /etc/httpd/conf/httpd.conf regexp: '^Listen' line: "Listen {{ http_port }}" notify: Restart Apache

実行時にインベントリを切り替えるだけで自動的に環境固有の値が使われます:

# ステージング環境へのデプロイ $ ansible-playbook site.yml -i inventories/staging/ # 本番環境へのデプロイ $ ansible-playbook site.yml -i inventories/production/

3. host_varsで特定のホストだけ上書きする

「webserversグループ全体はポート80を使うが、web03だけポート8443を使う」という場合、host_varsで上書きします。グループ変数よりホスト変数の方が優先度が高いため、確実に上書きされます。

# inventories/production/host_vars/web03.yml http_port: 8443 ssl_enabled: true

# 実行結果確認:web03だけ8443になっていることを確認 $ ansible all -m debug -a "var=http_port" -i inventories/production/ ok: [web01.example.com] => { "http_port": "80" } ok: [web02.example.com] => { "http_port": "80" } ok: [web03.example.com] => { "http_port": "8443" }

Ansibleの変数設計の基本を体系的に学びたい方は、以下もご参照ください。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の運用経験を持つ現役エンジニアが基礎から教えます。
Ansible実践ハンズオンの詳細を見る >>

roleのdefaultsとvarsの使い分け

roleを設計する際に悩みやすいのが、defaults/main.ymlvars/main.ymlのどちらに変数を書くかです。判断基準は「外から上書きさせるかどうか」です。

1. defaults/main.yml——外から上書き可能なデフォルト値

優先順位が最も低いdefaultsには「使う人が自由に変更できる設定値」を置きます。roleを共有する際に、利用側が独自の値でカスタマイズできる設計です。

# roles/nginx/defaults/main.yml nginx_port: 80 nginx_worker_processes: 1 nginx_keepalive_timeout: 65 nginx_log_dir: /var/log/nginx

利用側はgroup_varsやPlaybookのVarsで上書きするだけです:

# inventories/production/group_vars/webservers.yml # defaultsの値を本番用に上書き nginx_port: 443 nginx_worker_processes: auto

2. vars/main.yml——roleの内部で固定する値

vars/main.ymlはdefaultsより優先度が高く、inventory系よりも高い位置にあります。「roleが正しく動くために変えてはいけない値」を置く場所として使います。

# roles/nginx/vars/main.yml # 外から変更されては困る内部固有値(OS依存パス等) nginx_pid_file: /run/nginx.pid nginx_conf_dir: /etc/nginx nginx_service_name: nginx

vars/main.ymlに書いた値はインベントリのgroup_varsやhost_varsから上書きできません(extra_vars -eは例外)。roleの動作に必須なパスやサービス名はvarsに固定しておくのが設計の鉄則です。

Ansible GalaxyでRoleを管理する方法についてはこちらも参照してください:Ansible GalaxyでRoleを管理する方法|requirements.ymlと自社role設計の実践

vars_filesとinclude_varsで変数ファイルを外部化する

Playbookが長くなってきたら、変数定義を別ファイルに切り出すと管理しやすくなります。

1. vars_filesで機密情報をPlaybookから分離する

DBパスワードやAPIキーをPlaybookのVarsセクションに直書きするのは危険です。vars_filesで別ファイルに外出しし、Ansible Vaultで暗号化するパターンが現場の標準です。

# site.yml - hosts: webservers vars_files: - vars/common.yml - vars/{{ env }}_secrets.yml # 環境ごとの機密ファイル(Vault暗号化推奨) roles: - nginx - app

# vars/production_secrets.yml(Ansible Vaultで暗号化) db_password: "!vault |" ";1.1;AES256" "6236...(暗号化済み文字列)" api_key: "!vault |" ";1.1;AES256" "3831...(暗号化済み文字列)"

Ansible Vaultを使った機密情報の暗号化についてはAnsible Vaultでシークレットを安全に管理する方法も参照してください。

2. include_varsで動的にファイルを読み込む

実行時の条件によって読み込むファイルを切り替えたい場合はinclude_varsを使います。

# tasks/main.yml - name: OSごとの変数ファイルを読み込む ansible.builtin.include_vars: file: "{{ ansible_os_family }}.yml" # RHEL系なら RedHat.yml、Debian系なら Debian.yml を読み込む

# vars/RedHat.yml package_name: httpd service_name: httpd conf_path: /etc/httpd/conf/httpd.conf

# vars/Debian.yml package_name: apache2 service_name: apache2 conf_path: /etc/apache2/apache2.conf

これによりOS依存の差異をPlaybook本体から隠蔽できます。ansible_os_familyはAnsibleが自動収集するfactで、RHEL系は"RedHat"、Debian/Ubuntu系は"Debian"が入ります。

extra_vars(-e)は最高優先度——本番環境切替の実践パターン

extra_varsを使う最も実用的なシーンは、「通常は環境変数でインベントリを切り替えるが、緊急時に特定の値だけ上書きしたい」ときです。

例えばアプリケーションのバージョンをCI/CDパイプラインから注入するケースでは、extra_varsが最適です:

# CI/CDパイプライン(GitHub Actions等)からの呼び出し例 $ ansible-playbook deploy.yml -i inventories/production/ -e "app_version=" -e "deploy_timestamp=20260710110559" --vault-password-file ~/.vault_pass

extra_varsの注意点:最高優先度であるが故に、意図せず他の変数を上書きするリスクもあります。チームで運用する場合はextra_varsで渡せる変数名を規約で定義しておくと安全です。

また、デバッグ目的で特定の変数だけ上書きしてテストする用途にも便利です:

# 本番インベントリを使いながら、ポートだけ変えて動作確認 $ ansible-playbook site.yml -i inventories/production/ -e "http_port=8080" --check # 実際には変更しないドライランモード

トラブルシュート:変数が意図通りに動かない時

「変数を設定したはずなのに反映されない」というトラブルは、どのレイヤーの定義が最終的に使われているかを確認することで解決します。

1. debugモジュールで変数の実値をその場で確認する

実行前に変数の実値を確認するにはdebugモジュールが最も手軽です:

# Playbook内にデバッグタスクを追加 - name: 変数の実値を確認する ansible.builtin.debug: msg: "http_port={{ http_port }}, db_host={{ db_host }}" # 出力例 TASK [変数の実値を確認する] ***************** ok: [web01.example.com] => { "msg": "http_port=80, db_host=db.prod.example.com" }

コマンドラインから1タスクだけ実行したい場合はad-hocコマンドを使います:

# インベントリ内の全変数を一覧表示(hostvars経由) $ ansible web01.example.com -m debug -a "var=hostvars[inventory_hostname]" -i inventories/production/ # 特定変数だけ確認 $ ansible web01.example.com -m debug -a "var=http_port" -i inventories/production/

2. -vオプションと--list-hostsで変数の解決過程を追う

どのファイルから変数が読み込まれているか追いたい場合は、verboseオプション(-v~-vvvv)を使います:

# -vvv でデータソースを含む詳細ログを出力 $ ansible-playbook site.yml -i inventories/production/ -vvv 2>&1 | grep -A2 "http_port" # 出力例(変数の定義元が確認できる) "http_port": "80", # group_vars/webservers.yml から読み込まれた値

また、ansible-inventoryコマンドを使うとインベントリから解決された変数の最終値を一覧できます:

# ホストごとの変数最終値をJSON形式で表示 $ ansible-inventory -i inventories/production/ --host web01.example.com { "ansible_host": "192.0.2.10", "db_host": "db.prod.example.com", "http_port": "80", "max_connections": "200" }

AnsibleのJinja2テンプレートで変数を使う際のテンプレート構文については、AnsibleのJinja2テンプレートとhandler設計も参照してください。

本記事のまとめ

Ansible変数の優先順位と定義場所のルールを整理しました。

変数の定義場所 優先度 適した用途
role/defaults/main.yml 最低(1位) 外から上書きさせるデフォルト値
group_vars/[group].yml 低(5~6位) グループ単位の環境差分
host_vars/[host].yml 低(7位) ホスト固有の上書き
role/vars/main.yml 中(14位) roleの内部固定値(上書きさせない)
Playbookのvarsセクション 中(16位) Playbook単位の設定値
set_factタスク 高(18位) 実行時に動的に生成する値
extra_vars(-e) 最高(22位) CI/CDからの動的注入・緊急上書き
変数設計の基本方針は「defaultsで柔軟に、varsで確実に、group_varsで環境を分離する」です。変数が意図通りに動かない場合はdebugモジュールansible-inventory --hostで実値を確認し、優先順位のどのレイヤーで上書きされているかを特定します。

次のステップとして、Ansibleの冪等性設計も合わせて読むと、「何度実行しても安全なPlaybook」の設計が体系的に理解できます。 Ansibleの変数設計を含む構成管理の考え方を実機で体系的に習得したい方は、ぜひ詳細をご覧ください。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の運用経験を持つ現役エンジニアが基礎から教えます。
Ansible実践ハンズオンの詳細を見る >>

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

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

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

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

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

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

登録10秒/合わなければ解除3秒 / 詳細はこちら

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

この記事を書いた人

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

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

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