Ansible in 2026: Where It Still Beats Containers

Philip Rehberger Oct 30, 2026 7 min read

Use Ansible for the workloads containers do not fit. Bare metal, VMs, and one-shot configuration.

Ansible has been the dominant configuration management tool for a decade. Then containers showed up, and the "we use Ansible to configure servers" pattern got replaced by "we ship Docker images." Many teams retired Ansible.

But Ansible did not die. It survived in the workloads where containers do not fit — and there are still many of those. This post is what those workloads look like, when Ansible remains the right tool, and the patterns that hold up in 2026.

Where Ansible Still Wins

Concrete scenarios where Ansible beats containers in 2026:

Bare-metal servers. Hardware in a colo, on-premises servers, edge appliances. You cannot run them as containers; something has to configure the OS. Ansible is well-suited.

Network devices. Switches, routers, firewalls. Many support Ansible modules. Containerizing a switch makes no sense.

Legacy workloads. Systems built on Linux that cannot be cleanly containerized (kernel modules, hardware access, complex inter-process dependencies). Ansible manages the surrounding configuration.

Cloud provisioning of complete VMs. If a workload runs as a full VM (not a container) and needs configuration beyond what cloud-init handles, Ansible plays a role.

Initial bootstrapping. Before Kubernetes, before Docker, before any of the higher-level abstractions — Ansible can bootstrap the base layer.

One-off operational tasks. "Run this update across these 200 servers" is exactly Ansible's wheelhouse.

If your entire stack runs as containers in Kubernetes, you probably do not need Ansible. If you have anything outside that, Ansible likely still plays a role.

What Ansible Is

Ansible runs over SSH. A control node has Ansible installed; target nodes need only SSH and Python. The control node connects, runs tasks, and disconnects.

A simple playbook:

---
- name: Configure web servers
  hosts: webservers
  become: yes
  tasks:
    - name: Install nginx
      apt:
        name: nginx
        state: present
        update_cache: yes

    - name: Copy nginx config
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: restart nginx

    - name: Ensure nginx is running
      service:
        name: nginx
        state: started
        enabled: yes

  handlers:
    - name: restart nginx
      service:
        name: nginx
        state: restarted

ansible-playbook -i inventory webservers.yml runs this against every host in the webservers group. The same playbook can configure 1 server or 1,000.

Idempotency

The most important Ansible property: tasks are idempotent. Running a playbook twice does not produce different results than running it once.

- name: Ensure user exists
  user:
    name: deploy
    state: present
    shell: /bin/bash

- name: Ensure SSH key is authorized
  authorized_key:
    user: deploy
    key: "{{ lookup('file', 'deploy_key.pub') }}"

The first run creates the user and adds the key. The second run reports "ok" — nothing changed. Ansible's modules check current state before acting.

This is what makes Ansible safe to run repeatedly. Configuration drift gets corrected; existing-correct state is left alone.

Inventory and Groups

Ansible's inventory describes the hosts:

# Static inventory
[webservers]
web1.example.com
web2.example.com
web3.example.com

[dbservers]
db1.example.com

[production:children]
webservers
dbservers

For dynamic inventory (cloud-based), Ansible has plugins for AWS EC2, Azure, GCP, etc. The plugin queries the cloud and produces the inventory at runtime.

# aws_ec2.yml dynamic inventory plugin
plugin: amazon.aws.aws_ec2
regions:
  - us-east-1
keyed_groups:
  - key: tags.Role
    prefix: role

Now role_webserver and role_database groups exist based on EC2 tags.

Roles

Roles bundle tasks, handlers, templates, and variables into reusable units.

roles/
├── nginx/
│   ├── tasks/main.yml
│   ├── handlers/main.yml
│   ├── templates/nginx.conf.j2
│   └── defaults/main.yml
├── monitoring/
└── security/

A playbook applies roles to hosts:

- hosts: webservers
  roles:
    - security
    - monitoring
    - nginx
    - role: app
      vars:
        app_version: "1.4.0"

For production setups, roles are the unit of reuse. The same monitoring role applies to every server type.

Variables and Secrets

Variables can come from many sources: defaults, inventory, command line, vault.

For secrets: Ansible Vault encrypts variables in version control.

ansible-vault encrypt_string 'super-secret-password' --name 'db_password'

The encrypted string can be committed to git. At runtime, supply the vault password (from a file, environment, or prompt) to decrypt.

For larger setups: integrate with a real secrets manager (Vault, AWS Secrets Manager, etc.) via Ansible's lookup plugins.

Modes of Operation

Three common modes:

Push. The control node connects to targets and runs tasks. The default mode. Good for ad-hoc operations and small fleets.

Pull (ansible-pull). Each target pulls its config from a git repo and runs locally. Better for very large fleets and edge devices where push is impractical.

AWX / Ansible Automation Platform. A web UI and API on top of Ansible. Manages playbook runs, schedules, audit logs. Common in larger organizations.

For most teams: push from CI is enough. AWX is the right call when many people need to run Ansible playbooks with audit trails.

Performance at Scale

Ansible's push model is mostly serial — it connects to hosts and runs tasks. For 1,000 hosts, this is slow unless you tune it.

Parallelism (forks): how many hosts Ansible operates on at once. Default is 5; bump to 50 or 100 for large fleets.

Fact gathering: Ansible gathers facts about each host by default. For large fleets, this is wasted time. Disable with gather_facts: no when not needed.

Async tasks: long-running tasks can run asynchronously, polled for completion. Useful for slow operations like package installs.

- name: Install package
  apt: name=heavy-package state=present
  async: 600
  poll: 0

For a fleet of thousands: parallelism + async + selective fact gathering brings runtimes to manageable levels.

Drift Detection

A common Ansible pattern: scheduled idempotent runs against the fleet. If something has drifted (someone manually changed a file), the next Ansible run corrects it.

# Hourly cron on the control node
ansible-playbook -i inventory site.yml --check --diff

--check runs in dry-run mode; --diff shows what would change. Combined with monitoring, you see drift before it causes problems.

For active enforcement: drop the --check flag and let Ansible correct drift automatically.

When to Use Ansible vs Alternatives

Ansible vs Terraform. Different layers. Terraform provisions infrastructure (the VM exists). Ansible configures it (the VM has nginx). Most teams use both.

Ansible vs Salt / Chef / Puppet. Older alternatives, mostly displaced by Ansible's simpler model. Salt is still in use for very large fleets where its pub/sub model scales better.

Ansible vs cloud-init. Cloud-init runs once at first boot. Ansible can run repeatedly. For workloads that need ongoing configuration management, Ansible. For workloads that only need bootstrap, cloud-init.

Ansible vs Docker images / Packer. Different paradigms. Ansible mutates running systems; Docker/Packer build immutable images. Containers and image-based VMs are usually better when applicable. Ansible is for what cannot be done that way.

What Stays in Ansible's Niche

The workloads where Ansible remains the right tool in 2026:

  • Bare-metal servers, on-premises infrastructure
  • Network device configuration
  • Legacy VM-based workloads that cannot be containerized
  • Configuration of complete VMs (post-cloud-init)
  • Fleet operations (one-off tasks across many hosts)
  • Hybrid environments combining cloud, on-prem, and edge

For modern cloud-native workloads in Kubernetes: Ansible is mostly unnecessary. The configuration lives in container images and Kubernetes manifests.

Common Mistakes

  • Using Ansible for what containers do well. A web app being configured by Ansible into a VM, when a container would be simpler.
  • Non-idempotent tasks. Custom shell tasks that fail or change behavior on repeat. Use idempotent modules instead.
  • No version control. Ansible playbooks are code. Treat them as such.
  • Secrets in plaintext. Vault or external secrets manager. Always.
  • No testing. Molecule (Ansible's testing framework) catches regressions before they hit production.

A Practical Modern Use Case

A real team in 2026 might use Ansible for:

  • Configuring bare-metal Kubernetes worker nodes (post-OS-install)
  • Network switch configuration via Ansible network modules
  • Emergency operational tasks across cloud VMs ("rotate this SSH key on every host")
  • Edge appliance configuration where containers do not run

The team's main application infrastructure is containers in Kubernetes. Ansible handles the parts containers do not.

This is the realistic 2026 role of Ansible: necessary, not central. A useful tool for what other tools do not address well.


Working with infrastructure that has both containerized and non-containerized workloads? We help teams design configuration management that handles both without over-investing in either. scopeforged.com

Share this article

Related Articles

Need help with your project?

Let's discuss how we can help you build reliable software.