Puppet ·
Ansible ·
Terraform
— What's the difference and when to use what? —
FinistDevs · 2026
Tech Lead @ OVHCloud
arnaud.premel-cabic@ovhcloud.com
Or: why doesn't it work here, when it works everywhere else?
Great.
Still manageable… but every small change means 10 SSH sessions, 10 vim edits, 10 chances to make a mistake.
Some 2 years old. Some a couple of months. Some freshly provisioned.
None of them are exactly alike.
Welcome to Snowflake Hell.
Prod breaks on a Tuesday. You can't reproduce the bug locally. You can't scale reliably. You can't onboard a new server without fear.
Yes, even your AI assistant can write it. But you still need to understand what it deploys.
Managing infrastructure through machine-readable files, stored in version control.
Reproducible · Versionable · Auditable
Puppet · Ansible · Terraform — each fights a different battle.
Start here. Before you configure a server, you need to have one.
Declarative, human-readable — and pure JSON works too.
terraform plan previews · terraform apply creates · terraform destroy removes.
The .tfstate file maps code to real-world resources. Store it remotely.
Depending on what you manage, it can contain plaintext sensitive values — credentials, tokens, secrets.
Handle it with care. Don't feed it to your LLM.
1000+ providers: AWS, GCP, Azure, Cloudflare, GitHub, Kubernetes…
Not just cloud — manage GitHub teams, Datadog monitors, PagerDuty schedules, DNS records.
If it has an API, there's a Terraform provider for it.
# main.tf
terraform {
required_providers {
openstack = { source = "terraform-provider-openstack/openstack", version = "~> 3.0" }
ovh = { source = "ovh/ovh", version = "~> 1.0" }
}
}
resource "openstack_compute_instance_v2" "web" {
name = "finistdevs-web"
image_name = "Debian 12"
flavor_name = "b3-8"
network { name = "Ext-Net" }
}
resource "ovh_domain_zone_record" "web" {
zone = "example.com"
subdomain = "finistdevs"
fieldtype = "A"
target = openstack_compute_instance_v2.web.access_ip_v4
}
BSL instead of MPL — no longer truly open-source.
The community responded: OpenTofu, by the OpenTF Foundation, is the open-source fork.
Drop-in replacement. Fully compatible. Community-driven.
Terraform Enterprise / HCP Terraform — HashiCorp's commercial offering: remote state, RBAC, audit logs
Spacelift — GitOps-first CI/CD for Terraform (and OpenTofu)
Atlantis — open-source: plan & apply triggered by pull requests
env0, Scalr — SaaS alternatives with policy & cost management
Your servers are provisioned. Now make them do something.
YAML playbooks run tasks in order, across any number of hosts.
No daemon. No certificate authority. Just Python + SSH.
Idempotent modules ensure the same playbook can run safely again and again.
# playbook/webserver.yml
- name: Configure web server
hosts: webservers
become: true
tasks:
- name: Install nginx
ansible.builtin.package:
name: nginx
state: present
- name: Deploy nginx config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart nginx
handlers:
- name: Restart nginx
ansible.builtin.service:
name: nginx
state: restarted
Patch 200 servers tonight. Roll out a kernel upgrade with a canary strategy. Run a compliance audit across your whole fleet.
Ansible is the tool you reach for when you need to do something — once, or every week.
Ansible Galaxy — 10,000+ ready-made roles and collections.
Don't write a playbook to install Docker from scratch. Someone already did.
Just ansible-galaxy install geerlingguy.docker.
AWX — open-source web UI, API, and scheduler for Ansible
Ansible Automation Platform (Red Hat) — enterprise version of AWX, with support & integrations
Semaphore — lightweight open-source alternative to AWX
The core Ansible engine remains Apache 2.0 — truly open-source.
Your servers are configured. Now keep them that way.
Every 30 minutes, each puppet-agent polls the Puppet Server, compiles a catalog, and enforces it.
Drift is corrected automatically — without anyone lifting a finger.
# manifests/webserver.pp
class webserver {
package { 'nginx':
ensure => installed,
}
file { '/etc/nginx/nginx.conf':
ensure => file,
content => template('webserver/nginx.conf.erb'),
notify => Service['nginx'],
}
service { 'nginx':
ensure => running,
enable => true,
}
}
Puppet noticed. Puppet fixed it.
Continuous compliance — not just at deploy time. Every. 30. Minutes.
No more gardening your servers by hand.
Continuous compliance, auditability, and guaranteed state — at scale.
Best suited for enterprises with hundreds or thousands of long-lived servers.
Fewer friendly SaaS options than Terraform or Ansible.
Puppet Enterprise and Foreman are self-hosted. No managed cloud offering.
Vox Pupuli — 100+ open-source Puppet modules, community-maintained.
OpenVox — an emerging open-source fork of the Puppet core.
The community is strong, with or without Puppet Inc.
Each one solves a different layer of the same problem.
Thank you!
Arnaud Prémel-Cabic · arnaud.premel-cabic@ovhcloud.com
Slides: ministicraft.pages.git.cloud.arnaud-pc.fr/finistdev-configuration-as-code/