Configuration management with Ansible
Converge existing hosts to a declared configuration, idempotently, and use check mode to see drift before you fix it.
Configuring what already exists
Provisioning tools create infrastructure. Configuration management keeps the software and settings on existing hosts in a declared state: packages, files, users, and services. Ansible's model, which Ansible for DevOps builds up chapter by chapter:
- An inventory lists hosts and groups (
[renderers],[depot_proxies]) with variables. - A playbook maps groups to tasks.
- Each task calls a module with arguments describing the desired state:
package: name=label-renderer state=present. - Handlers react to changes, for example "restart renderer if its config changed".
- Roles package related tasks, templates, handlers, and defaults for reuse.
Ansible connects over SSH and needs no agent. That makes it easy to start with and easy to run from a pipeline.
Idempotence is a property of tasks
Ansible is only as idempotent as its tasks. State-describing modules check before they act. package installs only if absent, template writes only if content differs, and service: state=started starts only if stopped. Each reports ok or changed. Raw command and shell tasks run every time and report changed every time, unless you add creates:, removes:, or changed_when: to describe their effect.
A healthy playbook run on a converged host reports zero changed. As with Terraform's empty second plan, that is a test. A playbook that always reports changes hides the one change that matters among the noise.
- name: Renderer configuration
template:
src: renderer.conf.j2
dest: /etc/renderer/renderer.conf
mode: "0640"
notify: restart renderer
handlers:
- name: restart renderer
service:
name: renderer
state: restarted
The service restarts only when the file actually changed, and only once per run.
Seeing drift before fixing it
ansible-playbook site.yml --check --diff --limit renderers reports, per host, what would change, without changing it. Against a fleet that should be identical, check mode works as a drift report. The odd node shows a pending package change or config diff. This matches the Linux Administration track's notes on drift. The difference is that the remedy is now a reviewed line of code applied to every host, not a hand fix on one.
Pin what you depend on
state: latest means "whatever the repository has right now". Hosts configured on different days end up with different versions, which is drift created by the tool itself. Pin versions in variables, change them through pull requests, and let the playbook converge everyone to the same release. Unpinned latest is reasonable only for packages where any version is acceptable.
Roll out in batches
A configuration change applied to every host at once has the same blast radius as a big-bang deploy. serial applies a play to hosts in batches (one host, then 25%, and so on), and max_fail_percentage stops the run when a batch fails. Add a verification task at the end of each batch, such as an HTTP check of the service, and you have a canary for configuration. It is the same idea as the “Releasing safely” notes, applied to hosts.
Where Ansible fits
The administrator's handbook and Brikman agree that tools overlap and teams combine them. A common split: Terraform or OpenTofu provisions networks and machines, images are built immutably where possible, and Ansible handles what still has to be configured in place. Whatever the split, the principles stay the same: declare the state, review the change, preview it, apply it gradually, and verify it.
Key terms
- Inventory
- The list of managed hosts and groups, static or generated, with per-host and per-group variables.
- Module
- A unit of work Ansible runs on a host. Good modules check current state and change only what differs.
- Handler
- A task run only when notified by a changed task, for example restarting a service after its config template changes.
- Check mode
--checkruns a playbook without changing anything and reports what would change. With--diffit also shows the differences.
Read further
- Ansible for DevOps, Chapters "Ansible Playbooks" and "Inventories" (Purchase)
Playbook structure, handlers, variables, and how inventories group hosts. Note the difference between modules that declare state (package,template,service) and rawcommandorshelltasks. - Ansible for DevOps, Chapter "Playbook Organization — Roles, Includes, and Imports" (Purchase)
How roles package tasks, handlers, templates, and defaults for reuse, and when to use static imports versus dynamic includes. - UNIX and Linux System Administration Handbook, 5th edition, Ch. 23, "Configuration Management" (Purchase)
The Ansible section and the comparison with Salt and other tools. Note the handbook's points on idempotence and on choosing push versus pull.