Inventory decides where your changes land
Teams spend most of their review energy on playbooks and almost none on inventory. That is backwards. A perfect playbook run against the wrong group is still an incident. We have seen stale host files that include decommissioned servers (causing timeouts and noisy failures), and ones that miss new autoscaled instances (leaving them unpatched and unhardened for months).
Inventory is where Ansible meets reality. This page explains how we design it as part of our Ansible configuration management service, and when to pick static files, cloud plugins or AWX smart inventories.
What good looks like
- Every managed host appears in the inventory without anyone typing it in, or the inventory is small enough that typing it is genuinely fine.
- Groups map to how you operate: environment (
production,staging), role (web,db), and sometimes region. - A host can be in several groups. Variables come from groups, so changing a setting for all web servers is one line.
- A reviewer can run one command and see which hosts a playbook will touch before it runs.
- Credentials for reading the cloud API are read-only and scoped narrowly.
How it works in practice
Static inventory
For a small, stable fleet, a YAML file is clear and reviewable:
all:
children:
production:
children:
web:
hosts:
web01.example.internal:
web02.example.internal:
db:
hosts:
db01.example.internal:
staging:
children:
web:
hosts:
web-stg01.example.internal:
Variables go in group_vars/web.yml, group_vars/production.yml and so on. When the same host belongs to web and production, Ansible merges both sets of variables according to documented precedence, which we write down for your team.
Dynamic inventory on AWS
For autoscaling groups and short-lived instances, a static file is wrong by definition. The amazon.aws.aws_ec2 plugin reads instance data directly:
# inventories/aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions:
- eu-west-1
filters:
instance-state-name: running
tag:ManagedBy: ansible
keyed_groups:
- key: tags.Environment
prefix: env
- key: tags.Role
prefix: role
hostnames:
- tag:Name
- private-ip-address
compose:
ansible_host: private_ip_address
This creates groups such as env_production and role_web from tags. The quality of the inventory is therefore the quality of your tagging, which is why we agree a tag standard with whoever runs your cloud accounts. If you also use Terraform, add the tags in code so every instance is born correctly labelled, as described in our Terraform service.
You can preview what the plugin returns without running anything:
ansible-inventory -i inventories/aws_ec2.yml --graph
ansible-inventory -i inventories/aws_ec2.yml --host web01 --yaml
Dynamic inventory on Azure
Azure uses the azure.azcollection.azure_rm plugin, with a file ending in azure_rm.yml. The ideas are the same: filter by resource group or tag, create groups with keyed_groups, and compose a reachable ansible_host. Authentication uses a service principal or managed identity, scoped to reader access.
Combining sources
Pointing Ansible at a directory merges everything inside it. A common layout is one dynamic file for cloud, one static file for on-premises hosts and a shared group_vars directory. The rule is simple: group names must mean the same thing in every source.
AWX inventories and smart inventories
In AWX or Automation Platform, inventories are objects with sources that sync on a schedule. A smart inventory is a filtered view across them. Useful examples include all hosts with a given operating system, all hosts in env_production with a fact showing a pending reboot, or all hosts whose name matches a pattern. Smart inventories rely on facts being cached, so we enable fact caching and a scheduled fact-gathering job. They pair naturally with patching automation.
Decisions and trade-offs
Static versus dynamic. Static is easy to read and review, and it works offline. Dynamic is always current but depends on API access and tags. For mixed estates we use both, and we keep the static part small.
Tags versus naming conventions. Tags are more reliable than parsing hostnames. Where a legacy estate has no tags, we begin with naming patterns and migrate to tags gradually.
Variables on hosts. Tempting, and a source of surprises. If one server needs a special setting, that is often a sign it deserves its own group.
When a CMDB is better. If you already have a trusted CMDB, we can write a small inventory script or plugin against it instead of duplicating data. If your CMDB is not trusted, do not build on it.
Common failure modes
- Untagged instances. They silently drop out of every group. We add a CI or scheduled check that lists untagged hosts.
- Name collisions across accounts. Two accounts with a host called
web01. We use a hostname scheme that includes environment or account. - API rate limits and slow runs. Large estates make inventory refresh slow. We enable caching on the plugin and scope regions and filters tightly.
- Over-broad credentials. Inventory needs read access only. Anything more is a risk. See secrets handling for how credentials are stored.
- Ambiguous precedence. Variables defined in several places. We document the order and keep the places few.
Delivery and handover
You receive the inventory files and plugin configs in Git, a tag standard, CI that runs ansible-inventory --list and fails on duplicate hosts or missing groups, and AWX inventory sources if you use AWX. Our documentation deliverable includes a variable reference that shows which group each setting comes from.
A handover detail that saves a weekend
We leave a short “inventory contract” in the repository: which group names are stable and safe to target, which are generated and may change, and which variables each group is allowed to set. Without it, a new engineer invents a group during an incident and the next sync quietly removes it. Keep the contract next to the inventory, review it when cloud tagging conventions change, and treat a renamed tag as a breaking change.
How to tell it is working
- New instances appear in the right groups within one sync interval, with no human involved.
- Retired instances disappear from runs without edits.
- You can answer “which hosts will this change touch?” before pressing run.
- Host-level variable overrides are rare and each has a comment.
- Nobody maintains a spreadsheet of servers on the side.
If you are not sure your inventory matches your estate, contact us and we will compare the two.
References
- How to build your inventory, Ansible Community Documentation
- Working with dynamic inventory, Ansible Community Documentation
- amazon.aws.aws_ec2 inventory, EC2 inventory source, Ansible Community Documentation
- azure.azcollection.azure_rm inventory, Azure Resource Manager inventory plugin, Ansible Community Documentation