unit 1 · Orientation
What Ansible is & isn't
Declarative desired state, not a script runner
tl;dr
- Ansible is declarative: you state the end state, modules work out the how — Bicep thinking, not PowerShell.
- Push-based and agentless, with no state file — "changed" is computed fresh against the real machine each run.
- Bare shell tasks drag it back to scripting. Reach for a purpose-built module first.
why it matters Treat Ansible like a script runner and every rerun reports changes, reviewers bounce your shell tasks, and you fight the tool instead of describing what prod should look like.
The top beginner mistake, and the one your background makes most tempting: treating Ansible as a scripting language. It isn’t. A playbook looks like a script: YAML tasks, read top to bottom. But each task is a declarative statement of an end state, not an instruction to execute. You say what the machine should look like. The module behind the task works out how to get there, and whether anything needs doing at all.
Two mindsets, same job:
- name: MOTD file is in place
ansible.builtin.copy: # a module: this file, with this content, exists
src: files/motd # what the file must contain
dest: /etc/motd # where it must liveThe copy module inspects what’s actually on the host first. Matches? It
reports ok and touches nothing. Differs? It fixes it and reports changed.
Run it once or fifty times and you converge on the same machine. That makes
the task idempotent , and modules give it to you for free.
(Those dotted module names are FQCNs — lesson 4 explains them; copy the
style for now.)
Now the scripting reflex:
- name: Write the MOTD
ansible.builtin.shell: echo "Welcome" > /etc/motdIt works. But a shell task always executes and always reports changed,
because Ansible can’t see inside your command to know whether the host
moved. Chain a dozen together and you’ve written a PowerShell script with
worse ergonomics.
What will surprise a Terraform and Bicep brain
Three things about this model won’t match your instincts:
- There is no state file. Unlike Terraform, Ansible stores nothing between
runs. Every run inspects the actual machines and computes
changedfresh — the real system is the state. - Ordering is top-down and looks imperative. Tasks run in the order you wrote them — no dependency graph like Bicep’s. The tasks are declarative; the sequence is yours to control.
- Facts are gathered fresh each run unless you cache them: Ansible re-asks every host what it is before doing anything. Lesson 17 covers facts.
If you know DSC, one more calibration: DSC is Windows desired state through an agent (the Local Configuration Manager). Ansible is agentless, cross-platform, and can even drive DSC when it needs to.
The one-line definition: agentless, push-based, declarative automation.
One habit makes it stick: before you type shell:, ask what end state you’re
describing — there’s almost always a module for it.
at work, this sounds like
- “It's not idempotent.”
- Re-running the playbook keeps making changes (or reporting them) when nothing should change — usually a raw shell task.
self-check — recall, not a test
1 A colleague calls Ansible "a nicer way to run scripts". What is wrong with that?
2 Your playbook reports "changed" on every run even though nothing differs. Likely culprit?
3 Coming from Terraform: where does Ansible keep its state file?