Inventory: Static, Dynamic, Groups and Variables

K
Kai··4 min read

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.