Acumatica · Ansible

Ansible in 2026 — A Field Guide

Ansible in 2026 — A Field Guide is the work that turns a deploy into a system. The deployment is one moment; the system is the next 18 months of uptime, incidents, and.

John Kihiu12 min read

Ansible remains the default choice for configuration management and lightweight orchestration precisely because it hasn't changed its core model: SSH (or WinRM) plus Python, no agent to install, YAML playbooks that read close to plain English. What has changed by 2026 is the tooling around it — execution environments, the collection ecosystem, and how it fits into a GitOps-driven pipeline rather than being run ad hoc from a laptop.

Execution environments replace ad hoc Python setups

The old failure mode — "works on my machine" because of a locally installed collection or a Python library version mismatch — is what execution environments (container images built with ansible-builder, bundling Ansible core, a defined set of collections, and their Python dependencies) are designed to eliminate. Running playbooks through ansible-navigator against an execution environment means the automation runs identically whether it's triggered from a developer's laptop, a CI runner, or AWX/Ansible Automation Platform.

YAML · EXECUTION ENVIRONMENT DEFINITION
version: 3
images:
  base_image:
    name: quay.io/ansible/ansible-runner:latest
dependencies:
  galaxy: requirements.yml
  python: requirements.txt
  system: bindep.txt

# requirements.yml
collections:
  - name: community.general
    version: ">=8.0.0"
  - name: amazon.aws
    version: ">=7.0.0"

Collections, not a monolithic core

Since the 2.10 split, Ansible ships as a thin core plus independently versioned collections (community.general, ansible.posix, cloud-vendor collections like amazon.aws). Pin collection versions in requirements.yml the same way you'd pin a package.json dependency — an unpinned ansible-galaxy collection install pulling the latest version of a cloud collection is a common source of a playbook that worked last month silently breaking this month.

ansible-lint catches what code review misses

Run ansible-lint in CI against every playbook change. It catches the class of bugs that are easy to miss by eye — missing become: true, unquoted Jinja expressions, tasks without a name, and use of deprecated module arguments — before they reach a target host.

Idempotency is still the design contract, not a nice-to-have

A playbook re-run against a host that's already in the desired state should report zero changes. This is what separates Ansible modules from a raw shell script and is the property that makes drift detection and safe re-runs possible. The most common way teams break it is reaching for ansible.builtin.shell or command where a proper module exists — a shell command has no built-in concept of "already done," so it runs and reports "changed" every time regardless of actual state.

Use creates/removes as an escape hatch, not a habit

When a shell or command task is genuinely unavoidable, the creates: or removes: argument gives you a cheap idempotency check by testing for a file's existence. It's not a substitute for a real module, but it's better than a task that reports "changed" on every run regardless of actual system state.

Ansible inside a GitOps pipeline

The 2026-era pattern is less "run ansible-playbook from a laptop" and more "a merge to main triggers a pipeline that runs the playbook against a defined inventory, with the run's output posted back to the PR." Ansible Automation Platform's job templates, or a plain CI runner invoking ansible-playbook inside the execution environment container, both fit this model — the important shift is that inventory and playbook changes go through the same review process as application code, not an out-of-band change.

Dynamic inventory over static files

Static hosts.ini files rot the moment infrastructure becomes elastic. Cloud inventory plugins (amazon.aws.aws_ec2, azure.azcollection.azure_rm) query the provider's API at run time and group hosts by tags automatically, so a playbook targeting tag_Environment_production stays correct as instances are created and terminated, with no inventory file to maintain by hand.

Old habit2026 practice
Local pip install of ansible + collectionsExecution environment container, versioned
Unpinned ansible-galaxy installPinned versions in requirements.yml
Static hosts.iniDynamic cloud inventory plugin
Playbook run from a laptopTriggered from CI/CD against reviewed changes

Wrapping up

Ansible's core value proposition — agentless, idempotent, readable — hasn't moved. What's matured is the packaging around it: execution environments for reproducibility, pinned collections instead of a moving-target core, and running playbooks through the same review and CI gates as any other code change. Skip the execution environment step at your peril; it's the fix for the single most common "worked yesterday" bug report in Ansible-managed infrastructure.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.