Skip to main content
RunBook Academy

LinuxXXXIV · Configuration ManagementInventory

Inventory and facts - knowing your fleet

Intermediate⏱ ~10 minansible

What you'll learn

  • Build a static inventory
  • Use dynamic inventory for cloud and CMDB
  • Gather and use host facts
  • Group hosts by role

Prerequisites

Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09

Not yet marked complete on this device.

Ansible inventory is the list of hosts and groups. Facts are gathered host variables. Together they let playbooks target the right hosts with the right configuration.

Static inventory

# /etc/ansible/hosts
web01.example.com
web02.example.com
db01.example.com

[webservers]
web01.example.com
web02.example.com

[databases]
db01.example.com

[production:children]
webservers
databases

Inventory can be a file, a directory of files, or a dynamic source.

Dynamic inventory

For dynamic fleets (cloud, CMDB, LDAP), point -i at an inventory plugin configuration instead of a static file. The plugin queries the source at run time, so the inventory can never be stale relative to what is actually deployed.

The configuration is YAML and lives in your repository:

# inventory/aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions:
  - eu-west-1
filters:
  instance-state-name: running
keyed_groups:
  - key: tags.Role
    prefix: role
  - key: tags.Environment
    prefix: env
ansible-playbook -i inventory/aws_ec2.yml site.yml

keyed_groups is the part that earns its keep. It turns instance tags into Ansible groups, so role_webserver and env_prod exist without anyone maintaining them. That is what makes environment separation and wave-by-wave targeting possible on a fleet that changes hourly — a hand-written file cannot keep up, and the failure mode when it falls behind is a playbook that skips the host nobody noticed was missing.

Always inspect the resolved inventory before you run anything against it:

ansible-inventory -i inventory/aws_ec2.yml --graph   # group tree
ansible-inventory -i inventory/aws_ec2.yml --list    # full hostvars

Other sources follow the same shape: openstack.cloud.openstack, community.vmware.vmware_vm_inventory, azure.azcollection.azure_rm. Run ansible-doc -t inventory -l to list the plugins your installed collections provide.

Group by role

Group hosts by role, environment, or any other dimension:

[webservers]
web[01:10].example.com

[webservers:vars]
nginx_worker_processes=4

[databases]
db[01:03].example.com

[production]
web[01:10].example.com
db[01:03].example.com

:vars sets group variables. [01:10] is a range (web01 through web10).

Facts

Gathered facts describe each host:

- hosts: all
  tasks:
    - debug:
        var: ansible_facts

Common facts:

  • ansible_hostname: the host’s name.
  • ansible_default_ipv4.address: primary IPv4 address.
  • ansible_distribution: Linux distribution (Ubuntu, RHEL).
  • ansible_distribution_version: version (22.04, 9.x).
  • ansible_kernel: kernel version.
  • ansible_memtotal_mb: total memory in MB.
  • ansible_processor_count: number of CPU cores.

Use facts in playbooks

- hosts: webservers
  tasks:
    - name: Set worker processes based on CPU count
      lineinfile:
        path: /etc/nginx/nginx.conf
        regexp: '^worker_processes'
        line: "worker_processes {{ ansible_processor_count }};"
      become: yes

Facts are templated with {{ ... }}.

Custom facts

Set custom variables for hosts or groups:

# group_vars/webservers.yml
nginx_listen_port: 80
nginx_worker_processes: 4
# host_vars/web01.example.com.yml
ansible_host: 10.0.0.10

Ansible loads group_vars/<group>.yml and host_vars/<host>.yml automatically.

Conditional playbooks

Use facts to skip tasks:

- hosts: all
  tasks:
    - name: Install nginx on Debian
      apt:
        name: nginx
      when: ansible_os_family == "Debian"

    - name: Install nginx on Red Hat
      dnf:
        name: nginx
      when: ansible_os_family == "RedHat"

Knowledge check

Knowledge check · 3 questions

  1. Q1. Where does Ansible look for inventory by default?

  2. Q2. Facts are gathered automatically on every playbook run.

  3. Q3. Which of the following are valid Ansible facts? Select all that apply.

Passing score: 75%. Answers are checked in this browser.