unit 3 · Inventory
Patterns, --limit & per-env inventories
Deciding exactly which hosts a run touches
you may want to read 8 · Inventory: INI and YAML first — but nothing is locked
tl;dr
- Patterns pick hosts at run time: all, web*, web:&staging (in both), web:!db (web minus db).
- --limit narrows any run to the hosts you name — the re-run and debugging flag.
- One inventory directory per environment is the guardrail that stops a staging run touching prod.
why it matters Target the wrong hosts and Ansible cheerfully configures the wrong hosts — patterns, --limit and per-environment inventories are the three controls that decide where a run lands, prod included.
Lesson 8 gave you an inventory full of groups. Every command since has
opened with a target — web, all. Those are the simplest cases of
a pattern , the expression deciding which inventory
hosts a run touches. Nothing executes until a pattern says where.
Four forms cover most cases:
ansible all -m ansible.builtin.ping # every host in the inventory
ansible 'web*' -m ansible.builtin.ping # wildcard: web01, web02, webcache...
ansible 'web:&staging' -m ansible.builtin.ping # in web AND in staging
ansible 'web:!db' -m ansible.builtin.ping # in web but NOT in dbRead the last two as set operations on groups. web:&staging is an
intersection — hosts in both groups. web:!db is an exclusion —
web minus the db members. The quotes are for your shell, not Ansible: !
and & mean things to bash. And a bare : between two group names is
a union — web:db is everything in either group.
--limit: narrow the run you already wrote
--limit is a run-control flag: it narrows any run to the hosts you
name, without editing a thing.
When you reach playbooks in unit 4, each play declares its own targets —
--limit cuts below that declaration.
# the full run, as the play targets it
ansible-playbook site.yml -i inventories/staging/
# identical run, narrowed to the one host that failed
ansible-playbook site.yml -i inventories/staging/ --limit web01That second line is why --limit sits in the debugging toolkit next to
-vvv and --check. One host broke mid-run? Fix the cause, re-run
against just that host — not the whole fleet.
One inventory directory per environment
This habit matters more than any pattern syntax: a separate inventory directory per environment, each with its own group_vars and host_vars :
inventories/
production/
hosts.yml # prod hosts and groups
group_vars/ # prod values live with prod
host_vars/
staging/
hosts.yml # same group names, different machines
group_vars/
host_vars/You choose the environment when you type -i inventories/production/.
That’s the mechanism behind the standup phrase “run the playbook
against prod” — same playbook, prod inventory. Keep group_vars/all.yml
minimal. Anything environment-specific belongs in that environment’s
directory, not in a shared file both environments read.
Before trusting any inventory, look at what it contains:
ansible-inventory --graph -i inventories/staging/ prints the group tree
Ansible resolved. Make that your reflex before the first run against any
inventory you didn’t write. Same cheapest-fact-first instinct as the ping
in lesson 7, one level up.
practice — aim a pattern at this inventory
→ web01
covers this lesson’s forms: names, *, : union, :& intersection, :! exclusion
at work, this sounds like
- “Run the playbook against prod.”
- Execute it with the production inventory — ansible-playbook site.yml -i inventories/prod/.
self-check — recall, not a test
1 What do web:&staging and web:!db each match?
2 A playbook run failed on one host. How do you re-run it against just that host without editing anything?
3 Why one inventory directory per environment instead of one big inventory holding prod and staging groups?
lab (optional — never required)
Build inventories/staging/ and inventories/production/ with one host each, inspect both with ansible-inventory --graph -i <dir>, then ping with a pattern and again with --limit.
needs: The control node from lesson 5.