Angga.
← Back to all posts
devopsansibleinfrastructure

Ansible in one page

Agentless config management explained — the mental model, the execution flow, and the commands you'll actually use.

· 6 min read

Most config-management tools require you to install something on every server you manage. Ansible does not. Here is the whole tool in one page.

The one-paragraph version

Ansible is agentless — there's no daemon on the target servers. From your laptop, you run a command. Ansible SSHes into each target, copies small Python scripts called modules, runs them, deletes them, and shows you what changed. That's it. The "configuration" lives in YAML files on your machine that describe the desired end state, and the modules are smart enough to skip work that's already done (idempotent).

What happens when you run a command

Every Ansible run follows the same flow:

  • You type ansible-playbook site.yml on your laptop.
  • Ansible reads the inventory to find target hosts.
  • For each host, open an SSH connection.
  • Copy a small Python module (e.g. apt, copy, service) into a temp directory on the target.
  • Run the module with arguments pulled from your YAML.
  • The module reports back ok or changed.
  • Delete the module. Close the connection.

No background process is left behind. The only software the target needs is SSH and Python — both already present on every Linux server you'd care about.

Why "idempotent" matters

Running the same playbook twice should leave the system in the exact same state as running it once. That property — called idempotency — is what makes Ansible safe to run on a Friday afternoon.

If a module would be a no-op, it skips. If a config file already matches the desired content, it does not rewrite it. The output tells you exactly what changed:

PLAY RECAP
public_ec2 : ok=12 changed=0 unreachable=0 failed=0

Zero changed means: the system already looks how the playbook describes it.

Anatomy: inventory + playbook

Two kinds of YAML do most of the work.

Inventorywho to talk to. Lives in inventories/<env>/hosts:

[public]
public_ec2 ansible_host=54.12.34.56

[private]
db1 ansible_host=10.0.1.10
db2 ansible_host=10.0.1.11

Playbookwhat to do. Lives in playbooks/<name>.yml:

- hosts: public
  become: yes
  tasks:
    - name: Install nginx
      apt:
        name: nginx
        state: present
    - name: Start nginx
      service:
        name: nginx
        state: started
        enabled: yes

The playbook says "I want nginx installed and running." Ansible figures out the verbs.

The commands you'll actually use

Memorize five. Look up the rest when you need them.

Sanity check first

ansible all -m ping

Verifies SSH works and Python is reachable on every host. Changes nothing. Always run this when you add a new host or rotate SSH keys.

Dry run before real apply

ansible-playbook playbooks/site.yml --check

Reports what would change without making any changes. The seatbelt before any real run.

Real apply

ansible-playbook playbooks/site.yml

Full configuration across the entire inventory. The default, most common command.

Scope by group or single host

ansible-playbook playbooks/public.yml
ansible-playbook playbooks/private.yml
ansible-playbook playbooks/site.yml --limit public_ec2

Groups (public, private) come from the inventory. --limit narrows further to a single host or pattern. Useful when only one tier needs changes — or when you're rolling out cautiously, one box at a time.

Scope by tag

ansible-playbook playbooks/public.yml --tags build

Each task in a playbook can carry tags. Use this when you only want to "rebuild the binary" and skip everything else (installing system packages, restarting services, etc.).

Debug what Ansible sees for a host

ansible public_ec2 -m debug -a "var=hostvars[inventory_hostname]"

When a task does the wrong thing, the cause is usually a variable you didn't expect. This dumps every variable Ansible knows about the host — facts, group_vars, host_vars, the lot.

Ad-hoc commands, no playbook needed

ansible all -m shell -a "uptime"
ansible private -m shell -a "systemctl status postgresql" --become

For one-off ops: status checks, quick diagnostics. -m shell runs a shell command; --become runs it as root via sudo. Think of this as "ssh-for-loop with structure."

Encrypted secrets

ansible-vault edit inventories/staging/group_vars/private.yml

Vault encrypts variable files at rest. The unencrypted content only exists in memory while the play runs — plaintext credentials never sit on disk or in git.

Collection dependencies

ansible-galaxy collection install -r requirements.yml

Run this once after cloning the repo, or whenever requirements.yml changes. Collections are how external modules ship — AWS, GCP, Kubernetes, community plugins, etc.

When to reach for Ansible

Reach for it when:

  • You manage more than three servers by hand.
  • You want infra changes to live next to code in git.
  • You don't want to install an agent on every box.

Skip it when:

  • You only manage one laptop — way too much machinery.
  • You need real-time state convergence. Ansible runs when you run it, not on a schedule. Puppet or Chef fit that better.
  • You're already all-in on Kubernetes — Helm charts and operators cover the same ground for the container side.

Closing

Ansible's value is that it's boring. SSH, Python, YAML. Nothing wakes you up at 2am because the agent died on a node — because there is no agent. If you've avoided it because the YAML feels verbose, the trade is fair: explicit YAML now, no surprises later.

Enjoyed this? More posts coming weekly — see the full archive.