Add presentation for Finistère Dev meetup

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-13 22:02:44 +02:00
commit 60cb8b1a50

435
index.html Normal file
View File

@@ -0,0 +1,435 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Configuration as Code — Puppet vs Ansible vs Terraform</title>
<!-- Reveal.js CDN -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/dist/reset.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/dist/reveal.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/dist/theme/moon.css">
<!-- Highlight.js for code blocks -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/plugin/highlight/monokai.css">
<style>
:root {
--puppet-color: #FFAE1A;
--ansible-color: #EE0000;
--terraform-color: #7B42BC;
}
.reveal .slides section {
text-align: left;
}
.reveal h1, .reveal h2 {
text-align: center;
}
.reveal h1 { font-size: 1.8em; }
.reveal h2 { font-size: 1.3em; }
.reveal p, .reveal li { font-size: 0.78em; }
.reveal code { font-size: 0.7em; }
.reveal pre { width: 100%; }
.title-slide { text-align: center !important; }
.title-slide h1 { font-size: 2em; margin-bottom: 0.2em; }
.title-slide .subtitle { font-size: 1em; color: #aaa; }
.title-slide .meta { font-size: 0.7em; color: #888; margin-top: 1em; }
.tag {
display: inline-block;
padding: 2px 10px;
border-radius: 4px;
font-size: 0.55em;
font-weight: bold;
vertical-align: middle;
margin-left: 8px;
}
.tag-puppet { background: var(--puppet-color); color: #000; }
.tag-ansible { background: var(--ansible-color); color: #fff; }
.tag-tf { background: var(--terraform-color);color: #fff; }
.card-row {
display: flex;
gap: 1em;
margin-top: 0.5em;
}
.card {
flex: 1;
border-radius: 8px;
padding: 0.7em 1em;
font-size: 0.7em;
}
.card-puppet { border: 2px solid var(--puppet-color); background: rgba(255,174,26,0.08); }
.card-ansible { border: 2px solid var(--ansible-color); background: rgba(238,0,0,0.08); }
.card-tf { border: 2px solid var(--terraform-color);background: rgba(123,66,188,0.08); }
.card h3 { margin: 0 0 0.4em; font-size: 1.1em; }
.card ul { margin: 0; padding-left: 1.2em; }
.comparison-table {
width: 100%;
border-collapse: collapse;
font-size: 0.62em;
margin-top: 0.5em;
}
.comparison-table th, .comparison-table td {
border: 1px solid rgba(255,255,255,0.2);
padding: 0.4em 0.6em;
text-align: center;
}
.comparison-table th { background: rgba(255,255,255,0.1); }
.comparison-table td:first-child { text-align: left; font-weight: bold; }
.puppet-col { color: var(--puppet-color); }
.ansible-col { color: var(--ansible-color); }
.tf-col { color: var(--terraform-color); }
.highlight-box {
border-left: 4px solid #4CAF50;
background: rgba(76,175,80,0.1);
padding: 0.5em 1em;
margin: 0.5em 0;
border-radius: 0 6px 6px 0;
font-size: 0.75em;
}
.agenda-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.5em;
margin-top: 0.5em;
}
.agenda-item {
background: rgba(255,255,255,0.07);
border-radius: 6px;
padding: 0.5em 0.8em;
font-size: 0.75em;
}
.agenda-item .num { font-size: 1.3em; font-weight: bold; color: #888; }
.emoji { font-style: normal; }
</style>
</head>
<body>
<div class="reveal">
<div class="slides">
<!-- ─── SLIDE 1 : Title ─────────────────────────────────────────── -->
<section class="title-slide">
<h1>⚙️ Configuration as Code</h1>
<p class="subtitle">Puppet · Ansible · Terraform<br>— What's the difference and when to use what? —</p>
<p class="meta">Finistère Dev Meetup · 2026</p>
</section>
<!-- ─── SLIDE 2 : Agenda ────────────────────────────────────────── -->
<section>
<h2>📋 Agenda</h2>
<div class="agenda-grid">
<div class="agenda-item"><span class="num">01</span><br>What is Configuration as Code?</div>
<div class="agenda-item"><span class="num">02</span><br>The IaC landscape</div>
<div class="agenda-item"><span class="num">03</span><br><span class="puppet-col">Puppet</span> — Declare your state</div>
<div class="agenda-item"><span class="num">04</span><br><span class="ansible-col">Ansible</span> — Automate everything</div>
<div class="agenda-item"><span class="num">05</span><br><span class="tf-col">Terraform</span> — Provision infrastructure</div>
<div class="agenda-item"><span class="num">06</span><br>Comparison & when to use what</div>
</div>
</section>
<!-- ─── SLIDE 3 : What is CaC ──────────────────────────────────── -->
<section>
<h2>🤔 What is Configuration as Code?</h2>
<div class="highlight-box">
Managing infrastructure and system configuration <strong>through machine-readable files</strong> stored in version control — just like application code.
</div>
<ul>
<li class="fragment"><strong>Reproducible</strong> — same result every time</li>
<li class="fragment"><strong>Versionable</strong> — Git history, pull requests, rollbacks</li>
<li class="fragment"><strong>Auditable</strong> — who changed what, and when</li>
<li class="fragment"><strong>Scalable</strong> — apply to 1 or 10 000 servers identically</li>
<li class="fragment"><strong>Collaborative</strong> — code review, CI/CD pipelines</li>
</ul>
</section>
<!-- ─── SLIDE 4 : IaC landscape ───────────────────────────────── -->
<section>
<h2>🌍 The IaC Landscape</h2>
<p>Three main problem spaces:</p>
<div class="card-row">
<div class="card card-puppet">
<h3>🐾 Configuration<br>Management</h3>
<ul>
<li>Install / configure software</li>
<li>Enforce desired state on servers</li>
<li><strong>Puppet, Chef, Salt</strong></li>
</ul>
</div>
<div class="card card-ansible">
<h3>⚡ Orchestration &amp;<br>Automation</h3>
<ul>
<li>Run tasks across many hosts</li>
<li>Deploy apps, pipelines</li>
<li><strong>Ansible, Fabric</strong></li>
</ul>
</div>
<div class="card card-tf">
<h3>🏗️ Infrastructure<br>Provisioning</h3>
<ul>
<li>Create VMs, networks, DNS…</li>
<li>Cloud-agnostic</li>
<li><strong>Terraform, Pulumi, OpenTofu</strong></li>
</ul>
</div>
</div>
</section>
<!-- ─── SLIDE 5 : Puppet overview ─────────────────────────────── -->
<section>
<h2>🐾 Puppet <span class="tag tag-puppet">Configuration Management</span></h2>
<ul>
<li><strong>Born:</strong> 2005 — one of the oldest IaC tools</li>
<li><strong>Language:</strong> Puppet DSL (Ruby-based) or YAML (Hiera)</li>
<li><strong>Model:</strong> <em>Pull</em> — agents poll a central Puppet Server every 30 min</li>
<li><strong>Approach:</strong> <em>Declarative</em> — you describe the desired state</li>
<li><strong>Agent required:</strong> Yes (puppet-agent on each node)</li>
</ul>
<div class="highlight-box" style="margin-top:0.8em;">
💡 Great for large fleets where <strong>continuous compliance</strong> and drift detection matter.
</div>
</section>
<!-- ─── SLIDE 6 : Puppet code ─────────────────────────────────── -->
<section>
<h2>🐾 Puppet — Example</h2>
<pre><code class="language-puppet" data-trim>
# 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,
}
}
</code></pre>
<p>🔁 Run again → <strong>idempotent</strong>: only changes what diverged from the desired state</p>
</section>
<!-- ─── SLIDE 7 : Ansible overview ───────────────────────────── -->
<section>
<h2>⚡ Ansible <span class="tag tag-ansible">Automation &amp; Orchestration</span></h2>
<ul>
<li><strong>Born:</strong> 2012, acquired by Red Hat in 2015</li>
<li><strong>Language:</strong> YAML (Playbooks)</li>
<li><strong>Model:</strong> <em>Push</em> — the control node connects via SSH</li>
<li><strong>Approach:</strong> <em>Procedural</em> (tasks run in order) with idempotent modules</li>
<li><strong>Agent required:</strong> <strong>No</strong> — agentless, just Python + SSH</li>
</ul>
<div class="highlight-box" style="margin-top:0.8em;">
💡 Great for <strong>ad-hoc tasks</strong>, app deployments, and quick automation without setup overhead.
</div>
</section>
<!-- ─── SLIDE 8 : Ansible code ───────────────────────────────── -->
<section>
<h2>⚡ Ansible — Example</h2>
<pre><code class="language-yaml" data-trim>
# playbook/webserver.yml
- name: Configure web server
hosts: webservers
become: true
tasks:
- name: Install nginx
ansible.builtin.package:
name: nginx
state: present
- name: Copy nginx config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart nginx
- name: Ensure nginx is running
ansible.builtin.service:
name: nginx
state: started
enabled: true
handlers:
- name: Restart nginx
ansible.builtin.service:
name: nginx
state: restarted
</code></pre>
</section>
<!-- ─── SLIDE 9 : Terraform overview ─────────────────────────── -->
<section>
<h2>🏗️ Terraform <span class="tag tag-tf">Infrastructure Provisioning</span></h2>
<ul>
<li><strong>Born:</strong> 2014 by HashiCorp (open-source fork: <em>OpenTofu</em>)</li>
<li><strong>Language:</strong> HCL (HashiCorp Configuration Language)</li>
<li><strong>Model:</strong> <em>Plan → Apply</em> — preview changes before applying</li>
<li><strong>Approach:</strong> <em>Declarative</em> — describe your infrastructure graph</li>
<li><strong>Agent required:</strong> No — uses provider APIs (AWS, GCP, Azure, etc.)</li>
</ul>
<div class="highlight-box" style="margin-top:0.8em;">
💡 Great for <strong>creating and managing cloud resources</strong> — VMs, networks, DNS, databases…
</div>
</section>
<!-- ─── SLIDE 10 : Terraform code ────────────────────────────── -->
<section>
<h2>🏗️ Terraform — Example</h2>
<pre><code class="language-hcl" data-trim>
# main.tf
terraform {
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
}
}
provider "aws" { region = "eu-west-3" }
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
tags = { Name = "meetup-webserver" }
}
output "public_ip" {
value = aws_instance.web.public_ip
}
</code></pre>
<p>🗺️ <code>terraform plan</code> shows a diff · <code>terraform apply</code> creates resources · <code>terraform destroy</code> removes them</p>
</section>
<!-- ─── SLIDE 11 : Comparison table ──────────────────────────── -->
<section>
<h2>📊 Comparison at a Glance</h2>
<table class="comparison-table">
<thead>
<tr>
<th></th>
<th class="puppet-col">🐾 Puppet</th>
<th class="ansible-col">⚡ Ansible</th>
<th class="tf-col">🏗️ Terraform</th>
</tr>
</thead>
<tbody>
<tr><td>Primary focus</td><td>Config management</td><td>Automation / Orchestration</td><td>Infrastructure provisioning</td></tr>
<tr><td>Language</td><td>Puppet DSL</td><td>YAML</td><td>HCL</td></tr>
<tr><td>Approach</td><td>Declarative</td><td>Procedural + idempotent</td><td>Declarative</td></tr>
<tr><td>Push / Pull</td><td>Pull</td><td>Push</td><td>Push (via API)</td></tr>
<tr><td>Agent needed</td><td>Yes</td><td>No</td><td>No</td></tr>
<tr><td>State file</td><td>Catalog (server)</td><td>None (stateless)</td><td>Yes (.tfstate)</td></tr>
<tr><td>Cloud resources</td><td>Limited</td><td>Yes (modules)</td><td>Excellent</td></tr>
<tr><td>Learning curve</td><td>High</td><td>Low</td><td>Medium</td></tr>
</tbody>
</table>
</section>
<!-- ─── SLIDE 12 : When to use what ─────────────────────────── -->
<section>
<h2>🎯 When to Use What?</h2>
<div class="card-row">
<div class="card card-puppet">
<h3>🐾 Use Puppet when…</h3>
<ul>
<li>Large fleet (100s1000s of servers)</li>
<li>Continuous compliance / drift detection</li>
<li>Enterprise, strict governance</li>
<li>Long-running servers (pets)</li>
</ul>
</div>
<div class="card card-ansible">
<h3>⚡ Use Ansible when…</h3>
<ul>
<li>Agentless is a must</li>
<li>Quick automation or one-off tasks</li>
<li>App deployment & pipelines</li>
<li>Already using Red Hat / AWX</li>
</ul>
</div>
<div class="card card-tf">
<h3>🏗️ Use Terraform when…</h3>
<ul>
<li>Creating cloud infrastructure</li>
<li>Multi-cloud or hybrid environments</li>
<li>Preview changes before applying</li>
<li>Immutable infra (cattle, not pets)</li>
</ul>
</div>
</div>
</section>
<!-- ─── SLIDE 13 : They work together ───────────────────────── -->
<section>
<h2>🤝 They Work Together!</h2>
<div class="highlight-box">
These tools are <strong>complementary</strong>, not mutually exclusive.
</div>
<p>A common real-world stack:</p>
<ol>
<li class="fragment"><strong class="tf-col">Terraform</strong> provisions the VM on AWS/Azure/GCP</li>
<li class="fragment"><strong class="ansible-col">Ansible</strong> bootstraps the OS, installs base packages, deploys the app</li>
<li class="fragment"><strong class="puppet-col">Puppet</strong> continuously enforces compliance and manages config drift</li>
</ol>
<p class="fragment" style="margin-top:0.8em; font-style:italic; color:#aaa;">
→ Right tool for the right layer of the stack
</p>
</section>
<!-- ─── SLIDE 14 : Key Takeaways ────────────────────────────── -->
<section>
<h2>💡 Key Takeaways</h2>
<ul>
<li class="fragment">Configuration as Code → <strong>reproducible, auditable, scalable</strong> infrastructure</li>
<li class="fragment"><strong class="puppet-col">Puppet</strong> — continuous compliance on large server fleets (pull, agent)</li>
<li class="fragment"><strong class="ansible-col">Ansible</strong> — agentless automation & orchestration (push, YAML)</li>
<li class="fragment"><strong class="tf-col">Terraform</strong> — cloud infrastructure provisioning (plan/apply, HCL)</li>
<li class="fragment">They <strong>complement each other</strong> — choose based on the layer of your stack</li>
</ul>
</section>
<!-- ─── SLIDE 15 : Q&A ──────────────────────────────────────── -->
<section class="title-slide">
<h1>🙋 Questions?</h1>
<p class="subtitle">Thank you!</p>
<p class="meta" style="margin-top:2em;">
Slides made with <a href="https://revealjs.com" target="_blank">Reveal.js</a><br>
Finistère Dev Meetup · 2026
</p>
</section>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/dist/reveal.js"></script>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/plugin/notes/notes.js"></script>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/plugin/highlight/highlight.js"></script>
<script>
Reveal.initialize({
hash: true,
slideNumber: 'c/t',
transition: 'slide',
backgroundTransition: 'fade',
controls: true,
progress: true,
center: false,
plugins: [ RevealNotes, RevealHighlight ]
});
</script>
</body>
</html>