DevOps & Platform
10 min readAugust 6, 2026Updated August 19, 2026

What Is Ansible? Agentless Configuration Management Explained

AJ
Ajeet Yadav
Platform & Cloud Engineer
What Is Ansible? Agentless Configuration Management Explained

Quick answer

Ansible connects over SSH, pushes small programs to the machines you name, runs them, and deletes them. No agent, no database, no daemon. Here's the actual execution model, what idempotence really means in practice, and where Ansible stops being the right tool.

10 min read · DevOps & Platform

Ansible is an agentless automation tool that connects to your machines over SSH, copies small programs called modules onto them, executes those modules, collects the results, and deletes them. There is no agent to install on the managed machines, no central server that has to stay running, and no database of state. You describe the configuration you want in YAML, run a command, and Ansible makes the machines match.

That agentless design is the whole pitch. Where other configuration-management tools ask you to bootstrap an agent onto every host and keep a server running to coordinate them, Ansible asks for SSH and Python — things a Linux machine already has.

The execution model

This is the part worth understanding properly, because everything else follows from it.

You run Ansible from a control node — your laptop, a CI runner, a bastion host. The machines you manage are managed nodes, and they need nothing installed beyond an SSH daemon and a Python interpreter.

For each task, Ansible:

  1. Reads your inventory to work out which hosts the task applies to
  2. Generates a small self-contained program — the module with its arguments baked in
  3. Copies it to the target over SSH into a temporary directory
  4. Executes it
  5. Captures the JSON the module prints to stdout
  6. Deletes the temporary directory
  7. Moves to the next task

Two consequences fall out of this immediately.

Ansible only does something when you run it. There is no daemon watching for drift. If someone SSHes into a server at 3 a.m. and edits a config file by hand, Ansible will not notice or care until the next time you run it. This is a genuine difference from GitOps, where an in-cluster agent continuously reconciles.

Ansible pushes; it does not pull. The control node must be able to reach the managed nodes. Machines behind a NAT that you cannot SSH into are not manageable this way without extra plumbing.

The vocabulary

Ansible's terminology is specific, and mixing the terms up makes documentation hard to follow.

TermWhat it is
Control nodeThe machine you run Ansible from
Managed nodeA machine Ansible configures. Needs no agent
InventoryThe list of managed nodes, organised into groups
ModuleA unit of work — install a package, copy a file, restart a service
TaskOne invocation of a module, with arguments
PlayA set of tasks mapped to a group of hosts
PlaybookA YAML file containing one or more plays
RoleA reusable, directory-structured bundle of tasks, files, templates and variables
CollectionA distributable package of roles, modules and plugins
HandlerA task that runs only when notified by another task that changed something

Inventory

The inventory names your hosts and groups them. In YAML:

yaml
1webservers:
2  hosts:
3    web1.example.com:
4    web2.example.com:
5databases:
6  hosts:
7    db1.example.com:
8      ansible_user: postgres

Groups are the targeting mechanism. A play that targets webservers runs on both web hosts and neither database host.

Inventories can also be dynamic — generated by a script or plugin that queries your cloud provider, so the host list reflects reality rather than a file someone forgot to update. On any infrastructure with autoscaling, dynamic inventory is not optional.

A playbook

yaml
1- name: Configure web servers
2  hosts: webservers
3  become: true
4
5  tasks:
6    - name: Install nginx
7      ansible.builtin.apt:
8        name: nginx
9        state: present
10        update_cache: true
11
12    - name: Deploy the site configuration
13      ansible.builtin.template:
14        src: templates/site.conf.j2
15        dest: /etc/nginx/conf.d/site.conf
16        owner: root
17        mode: "0644"
18      notify: Restart nginx
19
20    - name: Ensure nginx is running and enabled
21      ansible.builtin.service:
22        name: nginx
23        state: started
24        enabled: true
25
26  handlers:
27    - name: Restart nginx
28      ansible.builtin.service:
29        name: nginx
30        state: restarted

Read that and the model becomes clear. hosts: selects from the inventory. become: true escalates to root via sudo. Each task names a module and gives it arguments. The template task renders a Jinja2 file and — this is the interesting bit — only notifies the handler if the file actually changed. If the rendered config is byte-identical to what is already there, nginx is not restarted.

Fully qualified collection names

Notice ansible.builtin.apt rather than just apt. That three-part name is a fully qualified collection name (FQCN): namespace, collection, module.

Short names still work for the built-in modules, but write the FQCN. Collections can define modules with the same short name, and the resolution order that decides which one you get is not something you want your production playbook depending on.

The modules bundled with ansible-core live in ansible.builtinapt, dnf, copy, template, file, service, systemd_service, user, group, git, uri, get_url, lineinfile, command, shell, and a few dozen more. Everything else — AWS, Kubernetes, Windows, network devices — ships in separate collections you install with ansible-galaxy.

One historical note that catches people: there is no ansible.builtin.yum in current ansible-core. Use ansible.builtin.dnf on RHEL-family systems. Old playbooks and old tutorials still reference yum.

Terraform Day-2 Operations Checklist

State hygiene, drift, imports, policy checks, and upgrade routines — everything after `terraform apply` works. Plain Markdown, commit it to your repo.

Free. Instant download. You'll also get the occasional deep-dive from the newsletter — unsubscribe anytime.

Idempotence, and what it actually means

Ansible modules are described as idempotent: running a playbook twice produces the same result as running it once, and the second run reports no changes.

This is true for well-written modules and it is the property that makes Ansible safe to run repeatedly. ansible.builtin.apt with state: present checks whether the package is installed and does nothing if it is. ansible.builtin.file with mode: "0644" checks the current mode first.

It is not automatic, and two modules break it by design: ansible.builtin.command and ansible.builtin.shell. They run whatever you give them, every time, and always report a change. That is not a bug — Ansible cannot know whether ./deploy.sh is safe to re-run.

The practical rule: reach for a real module before reaching for shell. When you genuinely need shell, guard it — with creates:, removes:, a when: condition, or a changed_when: expression that reflects reality. A playbook full of unguarded shell tasks is a shell script with extra steps, and it has none of the safety properties people install Ansible for.

What Ansible is good at

Configuring machines that already exist. Packages, users, files, services, kernel parameters, certificates. This is the core competence and nothing does it more simply.

Orchestrating ordered operations across a fleet. Rolling restarts with serial:, draining a node before patching it, running database migrations on exactly one host before restarting the app tier everywhere. Ansible's ordering and delegation primitives are genuinely good, and this is underrated relative to the configuration use case.

One-off operational tasks. Ad-hoc commands across a group of hosts, without writing a playbook at all.

Network devices and appliances. Switches, routers, firewalls — things that will never run an agent but do speak SSH or an API.

Bootstrapping the un-bootstrappable. The bare-metal machine, the appliance, the legacy VM that predates your platform.

Where Ansible is the wrong tool

Being clear about this saves more time than any tutorial.

Provisioning cloud infrastructure. Ansible has modules for it, and you will regret using them. Ansible has no state file and no dependency graph, so it cannot tell you what a change will do before you make it, and it cannot reliably destroy what it built. Use Terraform or OpenTofu to create infrastructure and Ansible to configure what is inside it. This is the Ansible vs Terraform question, and the answer is usually "both, at different layers."

Managing container images. Configuring a running container with Ansible is fighting the container model. Build the configuration into the image.

Continuous reconciliation. Ansible runs when invoked. If you need drift corrected continuously, you want an agent-based tool or a GitOps controller.

Very large fleets, naively. SSH to ten thousand hosts from one control node is slow. It is solvable — forks, pipelining, mitogen, splitting the run — but it is work, and agent-based tools handle that scale more naturally.

Ansible vs the alternatives

AnsiblePuppet / ChefTerraform
Agent requiredNoYesNo
ModelPush, on demandPull, continuousPush, on demand
LanguageYAML + Jinja2Puppet DSL / RubyHCL
Tracks stateNoServer-sideState file
Best atConfiguring and orchestrating existing machinesContinuously enforcing config at scaleCreating and destroying infrastructure
Learning curveLowHighMedium

The low barrier to entry is Ansible's real advantage: a YAML file and an SSH key gets you a working automation, and you can read someone else's playbook without learning a DSL. That accessibility is also its trap — it is easy to write a thousand-line playbook of shell tasks that nobody can safely re-run.

Frequently Asked Questions

Does Ansible need an agent on managed hosts?

No. Managed nodes need an SSH daemon and a Python interpreter, both of which are standard on Linux. Ansible copies the module to the host, runs it, and removes it. Windows hosts are managed over WinRM or SSH instead, and network devices are handled through connection plugins that use their native APIs.

Is Ansible the same as Terraform?

No, and they are not competitors so much as neighbours. Terraform creates and destroys infrastructure and tracks what it built in a state file. Ansible configures machines and services that already exist and tracks nothing. Most teams that use both let Terraform create the servers and Ansible configure them.

What does agentless actually cost me?

Three things: the control node must be able to reach every managed node, runs happen only when triggered rather than continuously, and SSH fan-out is the scaling limit. In exchange you skip agent installation, agent upgrades, and an always-on server — which for most fleets is a good trade.

Are playbooks really idempotent?

The modules are; your playbook is only as idempotent as the modules you choose. ansible.builtin.command and ansible.builtin.shell execute unconditionally and always report a change. Guard them with creates, removes, when, or changed_when, or use a purpose-built module instead.

What is the difference between a role and a collection?

A role is a directory-structured bundle of tasks, templates, files and variables — the unit of reuse within your automation. A collection is a distributable package that can contain roles, modules, and plugins, and it is the unit of distribution, installed with ansible-galaxy. Roles go inside collections; collections are how modules beyond ansible.builtin reach you.

Can Ansible manage Kubernetes?

Yes, through the kubernetes.core collection, which provides modules like kubernetes.core.k8s and kubernetes.core.helm. Whether you should is a separate question — see Ansible for Kubernetes automation for where it fits alongside Helm and GitOps controllers.

See also

Official References

Was this article helpful?

Be the first to rate this article

Related Topics

Ansible
Configuration Management
Automation
DevOps
IaC
Playbooks

Found this useful? Share it.

Practice this

Read Next