Inventory: Static, Dynamic, Groups and Variables
The inventory is the list of hosts Ansible manages and how they're organized. Every playbook applies to a set of hosts in the inventory, so understanding the inventory is foundational. This article goes from a simple static inventory to a dynamic one for the cloud.
Static inventory: INI and YAML
Article 2 already used a minimal INI inventory. Inventory supports two formats — INI (compact) and YAML (clearer structure when things get complex).
INI:
[web]
web1 ansible_host=10.0.0.11
web2 ansible_host=10.0.0.12
[db]
db1 ansible_host=10.0.0.21
The equivalent YAML:
all:
children:
web:
hosts:
web1:
ansible_host: 10.0.0.11
web2:
ansible_host: 10.0.0.12
db:
hosts:
db1:
ansible_host: 10.0.0.21
web1 is the host's friendly name (alias); ansible_host is its real address. Separating these two lets you give easy-to-remember names and change the IP without changing the playbook.
Groups: organizing hosts
Hosts are gathered into groups (web, db...). One host can belong to multiple groups, and groups can be nested (children). View the structure with ansible-inventory:
ansible-inventory --graph
@all:
|--@ungrouped:
|--@web:
| |--lab
|--@db:
| |--lab
Here the host lab belongs to both web and db. Two special groups always exist: all (every host) and ungrouped (hosts in no group). Groups let you apply a playbook to the right kind of machine: "install nginx on the web group", "configure postgres on the db group".
Variables: assigned per host and per group
You assign variables to hosts/groups for the playbook to use (Article 6 digs into variables). The cleanest way is the two special directories next to the inventory:
group_vars/<group_name>.yml— variables for an entire group.host_vars/<host_name>.yml— variables for a single host.
Example group_vars/web.yml:
http_port: 8080
app_env: production
Every host in the web group automatically receives http_port and app_env. Check that the variables merged into the host:
ansible-inventory --host lab
{
"ansible_host": "203.0.113.10",
"app_env": "production",
"http_port": 8080
}
The host lab (in web) receives all the variables from group_vars. When a host belongs to multiple groups with same-named variables, a precedence order decides which value wins — the topic of Article 6. Put shared variables in group_vars/all.yml, and specific ones in particular groups/hosts.
Patterns: targeting the right hosts
When you run a playbook/ad-hoc command, you specify a pattern — which hosts/groups to apply to:
ansible web --list-hosts # every host in the web group
ansible all --list-hosts # all
ansible 'web:db' --list-hosts # web OR db (union)
ansible 'web:&db' --list-hosts # both web AND db (intersection)
ansible 'web:!db' --list-hosts # web BUT NOT db (difference)
ansible 'web*' --list-hosts # match names by wildcard
The operators : (or), :& (and), :! (exclude) let you target precisely — e.g. "every web host except the one under maintenance". --list-hosts previews which hosts a pattern matches before you run for real.
Dynamic inventory: auto-discover hosts on the cloud
A static inventory is fine when hosts are fixed. But on the cloud, machines are created/destroyed constantly — keeping a list of IPs up to date by hand is impossible. Dynamic inventory solves this: a plugin automatically queries a source (AWS, GCP, Kubernetes...) to get the hosts in real time.
For AWS, the amazon.aws.aws_ec2 plugin fetches running EC2 instances. The inventory_aws.yml file:
plugin: amazon.aws.aws_ec2
regions:
- ap-southeast-1
keyed_groups:
- key: tags.Role # auto-create groups from the instance's "Role" tag
prefix: role
filters:
instance-state-name: running
Running ansible-inventory -i inventory_aws.yml --graph lists the running EC2 instances, auto-grouped by tag. The big advantage: you tag an instance Role=web on AWS, and Ansible automatically puts it in the role_web group — no need to edit the inventory file when you scale. (Requires the amazon.aws collection installed and AWS credentials configured — Article 9 covers collections.)
When to use which: static for small/fixed environments (a lab, a few servers); dynamic for cloud/auto-scaling where hosts change constantly. Many projects use both.
🧹 Cleanup
Inventory is just text files — it creates no resources. The sample code (INI/YAML inventory, group_vars) is in the nghiadaulau/ansible-series repo, directory 03-inventory.
Wrap-up
Inventory lists the hosts Ansible manages. Write it static (INI or YAML), gather hosts into groups (nestable, one host in multiple groups), and assign variables via group_vars/ and host_vars/. Target with patterns using the operators : :& :!. For the cloud, use dynamic inventory (a plugin like aws_ec2) to auto-discover and group hosts by tag. Use ansible-inventory --graph/--host to check.
With hosts and variables in place, now we write Ansible's main thing: the playbook. Article 4.