Configuration Management
Checking access...
Infrastructure Provisioning vs Configuration Management
Provisioning tools (Terraform, CloudFormation) create and manage the infrastructure — VPCs, servers, databases, load balancers. Configuration management tools handle what runs on those servers — packages, services, files, users.
| Tool | Provisions | Configures |
|---|---|---|
| Terraform | ✅ VMs, networks, databases | ❌ (limited provisioner support) |
| CloudFormation | ✅ AWS resources | ❌ |
| Ansible | ❌ (limited) | ✅ Packages, services, files |
| Chef / Puppet | ❌ | ✅ Packages, services, files |
Ansible
Ansible is an agentless, push-based configuration management tool that uses YAML playbooks and SSH to configure servers. It is the most popular CM tool because of its simplicity.
---- name: Configure web server hosts: webservers become: yes vars: nginx_port: 80 app_version: "1.2.3"
tasks: - name: Install Nginx apt: name: nginx state: present update_cache: yes
- name: Configure Nginx template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: restart nginx
- name: Deploy application copy: src: "app-v{{ app_version }}.tar.gz" dest: /opt/app.tar.gz notify: restart app
handlers: - name: restart nginx service: name: nginx state: restarted
- name: restart app service: name: my-app state: restarted# Run the playbookansible-playbook -i inventory/production playbook.ymlAnsible’s agentless model (it uses SSH) means no software to install on target nodes. It works with almost any system running Python.
Chef
Chef is a Ruby-based configuration management tool that uses a client-server architecture. Nodes run the Chef client, which pulls policies from the Chef server and converges the node to the desired state.
package 'nginx' do action :installend
template '/etc/nginx/nginx.conf' do source 'nginx.conf.erb' owner 'root' group 'root' mode '0644' notifies :restart, 'service[nginx]'end
service 'nginx' do action [:enable, :start]endChef uses recipes (collections of resources), cookbooks (collections of recipes), and run lists (ordered list of recipes for a node).
Puppet
Puppet uses a declarative DSL and a client-server model where nodes (agents) periodically check in with the Puppet server and apply the desired state.
node 'webserver.example.com' { package { 'nginx': ensure => installed, }
file { '/etc/nginx/nginx.conf': content => template('webserver/nginx.conf.erb'), notify => Service['nginx'], }
service { 'nginx': ensure => running, enable => true, }}Puppet uses Facter to collect system facts (OS, memory, IP address) that can drive conditional logic in manifests.
CM Tool Comparison
Ansible is the easiest to learn (YAML, no agent). Chef and Puppet are more powerful for large-scale deployments but have steeper learning curves (Ruby DSL). For cloud-native workloads, Ansible + Terraform is the most common combination.
Immutable vs Mutable Infrastructure
Mutable Infrastructure
Traditional approach: servers are provisioned, then updated in place over their lifetime.
Provision → SSH in → Update packages → Deploy code → Patch OS → (repeat)Pros: Familiar, no need to reprovision for small changes, state is preserved.
Cons: Configuration drift — servers diverge over time as manual changes accumulate. “Snowflake servers” that can’t be reproduced.
Immutable Infrastructure
Modern approach: servers are never modified after deployment. Every change creates a new server and destroys the old one.
# Terraform + user_data for immutable deploymentsresource "aws_launch_template" "web" { image_id = data.aws_ami.amazon_linux_2.id instance_type = "t3.micro" user_data = base64encode(templatefile("user_data.sh", { app_version = var.app_version })) lifecycle { create_before_destroy = true }}
resource "aws_autoscaling_group" "web" { launch_template { id = aws_launch_template.web.id version = "$Latest" } min_size = 2 max_size = 10 tags = [{ key = "Name" value = "web-asg" propagate_at_launch = true }]}AMI (immutable image) → Launch Template → ASG → Rolling updatePros: Reproducible, no drift, easy rollbacks (revert to previous AMI), consistent across environments.
Cons: Slower deployments (must build new images), stateful data must be externalized (RDS, S3).
Tip
For cloud-native workloads, prefer immutable infrastructure for compute and Terraform/CloudFormation for provisioning. Use Ansible for bootstrapping during image builds (Packer), not for ongoing server management.
Packer + Ansible: Immutable Image Pipeline
source "amazon-ebs" "web" { ami_name = "web-app-{{timestamp}}" instance_type = "t3.micro" region = "us-east-1" source_ami_filter { filters = { name = "amzn2-ami-hvm-*-x86_64-gp2" root-device-type = "ebs" virtualization-type = "hvm" } most_recent = true owners = ["amazon"] } ssh_username = "ec2-user"}
build { sources = ["source.amazon-ebs.web"] provisioner "ansible" { playbook_file = "./ansible/playbook.yml" }}packer build packer-template.pkr.hclThis builds a golden AMI with all packages and configuration baked in — no runtime SSH needed.
Summary
Configuration management tools fall on a spectrum: Ansible (simple, agentless, YAML), Chef (Ruby DSL, pull-based), Puppet (declarative, fact-driven). Modern cloud architectures favor immutable infrastructure — building new golden images with Packer + Ansible rather than mutating servers in place. Terraform provisions the immutable infrastructure; configuration management tools handle the image baking process.