Configuration Management & Ansible
A DevOps engineer rarely manages one server — they manage hundreds or thousands, and every one of them needs the same patches, packages, and settings. Doing that by hand, or with fragile per-server scripts, does not scale. This chapter rebuilds Days 14 and 15 into a workshop: first you understand what configuration management is and why Ansible became the tool everyone uses, then you get hands-on installing Ansible and writing your first playbooks and roles, then you get quizzed the way an interviewer would, and finally you face the senior scenarios of running config management on a real fleet.
Configuration management is how a DevOps engineer manages the configuration of many servers at once. Every server needs the same things kept in order — upgrades, security patches, default installations — and once you have hundreds or thousands of them, logging into each one is impossible. Configuration management is the discipline of describing the state you want and having a tool enforce it across the whole fleet. The tool almost everyone uses is Ansible, because it is agentless (nothing to install on the servers you manage), push-based (you run it from one place and it configures everything), and written in plain YAML.
Four ideas carry the chapter: (1) the problem is scale — the same task on thousands of heterogeneous servers; (2) Ansible connects agentlessly over SSH (or WinRM for Windows), so a server just needs to be reachable and set up for passwordless login; (3) you list the servers in an inventory file and describe the work in a playbook written in YAML; and (4) for anything complex you organise the playbook into a role, which is just a tidy folder structure for a big playbook.
- ① Theory — the concepts (Day 14)
- What configuration management is, and why it exists
- The tools, and why Ansible won
- Why Ansible — the four differences (and the trade-offs)
- ② Lab — hands-on with Ansible
- Install Ansible and set up passwordless SSH
- The inventory file, and ad-hoc commands
- Your first playbook
- Roles — structuring a complex playbook
- ③ Interview Q&A — the questions the instructor flags
- ④ Scenario drills — config management on a real fleet (10)
What configuration management is, and why it exists
Configuration management is one of the simpler topics in DevOps, and the clearest way to understand it is to watch the problem it grew out of.
Imagine you are a system administrator, back before DevOps existed as a role, and your company runs its own on-premises data centre with a hundred servers — say fifty on one Linux distribution, twenty-five on CentOS, and twenty-five on Ubuntu. Managing your own servers means constantly doing three kinds of work: applying upgrades (when CentOS moves from version 9 to 10, you have to move with it), applying security patches (just as you update your phone the moment a vulnerability is found), and making default installations (perhaps every server should come with Git or a database already installed, to save the developers time).
Now do those three things across a hundred servers with a team of five. Each person gets twenty servers, and they have to log into every one — over SSH for Linux, or a remote protocol for Windows — and run the commands by hand. The old way to cope was to write scripts: a shell script for Linux, a PowerShell script for Windows. But this was fragile for two reasons. First, you had to write in several languages. Second, and worse, the commands differed by distribution — a script written for Ubuntu might not work on CentOS or Alpine — so a script could work on some servers and silently fail on others.
Then the cloud made it far worse. With the move to the cloud and to microservices, the number of servers went up roughly tenfold while each server got smaller. Where you once had a thousand large servers, you now had ten thousand small ones. The by-hand-and-scripts approach that was already painful became impossible. That pressure created the need for a proper solution — a concept, configuration management, and the tools that implement it. Configuration management aims to solve exactly one thing: managing the configuration of many servers at once, which every organisation of any size now needs.
The tools, and why Ansible won
Configuration management has several well-known tools. Knowing which one to learn — and why — is the practical question.
The popular tools are Puppet, Chef, Ansible, and Salt. Historically, engineers started with Puppet or Chef, which were the first to implement configuration management six or seven years ago. Ansible gained real popularity around 2016 and 2017, and after Red Hat acquired it (around 2018–2019) it has been constantly developed — which is why you often hear it called Red Hat Ansible. Today it is the go-to tool for configuration management.
So the practical advice is simple: if you are confused about where to start, start with Ansible. There is roughly a 90% chance that the organisation you join will be using it. That is not to say nobody uses Puppet, Chef, or Salt — some do — but the majority use Ansible, and it is always better to learn the tool that is most widely used, because that is what gets you into a job. Once you know Ansible well, and if you still have time, you can look at the others.
Why Ansible — the four differences (and the trade-offs)
"When you have Puppet and Ansible, why did you choose Ansible?" is one of the most common interview questions. The answer is four architectural differences, and you should be able to give all four.
- Push versus pull. Puppet uses a pull model; Ansible uses a push model. With Ansible, you write your playbook in one place — your laptop or a control node — and push the configuration out to all your servers by running the playbook. You do not wait for each server to pull the config down for itself.
- Agentless versus master–slave. This is the big one. Puppet follows a master–slave (master–agent) architecture: you install an agent on every server and register it with the master using tokens and certificates before anything works. Ansible is agentless — there is nothing to install on the servers you manage. You simply list their IP addresses (or DNS names) in an inventory file and set up passwordless SSH authentication, and Ansible can configure them. This matters enormously in a dynamic environment where servers are created and torn down constantly: to manage a new server you just add its IP to the inventory. Ansible can even do this automatically with dynamic inventory, where it auto-detects new servers (for example, any new EC2 instance in a given region) and manages them without you editing the file at all.
- Good support for both Windows and Linux. Ansible has strong modules for both operating systems, and especially after Red Hat's involvement its Windows support improved a lot — which is often trickier with Puppet or Chef. Its Linux support is excellent.
- Simple YAML instead of a custom language. Puppet makes you learn its own Puppet language. Ansible playbooks are written in plain YAML — a format engineers already know from Kubernetes and elsewhere — so there is no new language to learn.
Install Ansible and set up passwordless SSH
You need two servers: a control node (where Ansible runs) and at least one target to configure. Create two Ubuntu EC2 instances, and on the control node install Ansible with the package manager — it is the easiest route, and it adds Ansible to your path automatically:
bashsudo apt update
sudo apt install -y ansible # on Mac: brew install ansible · on Windows: choco install ansible
ansible --version # verify it installed (under the hood it uses Python + pip)
The one prerequisite Ansible has is passwordless SSH: the control node must be able to connect to the targets without a password. Set that up by generating a key pair on the control node and copying its public key into the target's authorized keys. The private key never leaves the control node and is never shared:
bash# on the CONTROL node
ssh-keygen # creates ~/.ssh/id_rsa (private) and id_rsa.pub (public)
cat ~/.ssh/id_rsa.pub # copy this public key
# on the TARGET server, paste the control node's public key into:
~/.ssh/authorized_keys # (ssh-copy-id <target-ip> does this in one step, when it has permission)
# back on the control node — now this connects with no password:
ssh <target-private-ip>
Once ssh <target> connects without asking for a password, the prerequisite is met — for that server and any others you add the public key to. Use the private IP when the servers are in the same VPC. In one line: passwordless SSH is just the control node's public key sitting in the target's authorized_keys.
The inventory file, and ad-hoc commands
The inventory file is where you list the servers Ansible manages. Ansible's default is /etc/ansible/hosts, but it is more convenient to keep your own file next to your playbooks and point Ansible at it. You can also group servers with bracket headers and target a group by name:
text# inventory
172.31.6.228
[webservers]
172.31.62.100
[dbservers]
172.31.62.200
You do not always need a playbook. For a one-off task — "create a file on a hundred servers" — an ad-hoc command is simpler, exactly as you would run a single shell command rather than write a whole script. The form is ansible -i <inventory> <hosts> -m <module> -a "<args>", where -m is the module and -a is its arguments:
bashansible -i inventory all -m shell -a "touch devops-class" # run on every host in the inventory
ansible -i inventory webservers -m shell -a "nproc" # run only on the webservers group
ansible -i inventory all -m copy -a "src=./x dest=/tmp/x" # modules other than shell, e.g. copy
A yellow line means something changed and all is well; a red line means an error. Which module to use, and its arguments, you look up in the Ansible module documentation — there are thousands of modules and nobody memorises them all. The rule of thumb, and a common interview question, is: use an ad-hoc command for one or two tasks, and write a playbook when you have many.
Your first playbook
A playbook is just an Ansible file — the equivalent of a shell script — written in YAML, used when you want to run several tasks. Here is one that installs and starts nginx:
apt or service.yaml---
- name: install and start nginx
hosts: all # every server in the inventory
become: true # run as root, like sudo (package installs need it)
tasks:
- name: install nginx
apt: # the apt module — equivalent to "shell: apt install nginx", but sturdier
name: nginx
state: present # present = installed
- name: start nginx
service: # the service module
name: nginx
state: started
Run it with ansible-playbook (the ansible command runs ad-hoc commands; ansible-playbook runs playbook files):
bashansible-playbook -i inventory first-playbook.yaml
# the first task is always "Gathering Facts" — Ansible checks the auth and collects info about the target
ansible-playbook -i inventory first-playbook.yaml -vvv # add -v / -vvv for verbose debug output
Every playbook begins with a Gathering Facts step, where Ansible confirms it can authenticate and collects details about the target, before running your tasks. Two habits worth forming: prefer a purpose-built module (apt, service) over a raw shell command, because the module is more robust if the underlying command changes; and use -vvv when you want to see, step by step, exactly what Ansible is doing on the target — how it establishes the SSH connection, what it gathers, and the result of each task.
Roles — structuring a complex playbook
A two-task playbook fits in one file. A real one does not — and that is what roles are for.
Consider a realistic task: configure a Kubernetes cluster with Ansible, setting one server up as the master and two as workers. (In practice you would create the servers with Terraform — the right tool for provisioning infrastructure — and then configure them with Ansible.) A playbook like that has fifty or sixty tasks, plus variables, certificates, and secrets. Put all of that in one playbook.yaml and it becomes impossible to read. The answer is an Ansible role: an efficient, structured way to write a complex playbook. You create one with ansible-galaxy:
bashansible-galaxy role init kubernetes # scaffolds a folder of standard directories
That scaffolds a tidy folder structure. Instead of one giant file, each concern lives in its own directory, and a small parent playbook simply names the hosts and points to the role:
- tasks/ — the actual steps (what used to be the
tasks:block in your single playbook). - handlers/ — actions triggered by a change, and a place to handle problems (for example, if nginx fails to start, notify someone or roll the change back).
- templates/ — Jinja2 templates for config files that need values filled in.
- files/ — static files to copy to the targets, such as an
index.htmlor a certificate. - vars/ and defaults/ — variables, where
defaults/holds the lowest-precedence values that can be overridden. - meta/ — metadata and licensing, used when you share the role via Ansible Galaxy; and tests/ plus a README.
The pattern to remember for interviews: you write simple things directly in a playbook, and when a playbook grows complex — many tasks, variables, certificates, secrets — you turn it into a role so it stays structured and readable, and can be shared through Ansible Galaxy.
Q1What is configuration management, and why is it needed?reveal ▸
Configuration management is how a DevOps engineer manages the configuration of many servers at once — the upgrades, security patches, and default installations that every server needs. It exists because doing that by hand, or with per-server scripts, does not scale: an organisation has hundreds or thousands of servers, often on different operating systems, and the cloud and microservices pushed those numbers up roughly tenfold. Configuration management lets you describe the desired state once and enforce it across the whole fleet.
Q2Why did you choose Ansible over Puppet or Chef?reveal ▸
Four reasons. It is push-based — I run a playbook from one control node and it configures everything, rather than each server pulling config down. It is agentless — nothing to install on the managed servers, unlike Puppet's master–slave model with agents, tokens, and certificates; I just list IPs in an inventory and set up passwordless SSH. It has strong support for both Windows and Linux. And playbooks are plain YAML, so there is no custom language to learn as there is with Puppet. It is also the tool roughly 90% of organisations use.
Q3Is Ansible push or pull?reveal ▸
Ansible is push. You write the playbook on a control node and push the configuration out to all the target servers when you run it. Puppet, by contrast, is pull — the agents pull their configuration down from the master.
Q4What does "agentless" mean, and how does Ansible connect to the servers?reveal ▸
Agentless means there is nothing to install on the servers you manage — no agent, no registration, no certificates. Ansible connects over SSH (or WinRM for Windows), so a target just needs to be reachable and set up for passwordless login. You list the targets in an inventory file, and Ansible pushes the configuration to them. This is a big advantage in a dynamic environment, because to manage a new server you only have to add its IP to the inventory.
Q5Does Ansible support Windows and Linux? What protocols does it use?reveal ▸
It supports both. For Linux it connects over SSH, and for Windows it connects over WinRM. Its Linux support is excellent, and its Windows support is good — and improved a lot after Red Hat's involvement — though Windows configuration is still not quite as smooth as Linux.
Q6Does Ansible support all the cloud providers — AWS, Azure, GCP?reveal ▸
This can sound like a trick, but the answer is simple: Ansible does not care which cloud the server is on. All it needs is that the machine is reachable and that SSH is allowed from the Ansible control node (or WinRM for Windows). So it works the same on AWS, Azure, GCP, or anywhere else — the cloud provider is irrelevant, reachability and SSH access are all that matter.
Q7What language are playbooks written in, and what is Ansible itself written in?reveal ▸
Playbooks are written in YAML — the same format used across Kubernetes and much of DevOps, which is one of Ansible's advantages. Ansible itself is written in Python, which is why you can write your own custom modules in Python and contribute them back. If asked whether you have written custom modules, be honest — you can say you are comfortable enough with Python to write one whenever it is needed.
Q8What is the difference between an ad-hoc command and a playbook?reveal ▸
An ad-hoc command is for one or two quick tasks — like running a single shell command instead of writing a script — using the form ansible -i inventory all -m module -a "args". A playbook is for running many tasks together, written as a YAML file and run with ansible-playbook. So the rule is: ad-hoc for one or two tasks, a playbook when there are several.
Q9What is the inventory file, and how do you run tasks on only some servers?reveal ▸
The inventory file is where all the server names and details are configured — by default at /etc/ansible/hosts, though you usually keep your own file next to your playbooks. To target only some servers, you group them in the inventory with bracket headers, such as [webservers] and [dbservers], and then run against a group by name instead of all. Ansible looks up the group and runs the tasks only on those hosts.
Q10What is dynamic inventory?reveal ▸
Normally you edit the inventory file to add servers. Dynamic inventory removes even that step: with some configuration, Ansible auto-detects servers — for example, any new EC2 instance created in a given region or availability zone — and manages them automatically, without you touching the file. It is what makes Ansible practical for an autoscaling fleet where servers come and go constantly.
Q11What does become do in a playbook?reveal ▸
become: true runs the tasks as the root user — the equivalent of putting sudo in front of a command. You need it for anything that requires elevated privileges, such as installing packages with the package manager. You can also use become_user to run as a specific user rather than root.
Q12What is "Gathering Facts"?reveal ▸
Gathering Facts is the first step of every playbook run. Before your tasks execute, Ansible connects to each target, confirms it can authenticate without a password, and collects details about the server — the operating system, the interfaces, and so on — which your tasks can then use. It runs automatically no matter what playbook you write.
Q13What are Ansible roles, and why use them?reveal ▸
A role is a structured, efficient way to write a complex playbook. A simple two-task playbook fits in one file, but configuring something like a Kubernetes cluster has fifty or sixty tasks plus variables, certificates, and secrets — which is unreadable in a single file. A role (scaffolded with ansible-galaxy role init) splits all of that into standard directories, so the playbook stays organised and can be shared. The parent playbook then just names the hosts and applies the role.
Q14Explain the directories inside a role.reveal ▸
tasks/ holds the actual steps; handlers/ holds actions triggered by a change and is where you handle problems; templates/ holds Jinja2 templates for config files; files/ holds static files to copy to the targets; vars/ and defaults/ hold variables (defaults being the lower-precedence, overridable ones); meta/ holds metadata and licensing for sharing via Galaxy; and there is a tests/ directory and a README.
Q15What are handlers?reveal ▸
Handlers are actions that run in response to a change — a task "notifies" a handler, and the handler runs only if something actually changed. They are also where you handle situations: for example, if a service fails to start, a handler could send a notification or undo the change, so you are not left with a half-configured server. In a role, handlers live in the handlers/ directory.
Q16What are the disadvantages of Ansible?reveal ▸
Three honest ones. Windows configuration is still not as smooth as Linux. Its debugging is weak — the logs are not always easy to read, even in verbose mode, so tracking down why a playbook failed can be hard. And it can hit performance limits when running in parallel across very large fleets. Being able to name real weaknesses like these makes your answer sound like genuine experience.