Git, CI/CD & GitOpsCX · Ansible Delivery PipelineEnvironments
Staged validation environments — dev, staging, prod
What you'll learn
- Explain why Ansible delivery uses per-environment inventories instead of per-environment rebuilds
- Distinguish the dev, staging, and production inventories by what differs and what is shared
- Configure the Molecule scenario to test against the staging inventory without production credentials
- Recognise why promotion through stages is a credential swap, not a rebuild
Prerequisites
Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x
An Ansible delivery pipeline promotes a role through dev, staging, and production by swapping the inventory, not by rebuilding the artefact. This is the architectural distinction that makes Ansible delivery different from container delivery, where the same image moves through environments by tag, and from Terraform delivery, where the same plan is applied against different backends. In Ansible delivery, the role is the artefact; the inventory is the environment.
Why Ansible uses per-environment inventories
Three properties of Ansible make the inventory the natural promotion boundary:
- Ansible reads the inventory at apply time. Variables, host groups, and connection parameters resolve when the playbook runs, not when it is committed. The same playbook committed today can apply to a five-host staging inventory tomorrow and a five-hundred-host production inventory next week without modification.
- The role does not embed environment-specific values. A well-written role reads from
vars/anddefaults/, never from a hardcoded hostname or IP. Promoting the role through environments is a matter of changing which variables resolve, not which code runs. - Idempotency is inventory-relative. A role that converges a host to a known state works the same way against dev, staging, or production, provided the inventory describes the host accurately.
A pipeline that builds per-environment artefacts - a dev tarball, a staging tarball, a prod tarball - has misunderstood the medium. The artefact is the role; the inventory is the environment.
The three stages and what differs
The three stages share the same role, the same playbook, the same collection set, and the same role defaults. They differ on exactly three axes:
flowchart LR
A["Same role and playbook"] --> B["dev inventory"]
A --> C["staging inventory"]
A --> D["production inventory"]
B --> B1["ephemeral VMs"]
B --> B2["dev vault password"]
B --> B3["verbose logging"]
C --> C1["long-lived staging fleet"]
C --> C2["staging vault password"]
C --> C3["standard logging"]
D --> D1["production fleet"]
D --> D2["prod vault password"]
D --> D3["minimal logging"]
- Hosts. Dev points at ephemeral VMs that are created and destroyed per change. Staging points at a long-lived fleet that mirrors production in size and topology. Production points at the real fleet.
- Vault password. Each environment has its own Ansible Vault, encrypted with its own password. The dev vault contains fake credentials. The staging vault contains real-looking credentials scoped to the staging fleet. The production vault contains the actual credentials. The passwords live in separate secrets stores with separate access lists.
- Logging verbosity. Dev runs with
-vor-vvvso contributors can see module arguments. Production runs at default verbosity so secrets do not appear in logs.
Everything else - role variables, playbook structure, group_vars structure, handler definitions - is identical. The pipeline passes the inventory file as a parameter at apply time and the role behaves identically across environments.
How the pipeline passes the inventory
The CI job for each stage specifies the inventory as a flag:
ansible-playbook -i inventories/staging playbook.yml
The inventory file is committed to the repository. The vault password is not committed; it is fetched from the secrets store at job start. The CI configuration maps each branch or environment to an inventory path:
| Stage | Branch | Inventory path | Vault source |
|---|---|---|---|
| Dev | feature branches | inventories/dev/hosts | secrets/dev-vault-password |
| Staging | main after merge | inventories/staging/hosts | secrets/staging-vault-password |
| Production | tagged release | inventories/production/hosts | secrets/production-vault-password |
The mapping is enforced by the CI configuration and by the secrets store’s protected-environment rules. A PR job cannot reach the production vault password because the production vault is scoped to the production protected environment in the secrets store.
Molecule and the staging inventory
The Molecule scenario for a role should test against an inventory that resembles staging as closely as possible. The molecule/default/molecule.yml configuration file accepts an inventory section that points at a fixture inventory committed alongside the scenario:
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: instance
image: geerlingguy/docker-rockylinux9-ansible:latest
provisioner:
name: ansible
inventory:
links:
hosts: ../../inventories/staging/hosts
group_vars: ../../inventories/staging/group_vars
verifier:
name: ansible
The links section points Molecule at the staging inventory rather than at a scenario-local fixture. The role runs against the same group_vars structure the staging apply will use, which surfaces variable-resolution differences before they reach production.
This is also what makes promotion a credential swap, not a rebuild. The role, the playbook, and the inventory structure are identical between Molecule and staging and production. Only the host list, the vault password, and the secrets backing the vault change.
What this discipline prevents
Three failure modes the per-environment inventory pattern prevents:
- Configuration drift between Molecule and staging. A Molecule scenario that uses a fixture inventory can pass while staging fails because the fixture did not match the real group_vars structure.
- Credential leakage between environments. A single vault password used for all three environments means a compromised dev vault exposes production credentials. Per-environment vaults and per-environment passwords break that chain.
- Rebuild theatre. A pipeline that rebuilds the role per environment is a pipeline that has to test three artefacts instead of one. Per-environment inventory keeps the artefact count at one and the test count at one.
Production discipline
- Inventory files are committed. The apply that production runs should be replayable from the commit, the inventory, and the vault password alone.
- Vault passwords are per-environment. A single vault password that opens all three vaults is a single vault.
- Production inventory changes through PRs. Editing the production inventory in the console is the same class of error as editing production hosts in the AWS console.
- Molecule uses the staging inventory structure. A Molecule scenario that uses a fixture inventory is a scenario that has not been tested against the real group_vars layout.
- The apply job’s verbosity is bounded.
-vis acceptable in dev and staging; production runs at default verbosity so secrets do not leak into CI logs.
Cross-course references
- Ansible for Production Sysadmins - Part XX (Inventory) covers the group_vars and host_vars layout this Part builds on.
- Ansible for Production Sysadmins - Part XXI (Vault) covers the per-environment vault pattern in detail.
- This course, Part LVI (Environments) - lessons
git-cicd-gitops-lvi-01throughgit-cicd-gitops-lvi-06cover the broader environment promotion pattern across all IaC tools. - This course, Part CVIII (IaCIntegration) - lesson
git-cicd-gitops-cviii-03covers how the inventory swap compares to image-tag promotion in container pipelines.
Quiz
Knowledge check · 4 questions
Q1. An Ansible delivery pipeline promotes a role from staging to production. What changes between the two applies?
Q2. A single Ansible Vault password used across dev, staging, and production is not necessarily acceptable just because the vault files themselves are scoped per environment.
Q3. Name three properties of the role and playbook that should be identical across the dev, staging, and production applies, and three that should differ.
Q4. Diagnose a delivery pipeline that templates the production inventory from CI variables, and prescribe the structural correction.
A team refuses to commit any production inventory to the repository. The apply job templates the inventory from `ANSIBLE_HOSTS` and `ANSIBLE_VAULT_PASSWORD` CI variables. Six months after a production apply, a security incident requires replaying the exact command against the same host list. The CI logs are gone, the variables have rotated, and the inventory cannot be reconstructed.
Passing score: 75%. Answers are checked in this browser.