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.
- The execution model
- The vocabulary
- Idempotence, and what it actually means
- What Ansible is good at
- Where Ansible is the wrong 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:
- Reads your inventory to work out which hosts the task applies to
- Generates a small self-contained program — the module with its arguments baked in
- Copies it to the target over SSH into a temporary directory
- Executes it
- Captures the JSON the module prints to stdout
- Deletes the temporary directory
- 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.
| Term | What it is |
|---|---|
| Control node | The machine you run Ansible from |
| Managed node | A machine Ansible configures. Needs no agent |
| Inventory | The list of managed nodes, organised into groups |
| Module | A unit of work — install a package, copy a file, restart a service |
| Task | One invocation of a module, with arguments |
| Play | A set of tasks mapped to a group of hosts |
| Playbook | A YAML file containing one or more plays |
| Role | A reusable, directory-structured bundle of tasks, files, templates and variables |
| Collection | A distributable package of roles, modules and plugins |
| Handler | A task that runs only when notified by another task that changed something |
Inventory
The inventory names your hosts and groups them. In YAML:
1webservers:
2 hosts:
3 web1.example.com:
4 web2.example.com:
5databases:
6 hosts:
7 db1.example.com:
8 ansible_user: postgresGroups 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
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: restartedRead 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.builtin — apt, 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
| Ansible | Puppet / Chef | Terraform | |
|---|---|---|---|
| Agent required | No | Yes | No |
| Model | Push, on demand | Pull, continuous | Push, on demand |
| Language | YAML + Jinja2 | Puppet DSL / Ruby | HCL |
| Tracks state | No | Server-side | State file |
| Best at | Configuring and orchestrating existing machines | Continuously enforcing config at scale | Creating and destroying infrastructure |
| Learning curve | Low | High | Medium |
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
- What Is Infrastructure as Code? — the wider category Ansible sits in
- Ansible vs Terraform — provisioning versus configuration, and using both
- Ansible for Kubernetes Automation — the
kubernetes.corecollection in practice - What Is GitOps? — the continuous-reconciliation model Ansible does not have
Official References
- Ansible playbook guide — tasks, handlers, roles and execution order
- Terraform documentation — configuration language, state and provider behaviour
- Terraform state — remote backends, locking and drift
Was this article helpful?
Be the first to rate this article
Related Topics
Found this useful? Share it.


