Lesson 1 of 9 · 20m
The Agentless Model: SSH, Python, and No Daemons
Why Ansible pushes Python over SSH instead of running agents, what that buys you operationally, and the failure modes it quietly avoids — plus the ones it doesn't.
In 2013 I inherited a fleet managed by an agent-based config tool. The agents crashed, the agent versions drifted from the server version, and half my "fleet is converged" reports were stale because nodes hadn't checked in. Then someone showed me Ansible: ssh in, run a thing, leave nothing behind. It felt like cheating. It mostly isn't — but you need to understand the mechanism to know where it bends.
What's actually on the wire
When you run a task, Ansible does this on the control node:
- Reads the inventory to resolve hostnames, groups, and variables.
- Opens an SSH connection (control node → managed node) as your user.
- Ships a small self-contained Python program (the module) across the wire — usually via
sftp/scpinto~/.ansible/tmp/, or piped through stdin whenpipelining = True. - Executes it (often wrapped in
sudo/become), collects JSON output, deletes the temp file.
Nothing persists on the managed node. No daemon to patch, no certificate infrastructure beyond the SSH keys you already have, no "agent didn't check in" ambiguity — if SSH works, Ansible works.
The trade you're making
Push over SSH has real costs: every task is a connection (mitigated by persistent connections and pipelining), and orchestrating 5,000 hosts is bounded by your control node's forks, not by agents running in parallel. Pull-mode exists (ansible-pull from a git checkout) for hosts that can't be reached inbound — autoscaled instances, laptops.
Your first contact
# ping isn't ICMP — it exercises SSH + Python on the target
ansible all -i inventory.ini -m ping
ansible webservers -i inventory.ini -a "uptime" # ad-hoc command
ansible db01 -i inventory.ini -m setup | head -40 # dump gathered factsRequirements on the managed node: Python 3 (Ansible ships pure-Python modules) and SSH. Windows targets use WinRM (ansible_connection=winrm), network gear uses network_cli/netconf — same mental model, different transport.
Become: the privilege story
# ansible.cfg
[privilege_escalation]
become = True
become_method = sudo
become_ask_pass = Falsebecome on a task, play, or config is Ansible's sudo. It isn't optional plumbing — declaring privilege per-task is what lets you run audits as an unprivileged user and escalate only where needed.
Field notes
-m pingreturningpongmeans SSH and a usable Python interpreter — it's the first thing to check on a new host image.ansible_ssh_private_key_file,ansible_user,ansible_portare inventory vars, not CLI flags — put connection metadata where the host lives.- Agentless doesn't mean stateless for you: Ansible knows nothing about what ran last week. Drift detection is your
git logplus check-mode runs, not a central server.