Ansible — Inventory Management
Chapter 2 — Inventory Management
1. Theory
Inventory is Ansible's source of truth for "what hosts exist and how are they grouped." It can be static (INI or YAML file) or dynamic (a script/plugin querying a live source like AWS or a CMDB). Hosts can belong to multiple groups, and groups can nest (groups of groups), with variables resolved via a defined precedence order.
2. Internal Working
At startup, Ansible builds an in-memory graph: hosts → groups → group variables, plus a
special all group containing everything. Variable precedence (lowest to highest, among
inventory sources) is roughly: group_vars/all → group_vars/<group> →
host_vars/<host> → inventory file [group:vars] entries closer to the host. Command-line
-e extra vars always win over all of these.
3. Diagram
all
/ \
web db
/ \ \
web1 web2 db1
(host_vars/web1.yml overrides group_vars/web.yml overrides group_vars/all.yml)
4. Commands
ansible-inventory -i inventory.ini --list # dump resolved inventory as JSON
ansible-inventory -i inventory.ini --graph # visualize group nesting
ansible web1 -i inventory.ini -m debug -a "var=hostvars[inventory_hostname]"
ansible-playbook site.yml --limit web1 # restrict run to one host
5. Code Examples
# inventory.ini — nested groups
[web]
web1 ansible_host=10.0.0.11
web2 ansible_host=10.0.0.12
[db]
db1 ansible_host=10.0.0.21
[production:children]
web
db
[production:vars]
env=prod
# group_vars/web.yml
http_port: 8080
# host_vars/web1.yml
http_port: 9090 # overrides group_vars/web.yml for this one host
6. Real-world Example
A company has staging and production environments with identical roles (web, db, cache)
but different scale. They use two inventory files (inventory/staging.ini,
inventory/production.ini) with the same group structure, so the exact same playbooks run
unmodified against either — only the inventory changes.
7. Production Example
At scale, static INI files become unmanageable (hundreds of hosts churn constantly in
cloud environments) — production setups almost always move to dynamic inventory
plugins (e.g. amazon.aws.aws_ec2) that query live infrastructure by tag, combined with
group_vars still stored in version control for anything static (credentials excluded,
those go in Vault — Chapter 8).
8. Common Mistakes
- Defining the same variable in both
group_varsand directly in the inventory file and being surprised which one "wins" — precedence rules are easy to get backwards. - Forgetting
[group:children]syntax requires the child group to already be defined elsewhere in the file. - Using
--limitwith a pattern that matches zero hosts and not noticing the playbook "succeeded" trivially with nothing to do.
9. Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
| Variable has unexpected value | Precedence conflict across group_vars/host_vars | Run ansible-inventory --list to see resolved values per host |
[group:children] group not recognized |
Child group name typo or defined after use | Verify exact group names with --graph |
--limit matches nothing, playbook "succeeds" |
Pattern typo or host not in inventory | Confirm with ansible-inventory --list first |
10. Security Notes
- Never store plaintext secrets in
group_vars/host_varscommitted to version control — use Ansible Vault (Chapter 8) for anything sensitive. - Dynamic inventory credentials (cloud API keys) should themselves come from environment variables or a secrets manager, not hardcoded in the inventory plugin config.
11. Interview Questions
- Static vs dynamic inventory — when would you use each? Static for small/stable fleets; dynamic for cloud environments where hosts change frequently.
- What does
[production:children]mean? Definesproductionas a group containing the members of the listed child groups (web,db), not literal child group syntax for hosts directly. - What's the variable precedence between group_vars and host_vars?
host_vars(more specific) overridesgroup_vars(less specific). - How do you preview resolved inventory without running a playbook?
ansible-inventory --listor--graph. - What does
--limitdo? Restricts a playbook run to a subset of the inventory matching a host/group pattern.
12. Hands-on Lab
- Build the nested inventory above with
web,db, andproductiongroups. - Set
http_port: 8080ingroup_vars/web.ymland override it to9090inhost_vars/web1.yml. - Run
ansible-inventory --listand confirmweb1shows9090whileweb2shows8080. - Run a playbook with
--limit web1and confirm only that host is targeted.
13. Hacks
ansible-inventory --graph --varsshows both the group tree and every variable in one view — faster than cross-referencing multiple files by hand.- Host patterns support boolean logic:
ansible-playbook site.yml --limit 'web:!web2'targets all ofwebexceptweb2.
14. Workarounds
- If you need per-environment variable overrides without duplicating entire inventory
files, use one inventory with an
envgroup variable and conditionals in playbooks rather than maintaining parallel file trees.
15. Exercises
- Add a
cachegroup and make it a child ofproductionalongsidewebanddb. - Deliberately create a precedence conflict (same var in
group_vars/allandhost_vars/<host>) and predict the resolved value before checking withansible-inventory.
16. Quiz
- What command shows the fully resolved inventory as JSON?
- Which wins: a variable set in
group_vars/web.ymlorhost_vars/web1.yml? - What syntax nests one group inside another?
- What flag restricts a playbook run to specific hosts?
- Where should cloud API credentials for dynamic inventory NOT be stored?
Answer Key
ansible-inventory --listhost_vars/web1.yml[groupname:children]--limit- Hardcoded directly in the dynamic inventory plugin config file (in version control)