unit 3 · Inventory

Patterns, --limit & per-env inventories

Deciding exactly which hosts a run touches

essential · 7 min · linux + windows

you may want to read 8 · Inventory: INI and YAML first — but nothing is locked

tl;dr

  • Patterns pick hosts at run time: all, web*, web:&staging (in both), web:!db (web minus db).
  • --limit narrows any run to the hosts you name — the re-run and debugging flag.
  • One inventory directory per environment is the guardrail that stops a staging run touching prod.

why it matters Target the wrong hosts and Ansible cheerfully configures the wrong hosts — patterns, --limit and per-environment inventories are the three controls that decide where a run lands, prod included.

Lesson 8 gave you an inventory full of groups. Every command since has opened with a target — web, all — and those are the two simplest cases of a pattern , the expression that decides which inventory hosts a run touches. Nothing in Ansible executes anywhere until a pattern has said where.

Four forms cover most of what you’ll see:

ansible all -m ansible.builtin.ping             # every host in the inventory
ansible 'web*' -m ansible.builtin.ping          # wildcard: web01, web02, webcache...
ansible 'web:&staging' -m ansible.builtin.ping  # in web AND in staging
ansible 'web:!db' -m ansible.builtin.ping       # in web but NOT in db
the four pattern forms, on the ad-hoc command you already know

Read the last two as set operations on groups. web:&staging is an intersection — only hosts that belong to both groups. web:!db is an exclusion — the web group with the db members subtracted. The quotes are for your shell, not Ansible: ! and & mean things to bash. One more you’ll meet constantly: a bare : between two group names is a unionweb:db means everything in either group.

--limit: narrow the run you already wrote

--limit is the outside control: a run-control flag that narrows any run to the hosts you name, without editing a thing. When you reach playbooks in unit 4, each play declares its own targets — --limit cuts below that declaration.

# the full run, as the play targets it
ansible-playbook site.yml -i inventories/staging/
# identical run, narrowed to the one host that failed
ansible-playbook site.yml -i inventories/staging/ --limit web01
same playbook, progressively smaller blast radius

That second line is why --limit sits in the debugging toolkit next to -vvv and --check: one host broke mid-run, you fix the cause, you re-run against just that host instead of hammering the whole fleet again.

One inventory directory per environment

Here is the structural habit that matters more than any pattern syntax. Best practice is a separate inventory directory per environment, each carrying its own group_vars and host_vars :

inventories/
  production/
    hosts.yml        # prod hosts and groups
    group_vars/      # prod values live with prod
    host_vars/
  staging/
    hosts.yml        # same group names, different machines
    group_vars/
    host_vars/
the environment IS the directory you point -i at

You choose the environment the moment you type -i inventories/production/. That is the entire mechanism behind the standup phrase “run the playbook against prod” — same playbook, prod inventory. Keep group_vars/all.yml minimal; anything environment-specific belongs inside that environment’s directory, not in a shared file both environments read.

Before trusting any inventory, look at what it actually contains: ansible-inventory --graph -i inventories/staging/ prints the group tree Ansible resolved. Make that your reflex before the first run against any inventory you didn’t write — the same cheapest-fact-first instinct as the ping in lesson 7, one level up.

at work, this sounds like

“Run the playbook against prod.”
Execute it with the production inventory — ansible-playbook site.yml -i inventories/prod/.

self-check — recall, not a test

  1. 1 What do web:&staging and web:!db each match?

  2. 2 A playbook run failed on one host. How do you re-run it against just that host without editing anything?

  3. 3 Why one inventory directory per environment instead of one big inventory holding prod and staging groups?

lab (optional — never required)

Build inventories/staging/ and inventories/production/ with one host each, inspect both with ansible-inventory --graph -i <dir>, then ping with a pattern and again with --limit.

needs: The control node from lesson 5.

PLAY RECAP ************************** 10-patterns-and-limit : ok=1 next=11-dynamic-inventory read=6m