first commit
This commit is contained in:
435
index.html
Normal file
435
index.html
Normal 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 &<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 & 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 (100s–1000s 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>
|
||||
Reference in New Issue
Block a user