Configuration management and immutable infrastructure
Configure servers repeatably with Ansible’s idempotent tasks and inventories - and learn when to replace servers instead of changing them.
- Distinguish provisioning infrastructure from configuring what runs on it
- Write idempotent Ansible tasks and organize hosts and variables in an inventory
- Compare mutable and immutable infrastructure (“pets versus cattle”)
Terraform created Byte Bakery’s servers. But what’s on them - packages, config files, users, services - still drifted: web1 has nginx 1.24, web2 has 1.18, and nobody remembers why web3 has a cron job that emails the CEO pastry statistics.
Configuration management tools - Ansible, Chef, Puppet, Salt - describe the desired configuration of machines and enforce it. Ansible is popular for being simple: it’s agentless (it connects over SSH), and you write YAML playbooks of tasks, each calling a module that declares a desired state - “package nginx is present”, “this file has this content”, “service nginx is started”.
Modules are idempotent: each task checks the current state first and only acts if needed, reporting ok (already right) or changed. Run a playbook twice and the second run should change nothing.
1[web]
2web1 ansible_host=10.0.1.11
3web2 ansible_host=10.0.1.12 http_port=8080
4
5[ovens]
6oven-controller ansible_host=10.0.2.20
7
8[web:vars]
9http_port=80
10max_clients=2001- name: Configure Byte Bakery web servers
2 hosts: web
3 become: true
4 tasks:
5 - name: Install nginx
6 ansible.builtin.apt:
7 name: nginx
8 state: present
9
10 - name: Write the site config
11 ansible.builtin.template:
12 src: bakery.conf.j2
13 dest: /etc/nginx/conf.d/bakery.conf
14 notify: Reload nginx # only runs if this task changed something
15
16 - name: Keep nginx running
17 ansible.builtin.service:
18 name: nginx
19 state: started
20 enabled: true
21
22 handlers:
23 - name: Reload nginx
24 ansible.builtin.service:
25 name: nginx
26 state: reloadedPets versus cattle
Configuration management keeps mutable servers in line: long-lived machines that are updated in place. They’re pets - named, nursed back to health when sick.
Immutable infrastructure treats servers as cattle: you never change a running server. To update, you build a new machine image (with Packer, say) or container image, launch new instances from it, and throw the old ones away. There’s no drift to manage, because nothing changes after launch, and every server is identical. Containers and autoscaling groups push most teams this way; configuration management still shines for building those images and for machines you can’t easily replace.
Key takeaways
Provisioning creates infrastructure; configuration management sets up what runs on it.
Ansible is agentless; playbooks of idempotent module tasks report ok or changed.
Inventories group hosts and hold variables, with host variables overriding group ones.
Immutable infrastructure replaces servers instead of changing them - no drift, identical machines.
Lesson quiz
7 questions · pass with 5 correct · up to 50 XP
Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.
Practice: automate DevOps chores in Python
Write the small Python tools DevOps teams really build - pipeline runners, plan checkers, metric calculators, scanners - and run them against sample inputs. They run locally in your browser; no servers or cloud accounts needed.
Run a playbook twice
The input is a host’s current facts, ---, then tasks. Facts: package NAME VERSION, file PATH HASH, service NAME running|stopped. Tasks: package NAME present|absent, file PATH HASH, service NAME running|stopped.
Run the playbook twice against the same host. Each task reports ok if the host already matches, otherwise changed and updates the facts (a newly installed package gets version latest; a missing service counts as stopped). Print run 1:, the tasks as changed: package nginx present, and recap: ok=1 changed=3, then the same for run 2.
- Fresh web server
- New service
Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.
Resolve inventory variables
The input is an inventory, ---, then host names to look up. The inventory has group sections [web] listing hosts (web2 http_port=8080 - host variables after the name) and variable sections [web:vars] or [all:vars] with key=value lines. A host may be in several groups.
Effective variables, lowest to highest precedence: all:vars, then the vars of each group the host belongs to in the order the groups first appear in the file, then the host’s own variables. Print web2: http_port=8080 (host), max_clients=200 (web), ntp_server=time.example.com (all) with keys alphabetically, or ghost: unknown host.
- Byte Bakery inventory
Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.
Questions about this lesson
Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.
Loading posts…