diff --git a/index.html b/index.html
index 0a1a032..0e215b3 100644
--- a/index.html
+++ b/index.html
@@ -129,6 +129,13 @@
Terraform
— What's the difference and when to use what? —
FinistDevs · 2026
+
+
+ Welcome — quick intro to the topic: how we manage infrastructure as code.
+ Three tools compared: Puppet, Ansible, Terraform — what each is for, when to pick which.
+ Goal: not "which is best" but understanding their distinct roles.
+
+
@@ -136,18 +143,37 @@
Arnaud Prémel-Cabic
Tech Lead @ OVHCloud
arnaud.premel-cabic@ovhcloud.com
+
+
+ Tech Lead at OVHcloud — work with these tools daily.
+ Keep it short, get to the content.
+
+
"It works on my server."
Why doesn't it work here when it works everywhere else?
+
+
+ The classic excuse — everyone's heard it (or said it).
+ Hook: the real problem isn't the code, it's the un-managed environment.
+ Sets up the whole talk: configuration we can't reproduce.
+
+
You have a server. It works.
Great.
+
+
+ One server, configured by hand — totally fine at this scale.
+ No tooling needed yet. The pain starts when you grow.
+
+
@@ -179,6 +205,12 @@
10 manual edits
10 chances to make a mistake
+
+
+ Manual edits don't scale — repetition breeds error.
+ Did you apply the change to all 10? Identically? You can't be sure.
+
+
@@ -269,6 +301,13 @@
Some 2 years old. Some a few months. Some brand new.
None of them are exactly alike.
+
+
+ Different ages, different patch levels, manual tweaks over time.
+ Point at the snowflakes/warnings in the diagram — each box is subtly different.
+ This is the reality of a hand-managed fleet.
+
+
@@ -404,6 +443,13 @@
Unique. Unreproducible. Undocumented.
Welcome to Snowflake Hell.
+
+
+ "Snowflake servers" — unique, fragile, impossible to recreate.
+ The "this is fine" meme — we've all normalized this chaos.
+ Lighten the mood, then pivot to the consequences.
+
+
@@ -418,6 +464,13 @@
Can't scale reliably
Can't onboard a new server without fear
+
+
+ Define drift: state slowly diverging from intent, T0 → T2 in the diagram.
+ It's silent — no alarm goes off until prod breaks.
+ These four pains are why we need Configuration as Code.
+
+
@@ -483,12 +536,26 @@
*Like this presentation 🤖
+
+
+ The pitch: describe infra in files, deploy reproducibly.
+ Aside on AI: it can write the code, but you must understand what it deploys — own the result.
+ Fun fact: this deck itself was built with AI assistance.
+
+
Configuration as Code
Machine-readable files. Version-controlled. Automated.
+
+
+ Three core benefits: reproducible, versionable, auditable.
+ Same input → same result. Git history = change log. Know who changed what & when.
+ This is the foundation all three tools share.
+
+
@@ -536,12 +603,25 @@
Terraform
Each solves a different problem.
+
+
+ Introduce the three: Puppet, Ansible, Terraform.
+ Tease the punchline early: they're complementary, not rivals.
+ We'll go through them in deploy order: provision → configure → enforce.
+
+
Terraform
Start here. Before you configure a server, you need to have one.
+
+
+ First layer: provisioning. You can't configure what doesn't exist.
+ Terraform's job is creating the infrastructure itself.
+
+
@@ -554,12 +634,24 @@
Written in Go
BSL license since 2023 (was MPL)
+
+
+ The IaC standard for cloud provisioning.
+ HashiCorp, 2014, Go. Flag the 2023 license change — we'll come back to it (OpenTofu).
+
+
HCL: HashiCorp Configuration Language
Declarative, human-readable — pure JSON works too.
+
+
+ Declarative: you describe the desired end state, not the steps.
+ HCL is the common language across all HashiCorp tools.
+
+
@@ -571,6 +663,13 @@
terraform apply — create or update resources
terraform destroy — tear everything down
+
+
+ Key safety feature: plan lets you preview before anything changes.
+ Always review the plan — this is what makes Terraform safe in prod.
+ apply is idempotent; destroy cleanly removes everything it created.
+
+
@@ -630,6 +729,13 @@
May contain sensitive values: credentials, tokens, secrets
Handle with care.
+
+
+ State is how Terraform knows what it already built — maps code to real resources.
+ Two big gotchas: store it remotely (team access + locking), never commit it (secrets inside).
+ Lost or corrupt state = Terraform loses track of reality.
+
+
@@ -700,6 +806,13 @@
Not just cloud — DNS, monitoring, CI/CD, anything with an API
If it has an API, there's a Terraform provider for it.
+
+
+ The real power: one workflow for everything, not just one cloud.
+ Examples beyond cloud: DNS records, GitHub repos, monitoring dashboards.
+ Providers are the plugin ecosystem that makes Terraform universal.
+
+
@@ -727,6 +840,13 @@ resource "ovh_domain_zone_record" "web" {
target = openstack_compute_instance_v2.web.access_ip_v4
}
+
+
+ Real OVHcloud example: spin up an instance, then point a DNS record at it.
+ Note the implicit dependency — the DNS record references the instance's IP, so Terraform orders them automatically.
+ Two different providers (OpenStack + OVH) working together in one file.
+
+
@@ -753,6 +873,13 @@ ovh_domain_zone_record.web: Creation complete after 3s [id=456]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
+
+
+ Walk the lifecycle: init (download providers) → plan → apply.
+ "2 added, 0 changed, 0 destroyed" — exactly the diff you reviewed, nothing more.
+ Re-running apply with no changes does nothing — that's idempotence.
+
+
@@ -763,6 +890,13 @@ Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
The community responded: OpenTofu , by the OpenTF Foundation
Drop-in replacement. Fully compatible. Community-driven.
+
+
+ 2023: HashiCorp moved to BSL — restricts commercial competitors, not truly open-source anymore.
+ Community forked it: OpenTofu, now under the Linux Foundation.
+ Practical takeaway: drop-in compatible, swap the binary. Worth knowing for licensing-sensitive orgs.
+
+
@@ -774,12 +908,25 @@ Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Atlantis — open-source, plan & apply from pull requests
env0, Scalr — SaaS with policy & cost management
+
+
+ Running Terraform from a laptop doesn't scale to a team.
+ You need: shared/locked state, RBAC, audit, plan-on-PR, policy & cost guardrails.
+ Range from SaaS (HCP, Spacelift, env0) to self-hosted open-source (Atlantis).
+
+
Ansible
Your servers are provisioned. Now make them do something.
+
+
+ Second layer: configuration. The VMs exist — now install and set things up.
+ Transition: Terraform built the box, Ansible makes it useful.
+
+
@@ -792,6 +939,12 @@ Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Acquired by Red Hat in 2015
Written in Python — Apache 2.0 license
+
+
+ Key differentiator: agentless — nothing to install on targets.
+ Red Hat backed, Python, genuinely open-source (Apache 2.0) — contrast with Terraform's BSL.
+
+
@@ -802,6 +955,13 @@ Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Nothing to install on target servers — just Python + SSH
Idempotent modules — same playbook runs safely again and again
+
+
+ Push model: control node connects out over SSH and runs tasks — point at the diagram.
+ "Agentless" = just needs Python + SSH on the target, no daemon.
+ Idempotent modules: re-running is safe, only changes what's needed.
+
+
@@ -865,6 +1025,13 @@ Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
name: nginx
state: restarted
+
+
+ Plain YAML — tasks run top to bottom against the "webservers" group.
+ become: true = run as root (sudo).
+ Handlers are the neat bit: restart nginx only if the config actually changed.
+
+
@@ -890,6 +1057,13 @@ changed: [finistdevs-web]
PLAY RECAP ********************************************************************
finistdevs-web : ok=4 changed=3 unreachable=0 failed=0 skipped=0
+
+
+ "ok" vs "changed" — ok means already in desired state, changed means it acted. That's idempotence visible in the output.
+ The handler only fired because the config task reported "changed".
+ Run it again and everything would be "ok", changed=0.
+
+
@@ -901,6 +1075,13 @@ finistdevs-web : ok=4 changed=3 unreachable=0 failed=0 skipped=0
Run a compliance audit across your whole fleet
The go-to tool for one-off tasks and recurring operations.
+
+
+ Ansible isn't only "set up a server once" — it shines for ad-hoc operations.
+ Imperative/orchestration angle: patching, rolling upgrades, canary, audits across the fleet.
+ This is where it differs most from Puppet's "always converge" model.
+
+
@@ -911,6 +1092,13 @@ finistdevs-web : ok=4 changed=3 unreachable=0 failed=0 skipped=0
Don't write a playbook to install Docker from scratch — someone already did
Just ansible-galaxy install geerlingguy.docker.
+
+
+ Galaxy = the package registry for reusable roles/collections.
+ Don't reinvent common setups — pull a battle-tested role (geerlingguy is the famous example).
+ Huge productivity multiplier; just vet what you import.
+
+
@@ -922,12 +1110,25 @@ finistdevs-web : ok=4 changed=3 unreachable=0 failed=0 skipped=0
Semaphore — lightweight open-source alternative
Core engine remains Apache 2.0 — truly open-source.
+
+
+ At scale you want a UI/scheduler/RBAC layer on top of the CLI.
+ AWX (free) → Ansible Automation Platform (Red Hat, supported) is the main path; Semaphore is a lighter option.
+ Reassure: the core stays Apache 2.0 — no license rug-pull like Terraform.
+
+
Puppet
Your servers are configured. Now keep them that way.
+
+
+ Third layer: enforcement. Configured once isn't enough — drift creeps back.
+ Puppet's job: keep state correct continuously, forever.
+
+
@@ -940,6 +1141,12 @@ finistdevs-web : ok=4 changed=3 unreachable=0 failed=0 skipped=0
Puppet Inc. acquired by Perforce in 2022
Written in Ruby and Clojure
+
+
+ The oldest of the three (2005) — pioneered config management.
+ Now owned by Perforce. We'll touch on what that means for the community later.
+
+
@@ -950,6 +1157,13 @@ finistdevs-web : ok=4 changed=3 unreachable=0 failed=0 skipped=0
Compiles a catalog and enforces it locally
Drift is corrected automatically.
+
+
+ Opposite model to Ansible: pull, not push — agents reach out to the server.
+ Every ~30 min the agent fetches a catalog and converges the node — point at the diagram.
+ This is the key idea: enforcement runs on a loop, not just at deploy.
+
+
@@ -1007,6 +1221,13 @@ class webserver {
}
}
+
+
+ Same nginx example as Ansible — compare the styles side by side.
+ Pure declarative: describe resources (package, file, service) and desired state, not steps.
+ notify chains the dependency: config change → restart service.
+
+
@@ -1027,6 +1248,13 @@ Notice: /Stage[main]/Webserver/Service[nginx]/ensure: started
Notice: Applied catalog in 12.34 seconds
+
+
+ Agent run: fetch catalog → compare to actual → apply only the diffs.
+ This normally runs automatically every 30 min; -t is a manual trigger for demo.
+ Next run with no drift would report no changes.
+
+
@@ -1037,6 +1265,13 @@ Notice: Applied catalog in 12.34 seconds
Continuous compliance — not just at deploy time. Every. 30. Minutes.
No manual remediation
+
+
+ The killer feature: self-healing. Someone hand-edits a file → Puppet reverts it next run.
+ Walk the loop in the diagram: drift detected → agent applies → compliant → repeat.
+ This is what "continuous compliance" means in practice.
+
+
@@ -1079,6 +1314,13 @@ Notice: Applied catalog in 12.34 seconds
Fewer SaaS options than Terraform or Ansible
Puppet Enterprise and Foreman are self-hosted. No managed cloud offering.
+
+
+ Sweet spot: large fleets of long-lived servers where drift control matters.
+ Trade-off vs the others: fewer SaaS options, more setup — it's self-hosted.
+ Honest framing: overkill for a handful of ephemeral cloud VMs.
+
+
@@ -1089,12 +1331,26 @@ Notice: Applied catalog in 12.34 seconds
OpenVox — an emerging open-source fork of the Puppet core
The community is strong, with or without Puppet Inc.
+
+
+ Addresses the "is Puppet dying?" worry after the Perforce acquisition.
+ Vox Pupuli keeps the modules alive; OpenVox forks the core (echoes the OpenTofu story).
+ Reassurance: the open ecosystem outlives any single vendor.
+
+
They're not competing. They're complementary.
Each solves a different layer of the same problem.
+
+
+ The payoff slide — the "vs" framing was a trap. They stack.
+ Terraform provisions → Ansible configures → Puppet enforces. Three layers.
+ "Which should I use?" → depends which layer of the problem you have.
+
+
@@ -1131,6 +1387,13 @@ Notice: Applied catalog in 12.34 seconds
Ansible configures it and deploys the app
Puppet continuously enforces compliance
+
+
+ Concrete recap of how they fit together end to end.
+ You don't have to use all three — but they layer cleanly when you do.
+ Pick by your actual need: just provisioning? Terraform. Ad-hoc ops? Ansible. Drift control? Puppet.
+
+
@@ -1142,6 +1405,13 @@ Notice: Applied catalog in 12.34 seconds
Slides: ministicraft.pages.git.cloud.arnaud-pc.fr/finistdev-configuration-as-code/
🤖 Made with Claude & GitHub Copilot
+
+
+ Thank the audience, point to the slides URL.
+ Open the floor for questions.
+ Backup topics if quiet: Kubernetes operators, Pulumi, secrets management.
+
+