Ansible Inventory Groups — Organize Hosts for Targeted Automation

Introduction

Inventory groups let you target specific sets of hosts — run a playbook on all web servers, or just the production database tier. This guide covers static group definitions, nested groups, host patterns, group variables, and common organizational patterns for real infrastructure.

Basic Group Structure

# inventory/hosts
[webservers]
web01.example.com
web02.example.com
web03.example.com

[dbservers]
db01.example.com
db02.example.com

[loadbalancers]
lb01.example.com

YAML Format

# inventory/hosts.yml
all:
  children:
    webservers:
      hosts:
        web01.example.com:
        web02.example.com:
        web03.example.com:
    dbservers:
      hosts:
        db01.example.com:
        db02.example.com:
    loadbalancers:
      hosts:
        lb01.example.com:

Nested Groups (Children)

# inventory/hosts
[webservers]
web01.example.com
web02.example.com

[dbservers]
db01.example.com

[monitoring]
grafana01.example.com

# Parent groups using :children
[production:children]
webservers
dbservers
loadbalancers

[staging:children]
staging_web
staging_db

[all_servers:children]
production
staging
monitoring

Environment-Based Organization

inventory/
├── production/
│   ├── hosts.yml
│   └── group_vars/
│       ├── all.yml
│       ├── webservers.yml
│       └── dbservers.yml
├── staging/
│   ├── hosts.yml
│   └── group_vars/
│       ├── all.yml
│       └── webservers.yml
└── development/
    └── hosts.yml
# Target specific environment
ansible-playbook -i inventory/production site.yml
ansible-playbook -i inventory/staging site.yml

Host Patterns

# All hosts in a group
ansible webservers -m ping

# Multiple groups (OR)
ansible 'webservers:dbservers' -m ping

# Intersection (AND) — hosts in BOTH groups
ansible 'production:&webservers' -m ping

# Exclusion (NOT) — production except dbservers
ansible 'production:!dbservers' -m ping

# Wildcards
ansible 'web*' -m ping
ansible '*.example.com' -m ping

# Regex
ansible '~web[0-9]+\.example\.com' -m ping

# Numbered ranges
ansible 'web[01:50].example.com' -m ping

# Single host
ansible web01.example.com -m ping

# All hosts
ansible all -m ping

Group Variables

# group_vars/webservers.yml
http_port: 80
max_connections: 1000
document_root: /var/www/html
ssl_enabled: true

# group_vars/dbservers.yml
postgresql_port: 5432
max_connections: 200
shared_buffers: 4GB
# group_vars/all.yml (applies to every host)
ansible_user: deploy
ansible_python_interpreter: auto_silent
ntp_server: time.example.com
dns_servers:
  - 10.0.0.53
  - 10.0.1.53

Host Variables

# Per-host overrides
[webservers]
web01.example.com http_port=8080 max_connections=2000
web02.example.com
web03.example.com ansible_host=10.0.1.103
# host_vars/web01.example.com.yml
http_port: 8080
max_connections: 2000
ssl_certificate: /etc/ssl/web01.pem

Variable Precedence (Group Level)

1. host_vars/hostname.yml     (highest)
2. group_vars/child_group.yml
3. group_vars/parent_group.yml
4. group_vars/all.yml         (lowest)

Real-World Patterns

Functional Grouping

[webservers]
[appservers]
[dbservers]
[cacheservers]
[messagequeues]

Geographic Grouping

[us_east]
[us_west]
[eu_west]
[ap_southeast]

[north_america:children]
us_east
us_west

Combined Pattern

# Functional
[webservers]
web-us-east-01
web-us-west-01
web-eu-01

[dbservers]
db-us-east-01
db-eu-01

# Geographic
[us_east]
web-us-east-01
db-us-east-01

[eu_west]
web-eu-01
db-eu-01

# Environment
[production:children]
webservers
dbservers

Playbook Targeting

---
# Deploy to web servers only
- name: Deploy web application
  hosts: webservers
  tasks:
    - name: Deploy code
      ansible.builtin.git:
        repo: https://github.com/org/webapp.git
        dest: /var/www/app

---
# Database maintenance — production only
- name: Database backup
  hosts: production:&dbservers
  tasks:
    - name: Dump database
      community.postgresql.postgresql_db:
        name: app_db
        state: dump
        target: /backups/app_db.sql

---
# Rolling update — exclude load balancers
- name: System updates
  hosts: production:!loadbalancers
  serial: "25%"
  tasks:
    - name: Update packages
      ansible.builtin.apt:
        upgrade: safe

Magic Groups

Ansible automatically creates two groups:

# "all" — every host in inventory
# "ungrouped" — hosts not in any explicit group

[ungrouped]
standalone-server.example.com  # Only in "all" and "ungrouped"

List and Debug Groups

# Show all groups and hosts
ansible-inventory --list

# Show graph (tree view)
ansible-inventory --graph
# @all:
#   |--@webservers:
#   |  |--web01.example.com
#   |  |--web02.example.com
#   |--@dbservers:
#   |  |--db01.example.com

# Show specific host's variables
ansible-inventory --host web01.example.com

# List hosts matching a pattern
ansible 'production:&webservers' --list-hosts

Troubleshooting

IssueSolution
"No hosts matched"Check group name spelling, verify with --list-hosts
Variable not applyingCheck precedence — host_vars > child group_vars > parent group_vars
Host in wrong groupRun ansible-inventory --graph to visualize
Duplicate host warningsSame host listed in multiple places — use :children instead
Group vars file ignoredFilename must match group name exactly

Best Practices

  1. Use both functional and environment groups — target "production web servers" precisely
  2. Keep group_vars/all.yml minimal — only truly global settings
  3. One host_vars file per special host — don't clutter inventory file
  4. Use YAML inventory for complex setups — more readable than INI
  5. Separate inventory per environment — inventory/production/, inventory/staging/
  6. Document group purpose — comments in inventory file

Conclusion

Organize inventory into functional groups (webservers, dbservers) and environmental groups (production, staging). Use nested groups with :children for hierarchical targeting. Apply variables at the right level — group_vars/all.yml for global, group_vars/webservers.yml for role-specific, host_vars/ for individual overrides. Debug with ansible-inventory --graph and target precisely with patterns like production:&webservers:!maintenance.