Skip to main content
Infrastructure as Code·7 min read

Ansible Architecture — The Agentless Push Model Explained

How Ansible actually works: the agentless push model over SSH, control node vs managed nodes, inventory, modules, playbooks, idempotency, and how a playbook run flows from gathering facts to reporting results.

DT

DevOps Engineer & Technical Writer

The Problem

Teams reach for configuration management and immediately hit a wall: do you install an agent on every server, run a central master, open extra ports, and keep all of it patched? Agent-based tools like the classic Puppet and Chef setups ask for exactly that. Ansible takes a different path — nothing runs permanently on the servers it manages. Understanding why that works makes everything else about Ansible click into place.

ANSIBLE AGENTLESS PUSH MODEL — CONTROL NODE PUSHES OVER SSH inventory which hosts + groups playbook desired state (YAML) CONTROL NODE ansible-playbook pushes modules over SSH SSH :22 web01 no agent installed web02 no agent installed db01 no agent installed MANAGED NODES Python + SSH is all a managed node needs — modules are copied in, run, then removed

The whole model is one sentence: a control node pushes small programs (modules) to managed nodes over SSH, runs them, collects the results, and cleans up. There is no daemon to install, no port to open beyond SSH, and nothing left running afterward.

Control Node vs Managed Nodes

Ansible has exactly two roles in its topology:

  • Control node — the machine where Ansible is installed and where you run ansible-playbook. It needs Python and Ansible. This can be your laptop, a bastion host, or a CI runner.
  • Managed nodes — the servers you configure. They need an SSH daemon and a Python interpreter. That is it. They never have Ansible installed.

Because the managed nodes carry no agent, onboarding a new server is just "make sure SSH works." There is no bootstrap problem, no agent version to keep in sync, and no extra attack surface.

The Core Building Blocks

ConceptWhat it is
<strong>Inventory</strong>A list of managed hosts, organized into groups (e.g. <code class="inline-code">web</code>, <code class="inline-code">db</code>).
<strong>Module</strong>A small, purpose-built unit of work (<code class="inline-code">apt</code>, <code class="inline-code">copy</code>, <code class="inline-code">service</code>). The actual code pushed to a node.
<strong>Task</strong>A single call to a module with arguments.
<strong>Play</strong>A mapping of a group of hosts to an ordered list of tasks.
<strong>Playbook</strong>A YAML file containing one or more plays.
<strong>Facts</strong>System details (OS, IP, memory) Ansible gathers from each node before running tasks.

A Minimal Inventory

Inventory can be a simple INI file. Hosts are grouped so a play can target web or db instead of individual machines.

[web]

web01.example.com

web02.example.com

[db]

db01.example.com

[all:vars]

ansible_user=deploy

A Minimal Playbook

A playbook declares the desired state. You describe what should be true, not the step-by-step commands to get there.

---
  • name: Configure web servers
hosts: web

become: true

tasks:

- name: Ensure nginx is installed

ansible.builtin.apt:

name: nginx

state: present

update_cache: true

- name: Ensure nginx is running and enabled

ansible.builtin.service:

name: nginx

state: started

enabled: true

Run it with:

ansible-playbook -i inventory.ini site.yml

How a Playbook Run Actually Flows

When you run that command, Ansible does the following for each targeted host, in parallel across hosts:

  • Connect — opens an SSH connection to the managed node.
  • Gather facts — runs the setup module to collect system facts (unless disabled with gather_facts: false).
  • Execute tasks — for each task, Ansible copies the relevant module to a temp directory on the node, runs it with the task's arguments, captures the JSON result, then deletes the temp files.
  • Report — streams back ok, changed, failed, or skipped for every task, ending with a per-host recap.
  • The key detail: modules run on the managed node, but they are transient. Nothing persists between runs. That transience is what makes the agentless model possible.

    Idempotency: The Property That Makes It Safe

    A well-written Ansible task is idempotent — running it once or a hundred times converges on the same result. The second task above says "nginx should be running." If it already is, Ansible reports ok and changes nothing. If it is not, Ansible starts it and reports changed.

    This is why you can safely re-run a playbook any time. Ansible checks current state before acting, so re-runs are cheap and non-destructive. Idempotency comes from the modules, not from magic — which is why ansible.builtin.service is idempotent but a raw command: systemctl start nginx is not.

    Agentless vs Agent-Based: The Trade-offs

    DimensionAgentless (Ansible)Agent-based (classic pull model)
    Setup on nodesSSH + Python onlyInstall + maintain an agent
    Trigger modelPush, on demandPull, on a schedule
    Extra portsNone beyond SSHAgent-to-master port
    Drift correctionOnly when you run itContinuous, on each pull interval
    Scale ceilingSSH fan-out (mitigated by forks/pull)Master handles many agents natively

    Agentless wins on simplicity and security surface. Agent-based wins on continuous enforcement — it keeps correcting drift without anyone kicking off a run. Many teams pick Ansible precisely because the simplicity outweighs the lack of a constant background loop, and they schedule runs through CI instead.

    Common Mistakes to Avoid

    • Using command or shell for everything. Raw commands are not idempotent and defeat the point of Ansible. Reach for a real module (apt, copy, service) first.
    • Forgetting become: true. Tasks that need root silently fail or error without privilege escalation.
    • Disabling fact gathering, then using facts. If a task references ansible_facts but you set gather_facts: false, it will fail.
    • Treating the control node as special infrastructure. It holds no state between runs; any machine with SSH access and Ansible installed can be a control node.
    • Assuming push means continuous. Ansible only enforces state when you run it. If you need continuous drift correction, schedule the runs.

    FAQ

    Does Ansible need an agent on managed nodes?

    No. Managed nodes only need an SSH server and a Python interpreter, both of which ship on most Linux distributions. Ansible copies modules over SSH, runs them, and removes them, so nothing is permanently installed.

    What is the difference between a play and a playbook?

    A play maps one group of hosts to an ordered list of tasks. A playbook is a YAML file that contains one or more plays, letting you configure different host groups in different ways within a single run.

    Why does idempotency matter?

    Idempotency means re-running a playbook does not cause harm or unintended changes — tasks only act when the system is not already in the desired state. This lets you run the same playbook repeatedly and safely, which is essential for reliable automation.

    Is push or pull better?

    Neither is universally better. Push (Ansible's default) is simpler and runs on demand with no agents. Pull (agent-based tools) enforces state continuously on a schedule. Teams that value simplicity and a smaller attack surface tend to prefer push and trigger runs through CI.