Four reference files covering: - ansible.md — core commands, ansible.cfg, key settings - ansible-inventory.md — static/dynamic inventory, directory layout - ansible-variables.md — 22-level precedence, scoping, merge behavior - ansible-roles.md — structure, defaults vs vars, dependencies
5.6 KiB
5.6 KiB
Ansible Inventory
Define which hosts to manage, how to group them, and where to find them.
Inventory Formats
INI Format
# inventory/hosts.ini
[webservers]
web1.example.com
web2.example.com ansible_port=2222
[dbservers]
db1.example.com ansible_user=postgres
db[1:3].example.com # db1, db2, db3
[loadbalancers]
lb1.example.com
# Group of groups
[production:children]
webservers
dbservers
loadbalancers
# Group variables
[webservers:vars]
http_port=8080
app_env=production
[all:vars]
ansible_python_interpreter=/usr/bin/python3
YAML Format (preferred)
# inventory/hosts.yml
all:
vars:
ansible_python_interpreter: /usr/bin/python3
children:
production:
children:
webservers:
hosts:
web1.example.com:
web2.example.com:
ansible_port: 2222
vars:
http_port: 8080
dbservers:
hosts:
db1.example.com:
ansible_user: postgres
loadbalancers:
hosts:
lb1.example.com:
Directory Layout
inventory/
├── hosts.yml # Host definitions
├── group_vars/
│ ├── all.yml # Vars for every host
│ ├── all/ # Dir form (merged, alphabetical)
│ │ ├── common.yml
│ │ └── vault.yml # Encrypted secrets
│ ├── webservers.yml # Vars for webservers group
│ └── production.yml # Vars for production parent group
└── host_vars/
├── web1.example.com.yml
└── db1.example.com/ # Dir form
├── main.yml
└── vault.yml
Multiple Environments
inventories/
├── staging/
│ ├── hosts.yml
│ ├── group_vars/
│ └── host_vars/
└── production/
├── hosts.yml
├── group_vars/
└── host_vars/
ansible-playbook site.yml -i inventories/staging/
ansible-playbook site.yml -i inventories/production/
Dynamic Inventories
Script-Based (legacy)
A script that outputs JSON when called with --list or --host <name>.
#!/usr/bin/env python3
# inventory/dynamic.py — must be executable (chmod +x)
import json, sys
def get_inventory():
return {
"webservers": {
"hosts": ["web1.example.com", "web2.example.com"],
"vars": {"http_port": 8080}
},
"dbservers": {
"hosts": ["db1.example.com"]
},
"_meta": {
"hostvars": {
"web1.example.com": {"ansible_port": 22},
"db1.example.com": {"ansible_user": "postgres"}
}
}
}
if "--list" in sys.argv:
print(json.dumps(get_inventory(), indent=2))
elif "--host" in sys.argv:
host = sys.argv[sys.argv.index("--host") + 1]
hostvars = get_inventory().get("_meta", {}).get("hostvars", {})
print(json.dumps(hostvars.get(host, {})))
The _meta.hostvars key avoids per-host --host calls (efficiency).
Plugin-Based (modern, preferred)
# inventory/aws_ec2.yml — filename must end with the plugin suffix
plugin: amazon.aws.aws_ec2
regions:
- eu-west-1
keyed_groups:
- key: tags.Environment
prefix: env
- key: instance_type
prefix: type
filters:
tag:Managed: ansible
compose:
ansible_host: private_ip_address
Common inventory plugins:
| Plugin | Source | Suffix |
|---|---|---|
amazon.aws.aws_ec2 |
AWS EC2 | aws_ec2.yml |
azure.azcollection.azure_rm |
Azure | azure_rm.yml |
google.cloud.gcp_compute |
GCP | gcp.yml |
community.general.proxmox |
Proxmox | proxmox.yml |
community.docker.docker_containers |
Docker | docker.yml |
ansible.builtin.constructed |
Derived | constructed.yml |
# Verify dynamic inventory output
ansible-inventory -i inventory/aws_ec2.yml --graph
ansible-inventory -i inventory/aws_ec2.yml --list
Constructed Inventory (compose groups from existing data)
# inventory/constructed.yml
plugin: ansible.builtin.constructed
strict: false
groups:
is_debian: ansible_os_family == "Debian"
is_large: ansible_memtotal_mb > 8192
keyed_groups:
- key: ansible_distribution | lower
prefix: os
Special Variables
| Variable | Purpose |
|---|---|
ansible_host |
IP/hostname to connect to |
ansible_port |
SSH port (default: 22) |
ansible_user |
SSH user |
ansible_ssh_private_key_file |
SSH key path |
ansible_become |
Enable privilege escalation |
ansible_connection |
Connection type (ssh, local) |
ansible_python_interpreter |
Python path on target |
Gotchas
- Script inventories must be executable (
chmod +x) and have a shebang - Plugin inventory files must end with the correct suffix or be listed in
enable_plugins group_vars/directory must sit next to the inventory file, or at playbook level- YAML inventory: hosts need trailing colon even with no vars (
web1.example.com:) - Groups named
allandungroupedare implicit — don't redefine them - Directory form
group_vars/all/merges files alphabetically — name carefully
See Also
ansible— core commands and ansible.cfgansible-variables— variable precedence across inventory layersansible-roles— role structure and organization