Compare commits
23 Commits
86b6baa2c6
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| fa76a3a19a | |||
| f4b95c2676 | |||
| 47e2882d08 | |||
| 46b674ca29 | |||
| 67867f3bbd | |||
| 7b15bf7960 | |||
| 6a482c0445 | |||
| 9dd6d89c43 | |||
| 8ae95b03cf | |||
| cefa3e7dab | |||
| 6493a0a86c | |||
| ce3b26e62b | |||
| 36a4390fa3 | |||
| eab99485dd | |||
| 3bf622c3cc | |||
| 5fa4859220 | |||
| 50b43d4cd2 | |||
| f272be358f | |||
| 9822ba25f3 | |||
| bdbd5e19c4 | |||
| 22cdf0e7b9 | |||
| e2acdc5880 | |||
| f33b3914cd |
421
index.html
421
index.html
@@ -45,7 +45,16 @@
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.reveal .slides section svg,
|
||||
.reveal .slides section > img {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.reveal h1, .reveal h2 { text-align: left; }
|
||||
.reveal h1 { font-size: 1.8em; }
|
||||
.reveal h2 { font-size: 1.3em; }
|
||||
|
||||
.title-slide, .title-slide h1 { text-align: center !important; }
|
||||
.title-slide .subtitle { color: var(--ods-text); }
|
||||
@@ -122,20 +131,20 @@
|
||||
<p class="meta">FinistDevs · 2026</p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 2 : Speaker intro ────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 2 : Speaker intro ─────────────────────────────────── -->
|
||||
<section>
|
||||
<h2>Arnaud Prémel-Cabic</h2>
|
||||
<p>Tech Lead @ OVHCloud</p>
|
||||
<p><small style="color:var(--ods-text);">arnaud.premel-cabic@ovhcloud.com</small></p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 3 ──────────────────────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 3 ─────────────────────────────────────────────────── -->
|
||||
<section>
|
||||
<h2>"It works on my server."</h2>
|
||||
<p><em>Or: why doesn't it work here, when it works everywhere else?</em></p>
|
||||
<p><em>Why doesn't it work here when it works everywhere else?</em></p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 4 ──────────────────────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 4 ─────────────────────────────────────────────────── -->
|
||||
<section>
|
||||
<h2>You have a server. It works.</h2>
|
||||
<p><em>Great.</em></p>
|
||||
@@ -162,10 +171,14 @@
|
||||
</svg>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 5 ──────────────────────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 5 ─────────────────────────────────────────────────── -->
|
||||
<section>
|
||||
<h2>You have 10 servers.</h2>
|
||||
<p><em>Still manageable… but every small change means 10 SSH sessions, 10 vim edits, 10 chances to make a mistake.</em></p>
|
||||
<ul>
|
||||
<li>10 SSH sessions</li>
|
||||
<li>10 manual edits</li>
|
||||
<li>10 chances to make a mistake</li>
|
||||
</ul>
|
||||
<!-- SVG2 — laptop + 10 servers fan-out -->
|
||||
<svg width="720" height="260" viewBox="0 0 720 260" style="margin-top:0.5em;" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Laptop body -->
|
||||
@@ -249,10 +262,13 @@
|
||||
</svg>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 6 ──────────────────────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 6 ─────────────────────────────────────────────────── -->
|
||||
<section>
|
||||
<h2>Now you have 100 servers.</h2>
|
||||
<p><em>Some 2 years old. Some a couple of months. Some freshly provisioned.<br>None of them are exactly alike.</em></p>
|
||||
<ul>
|
||||
<li>Some 2 years old. Some a few months. Some brand new.</li>
|
||||
<li>None of them are exactly alike.</li>
|
||||
</ul>
|
||||
<!-- SVG3 — 100-server chaos grid with drift indicators -->
|
||||
<svg width="700" height="260" viewBox="0 0 700 260" style="margin-top:0.5em;" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
@@ -384,19 +400,24 @@
|
||||
</svg>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 7 ──────────────────────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 7 ─────────────────────────────────────────────────── -->
|
||||
<section>
|
||||
<h2>Each one is unique. Unreproducible. Undocumented.</h2>
|
||||
<h2>Unique. Unreproducible. Undocumented.</h2>
|
||||
<p><em>Welcome to Snowflake Hell.</em></p>
|
||||
<img src="https://media.giphy.com/media/QMHoU66sBXqqLqYvGO/giphy.gif"
|
||||
alt="This is fine"
|
||||
style="height:220px; margin-top:0.5em; border-radius:6px;">
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 8 ──────────────────────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 8 ─────────────────────────────────────────────────── -->
|
||||
<section>
|
||||
<h2>Configuration drift is silent… until it isn't.</h2>
|
||||
<p><em>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.</em></p>
|
||||
<h2>Configuration drift is silent…</h2>
|
||||
<ul>
|
||||
<li>Prod breaks on a Tuesday</li>
|
||||
<li>Can't reproduce the bug locally</li>
|
||||
<li>Can't scale reliably</li>
|
||||
<li>Can't onboard a new server without fear</li>
|
||||
</ul>
|
||||
<svg width="750" height="220" style="margin-top:0.5em;" viewBox="0 0 750 220" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="60" y1="180" x2="700" y2="180" stroke="#666666" stroke-width="2.5"/>
|
||||
<polygon points="700,174 720,180 700,186" fill="#666666"/>
|
||||
@@ -433,10 +454,10 @@
|
||||
</svg>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 9 ──────────────────────────────────────────────────── -->
|
||||
<section>
|
||||
<!-- ─── SLIDE 9 ─────────────────────────────────────────────────── -->
|
||||
<section style="height:100%;">
|
||||
<h2>What if your infrastructure was just… code?</h2>
|
||||
<p><em>Yes, even your AI assistant can write it. But you still need to understand what it deploys.</em></p>
|
||||
<p><em>Your AI assistant can write it*. You still need to understand what it deploys.</em></p>
|
||||
<svg width="750" height="220" style="margin-top:0.5em;" viewBox="0 0 750 220" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Code file icon -->
|
||||
<rect x="80" y="35" width="120" height="150" rx="6" fill="none" stroke="#0050d7" stroke-width="2.5"/>
|
||||
@@ -461,12 +482,13 @@
|
||||
<rect x="624" y="90" width="36" height="44" rx="5" fill="#0050d7" opacity="0.15" stroke="#0050d7" stroke-width="1.5"/>
|
||||
<circle cx="652" cy="124" r="3" fill="#00a344"/>
|
||||
</svg>
|
||||
<small style="position:absolute; bottom:40px; right:0; color:var(--ods-neutral-600); font-size:0.45em;">*Like this presentation 🤖</small>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 10 ──────────────────────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 10 ────────────────────────────────────────────────── -->
|
||||
<section>
|
||||
<h2>Configuration as Code</h2>
|
||||
<p>Managing infrastructure through machine-readable files, stored in version control.</p>
|
||||
<p>Machine-readable files. Version-controlled. Automated.</p>
|
||||
<svg width="750" height="220" style="margin-top:0.5em;" viewBox="0 0 750 220" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Reproducible -->
|
||||
<g transform="translate(125,80)">
|
||||
@@ -505,10 +527,15 @@
|
||||
</svg>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 11 ──────────────────────────────────────────────────── -->
|
||||
<section>
|
||||
<h2>Meet the three musketeers of infrastructure.</h2>
|
||||
<p><span class="puppet-col">Puppet</span> · <span class="ansible-col">Ansible</span> · <span class="tf-col">Terraform</span> — each fights a different battle.</p>
|
||||
<!-- ─── SLIDE 11 ────────────────────────────────────────────────── -->
|
||||
<section style="text-align:center;">
|
||||
<h2 style="text-align:center;">Meet the three musketeers of infrastructure.</h2>
|
||||
<p style="font-size:1.2em; margin-top:1em;">
|
||||
<img src="https://cdn.simpleicons.org/puppet/C17F00" alt="Puppet" style="height:0.9em; vertical-align:middle;"> <span class="puppet-col">Puppet</span> ·
|
||||
<img src="https://cdn.simpleicons.org/ansible" alt="Ansible" style="height:0.9em; vertical-align:middle;"> <span class="ansible-col">Ansible</span> ·
|
||||
<img src="https://cdn.simpleicons.org/terraform" alt="Terraform" style="height:0.9em; vertical-align:middle;"> <span class="tf-col">Terraform</span>
|
||||
</p>
|
||||
<p><em>Each solves a different problem.</em></p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 12 : Terraform intro ──────────────────────────────── -->
|
||||
@@ -517,56 +544,92 @@
|
||||
<p>Start here. Before you configure a server, you need to have one.</p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 13 : Terraform concepts ───────────────────────────── -->
|
||||
|
||||
<!-- ─── SLIDE 13 : What is Terraform ────────────────────────────── -->
|
||||
<section class="s-tf">
|
||||
<h2>HCL: HashiCorp Configuration Language.</h2>
|
||||
<p>Declarative, human-readable — and pure JSON works too.<br>
|
||||
<code>terraform plan</code> previews · <code>terraform apply</code> creates · <code>terraform destroy</code> removes.</p>
|
||||
<svg width="800" height="180" style="margin-top:0.5em;" viewBox="0 0 800 180" xmlns="http://www.w3.org/2000/svg">
|
||||
<h2>What is Terraform?</h2>
|
||||
<ul>
|
||||
<li><strong>Infrastructure as Code</strong> tool for provisioning cloud resources</li>
|
||||
<li>Created by <strong>HashiCorp</strong> in 2014</li>
|
||||
<li>Written in <strong>Go</strong></li>
|
||||
<li>BSL license since 2023 (was MPL)</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 14 : Terraform concepts ───────────────────────────── -->
|
||||
<section class="s-tf">
|
||||
<h2>HCL: HashiCorp Configuration Language</h2>
|
||||
<p>Declarative, human-readable — pure JSON works too.</p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 15 : Terraform workflow ───────────────────────────── -->
|
||||
<section class="s-tf">
|
||||
<h2>The Terraform workflow</h2>
|
||||
<ul>
|
||||
<li><code>terraform plan</code> — preview what will change</li>
|
||||
<li><strong>Review</strong> — validate the plan before proceeding</li>
|
||||
<li><code>terraform apply</code> — create or update resources</li>
|
||||
<li><code>terraform destroy</code> — tear everything down</li>
|
||||
</ul>
|
||||
<svg width="900" height="150" style="margin-top:0.5em;" viewBox="0 0 900 150" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<marker id="wf-arrow" viewBox="0 0 10 7" refX="10" refY="3.5" markerWidth="10" markerHeight="7" orient="auto-start-auto">
|
||||
<path d="M0,0 L10,3.5 L0,7z" fill="#7B42BC"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect x="10" y="30" width="150" height="120" rx="14" fill="none" stroke="#7B42BC" stroke-width="2.2"/>
|
||||
<g transform="translate(60,50)">
|
||||
<!-- Box 1: HCL Code -->
|
||||
<rect x="10" y="15" width="140" height="100" rx="12" fill="none" stroke="#7B42BC" stroke-width="2.2"/>
|
||||
<g transform="translate(50,28)">
|
||||
<path d="M0,4 L0,30 Q0,33 3,33 L27,33 Q30,33 30,30 L30,10 L20,0 L3,0 Q0,0 0,4z" fill="none" stroke="#7B42BC" stroke-width="1.6"/>
|
||||
<path d="M20,0 L20,7 Q20,10 23,10 L30,10" fill="none" stroke="#7B42BC" stroke-width="1.4"/>
|
||||
<line x1="7" y1="15" x2="23" y2="15" stroke="#7B42BC" stroke-width="1.2"/>
|
||||
<line x1="7" y1="20" x2="20" y2="20" stroke="#7B42BC" stroke-width="1.2"/>
|
||||
<line x1="7" y1="25" x2="17" y2="25" stroke="#7B42BC" stroke-width="1.2"/>
|
||||
</g>
|
||||
<text x="85" y="115" text-anchor="middle" font-family="system-ui,sans-serif" font-size="16" font-weight="600" fill="#00185e">HCL Code</text>
|
||||
<line x1="168" y1="90" x2="210" y2="90" stroke="#7B42BC" stroke-width="2" marker-end="url(#wf-arrow)"/>
|
||||
<rect x="218" y="30" width="150" height="120" rx="14" fill="none" stroke="#7B42BC" stroke-width="2.2"/>
|
||||
<g transform="translate(268,48)">
|
||||
<text x="80" y="92" text-anchor="middle" font-family="system-ui,sans-serif" font-size="14" font-weight="600" fill="#00185e">HCL Code</text>
|
||||
<!-- Arrow 1→2 -->
|
||||
<line x1="158" y1="65" x2="195" y2="65" stroke="#7B42BC" stroke-width="2" marker-end="url(#wf-arrow)"/>
|
||||
<!-- Box 2: plan -->
|
||||
<rect x="203" y="15" width="140" height="100" rx="12" fill="none" stroke="#7B42BC" stroke-width="2.2"/>
|
||||
<g transform="translate(248,30)">
|
||||
<ellipse cx="15" cy="15" rx="18" ry="12" fill="none" stroke="#7B42BC" stroke-width="1.6"/>
|
||||
<circle cx="15" cy="15" r="6" fill="none" stroke="#7B42BC" stroke-width="1.6"/>
|
||||
<circle cx="15" cy="15" r="2.5" fill="#7B42BC"/>
|
||||
</g>
|
||||
<text x="293" y="110" text-anchor="middle" font-family="monospace" font-size="15" font-weight="600" fill="#00185e">plan</text>
|
||||
<line x1="376" y1="90" x2="418" y2="90" stroke="#7B42BC" stroke-width="2" marker-end="url(#wf-arrow)"/>
|
||||
<rect x="426" y="30" width="150" height="120" rx="14" fill="none" stroke="#7B42BC" stroke-width="2.2"/>
|
||||
<g transform="translate(476,48)">
|
||||
<text x="273" y="92" text-anchor="middle" font-family="monospace" font-size="14" font-weight="600" fill="#00185e">plan</text>
|
||||
<!-- Arrow 2→3 -->
|
||||
<line x1="351" y1="65" x2="388" y2="65" stroke="#7B42BC" stroke-width="2" marker-end="url(#wf-arrow)"/>
|
||||
<!-- Box 3: review (new) -->
|
||||
<rect x="396" y="15" width="140" height="100" rx="12" fill="#f6f0ff" stroke="#7B42BC" stroke-width="2.2" stroke-dasharray="6,3"/>
|
||||
<g transform="translate(446,28)">
|
||||
<polyline points="3,18 10,25 25,8" fill="none" stroke="#7B42BC" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<text x="466" y="92" text-anchor="middle" font-family="system-ui,sans-serif" font-size="14" font-weight="600" fill="#00185e">review</text>
|
||||
<!-- Arrow 3→4 -->
|
||||
<line x1="544" y1="65" x2="581" y2="65" stroke="#7B42BC" stroke-width="2" marker-end="url(#wf-arrow)"/>
|
||||
<!-- Box 4: apply -->
|
||||
<rect x="589" y="15" width="140" height="100" rx="12" fill="none" stroke="#7B42BC" stroke-width="2.2"/>
|
||||
<g transform="translate(634,30)">
|
||||
<polygon points="5,2 30,15 5,28" fill="none" stroke="#7B42BC" stroke-width="1.8" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<text x="501" y="110" text-anchor="middle" font-family="monospace" font-size="15" font-weight="600" fill="#00185e">apply</text>
|
||||
<line x1="584" y1="90" x2="626" y2="90" stroke="#7B42BC" stroke-width="2" marker-end="url(#wf-arrow)"/>
|
||||
<rect x="634" y="30" width="156" height="120" rx="14" fill="none" stroke="#7B42BC" stroke-width="2.2"/>
|
||||
<g transform="translate(678,44)">
|
||||
<text x="659" y="92" text-anchor="middle" font-family="monospace" font-size="14" font-weight="600" fill="#00185e">apply</text>
|
||||
<!-- Arrow 4→5 -->
|
||||
<line x1="737" y1="65" x2="774" y2="65" stroke="#7B42BC" stroke-width="2" marker-end="url(#wf-arrow)"/>
|
||||
<!-- Box 5: Resources -->
|
||||
<rect x="782" y="15" width="108" height="100" rx="12" fill="none" stroke="#7B42BC" stroke-width="2.2"/>
|
||||
<g transform="translate(810,28)">
|
||||
<path d="M12,28 Q0,28 0,20 Q0,14 6,12 Q6,4 15,2 Q24,0 28,6 Q29,5 32,5 Q38,5 38,11 Q44,12 44,18 Q44,24 38,25 Q38,28 34,28z" fill="none" stroke="#7B42BC" stroke-width="1.6"/>
|
||||
</g>
|
||||
<text x="712" y="110" text-anchor="middle" font-family="system-ui,sans-serif" font-size="15" font-weight="600" fill="#00185e">Resources</text>
|
||||
<text x="400" y="18" text-anchor="middle" font-family="system-ui,sans-serif" font-size="12" fill="#666666" letter-spacing="1">WRITE → PLAN → APPLY</text>
|
||||
<text x="836" y="92" text-anchor="middle" font-family="system-ui,sans-serif" font-size="13" font-weight="600" fill="#00185e">Resources</text>
|
||||
</svg>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 14 : Terraform state ──────────────────────────────── -->
|
||||
<!-- ─── SLIDE 16 : Terraform state ──────────────────────────────── -->
|
||||
<section class="s-tf">
|
||||
<h2>Terraform remembers what it built.</h2>
|
||||
<p>The <code>.tfstate</code> file maps code to real-world resources. Store it remotely.<br>
|
||||
Depending on what you manage, it can contain plaintext sensitive values — credentials, tokens, secrets.<br>
|
||||
<em>Handle it with care. Don't feed it to your LLM.</em></p>
|
||||
<ul>
|
||||
<li>The <code>.tfstate</code> file maps code to real-world resources</li>
|
||||
<li>Store it <strong>remotely</strong> — never commit it to Git</li>
|
||||
<li>May contain sensitive values: credentials, tokens, secrets</li>
|
||||
</ul>
|
||||
<p><em>Handle with care.</em></p>
|
||||
<svg width="750" height="220" style="margin-top:0.5em;" viewBox="0 0 750 220" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<marker id="st-arrow" viewBox="0 0 8 6" refX="8" refY="3" markerWidth="8" markerHeight="6" orient="auto-start-auto">
|
||||
@@ -629,15 +692,17 @@
|
||||
</svg>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 15 : Terraform providers ──────────────────────────── -->
|
||||
<!-- ─── SLIDE 17 : Terraform providers ──────────────────────────── -->
|
||||
<section class="s-tf">
|
||||
<h2>One tool. Every API.</h2>
|
||||
<p>1000+ providers: AWS, GCP, Azure, Cloudflare, GitHub, Kubernetes…<br>
|
||||
Not just cloud — manage GitHub teams, Datadog monitors, PagerDuty schedules, DNS records.<br>
|
||||
<em>If it has an API, there's a Terraform provider for it.</em></p>
|
||||
<ul>
|
||||
<li><strong>1000+ providers</strong> — AWS, GCP, Azure, Cloudflare, GitHub, Kubernetes…</li>
|
||||
<li>Not just cloud — DNS, monitoring, CI/CD, anything with an API</li>
|
||||
</ul>
|
||||
<p><em>If it has an API, there's a Terraform provider for it.</em></p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 16 : Terraform code ───────────────────────────────── -->
|
||||
<!-- ─── SLIDE 18 : Terraform code ───────────────────────────────── -->
|
||||
<section class="s-tf">
|
||||
<p class="filename"># main.tf</p>
|
||||
<pre><code class="language-hcl" data-trim>
|
||||
@@ -664,37 +729,79 @@ resource "ovh_domain_zone_record" "web" {
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 17 : OpenTofu ──────────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 19 : Terraform CLI ────────────────────────────────── -->
|
||||
<section class="s-tf">
|
||||
<h2>In 2023, HashiCorp changed Terraform's license.</h2>
|
||||
<p>BSL instead of MPL — no longer truly open-source.<br>
|
||||
The community responded: <strong>OpenTofu</strong>, by the OpenTF Foundation, is the open-source fork.<br>
|
||||
<em>Drop-in replacement. Fully compatible. Community-driven.</em></p>
|
||||
<p class="filename">$ terminal</p>
|
||||
<pre><code class="language-bash" data-trim data-noescape>
|
||||
$ terraform init
|
||||
Initializing provider plugins...
|
||||
- Finding terraform-provider-openstack/openstack versions matching "~> 3.0"...
|
||||
- Finding ovh/ovh versions matching "~> 1.0"...
|
||||
- Installing terraform-provider-openstack/openstack v3.0.0...
|
||||
- Installing ovh/ovh v1.3.0...
|
||||
Terraform has been successfully initialized!
|
||||
|
||||
$ terraform plan
|
||||
openstack_compute_instance_v2.web: Refreshing state...
|
||||
Plan: 2 to add, 0 to change, 0 to destroy.
|
||||
|
||||
$ terraform apply
|
||||
openstack_compute_instance_v2.web: Creating...
|
||||
openstack_compute_instance_v2.web: Creation complete after 45s [id=abc-123]
|
||||
ovh_domain_zone_record.web: Creating...
|
||||
ovh_domain_zone_record.web: Creation complete after 3s [id=456]
|
||||
|
||||
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 18 : Terraform platforms ──────────────────────────── -->
|
||||
<!-- ─── SLIDE 20 : OpenTofu ─────────────────────────────────────── -->
|
||||
<section class="s-tf">
|
||||
<h2>HashiCorp changed Terraform's license.</h2>
|
||||
<ul>
|
||||
<li><strong>BSL</strong> instead of MPL — no longer truly open-source</li>
|
||||
<li>The community responded: <strong>OpenTofu</strong>, by the OpenTF Foundation</li>
|
||||
</ul>
|
||||
<p><em>Drop-in replacement. Fully compatible. Community-driven.</em></p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 21 : Terraform platforms ──────────────────────────── -->
|
||||
<section class="s-tf">
|
||||
<h2>Terraform at scale needs a platform.</h2>
|
||||
<p>
|
||||
<strong>Terraform Enterprise / HCP Terraform</strong> — HashiCorp's commercial offering: remote state, RBAC, audit logs<br>
|
||||
<strong>Spacelift</strong> — GitOps-first CI/CD for Terraform (and OpenTofu)<br>
|
||||
<strong>Atlantis</strong> — open-source: plan & apply triggered by pull requests<br>
|
||||
<strong>env0, Scalr</strong> — SaaS alternatives with policy & cost management
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>Terraform Enterprise / HCP Terraform</strong> — remote state, RBAC, audit logs</li>
|
||||
<li><strong>Spacelift</strong> — GitOps-first CI/CD for Terraform and OpenTofu</li>
|
||||
<li><strong>Atlantis</strong> — open-source, plan & apply from pull requests</li>
|
||||
<li><strong>env0, Scalr</strong> — SaaS with policy & cost management</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 19 : Ansible intro ─────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 22 : Ansible intro ────────────────────────────────── -->
|
||||
<section class="s-ansible">
|
||||
<h2><span class="ansible-col">Ansible</span></h2>
|
||||
<p>Your servers are provisioned. Now make them do something.</p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 20 : Ansible concepts ──────────────────────────────── -->
|
||||
|
||||
<!-- ─── SLIDE 23 : What is Ansible ──────────────────────────────── -->
|
||||
<section class="s-ansible">
|
||||
<h2>Push, not pull. SSH, not agents.</h2>
|
||||
<p>YAML playbooks run tasks in order, across any number of hosts.<br>
|
||||
No daemon. No certificate authority. Just Python + SSH.<br>
|
||||
<em>Idempotent modules ensure the same playbook can run safely again and again.</em></p>
|
||||
<h2>What is Ansible?</h2>
|
||||
<ul>
|
||||
<li><strong>Agentless automation</strong> tool for configuration and orchestration</li>
|
||||
<li>Created by <strong>Michael DeHaan</strong> in 2012</li>
|
||||
<li>Acquired by <strong>Red Hat</strong> in 2015</li>
|
||||
<li>Written in <strong>Python</strong> — Apache 2.0 license</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 24 : Ansible concepts ─────────────────────────────── -->
|
||||
<section class="s-ansible">
|
||||
<h2>Push-based. Runs over SSH.</h2>
|
||||
<ul>
|
||||
<li>YAML playbooks run tasks in order, across any number of hosts</li>
|
||||
<li>Nothing to install on target servers — just <strong>Python + SSH</strong></li>
|
||||
<li>Idempotent modules — same playbook runs safely again and again</li>
|
||||
</ul>
|
||||
<svg width="750" height="250" viewBox="0 0 750 250" xmlns="http://www.w3.org/2000/svg" style="margin-top:0.5em;">
|
||||
<defs>
|
||||
<marker id="a-push" viewBox="0 0 10 7" refX="9" refY="3.5" markerWidth="9" markerHeight="7" orient="auto">
|
||||
@@ -732,7 +839,7 @@ resource "ovh_domain_zone_record" "web" {
|
||||
</svg>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 21 : Ansible code ──────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 25 : Ansible code ─────────────────────────────────── -->
|
||||
<section class="s-ansible">
|
||||
<p class="filename"># playbook/webserver.yml</p>
|
||||
<pre><code class="language-yaml" data-trim>
|
||||
@@ -760,43 +867,89 @@ resource "ovh_domain_zone_record" "web" {
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 22 : Ansible operations ───────────────────────────── -->
|
||||
<!-- ─── SLIDE 26 : Ansible CLI ──────────────────────────────────── -->
|
||||
<section class="s-ansible">
|
||||
<p class="filename">$ terminal</p>
|
||||
<pre><code class="language-bash" data-trim data-noescape>
|
||||
$ ansible-playbook -i inventory playbook/webserver.yml
|
||||
|
||||
PLAY [Configure web server] ***************************************************
|
||||
|
||||
TASK [Gathering Facts] ********************************************************
|
||||
ok: [finistdevs-web]
|
||||
|
||||
TASK [Install nginx] **********************************************************
|
||||
changed: [finistdevs-web]
|
||||
|
||||
TASK [Deploy nginx config] ****************************************************
|
||||
changed: [finistdevs-web]
|
||||
|
||||
RUNNING HANDLER [Restart nginx] ***********************************************
|
||||
changed: [finistdevs-web]
|
||||
|
||||
PLAY RECAP ********************************************************************
|
||||
finistdevs-web : ok=4 changed=3 unreachable=0 failed=0 skipped=0
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 27 : Ansible operations ───────────────────────────── -->
|
||||
<section class="s-ansible">
|
||||
<h2>Not just configuration. Operations.</h2>
|
||||
<p>Patch 200 servers tonight. Roll out a kernel upgrade with a canary strategy. Run a compliance audit across your whole fleet.<br>
|
||||
<em>Ansible is the tool you reach for when you need to do something — once, or every week.</em></p>
|
||||
<ul>
|
||||
<li>Patch 200 servers tonight</li>
|
||||
<li>Roll out a kernel upgrade with a canary strategy</li>
|
||||
<li>Run a compliance audit across your whole fleet</li>
|
||||
</ul>
|
||||
<p><em>The go-to tool for one-off tasks and recurring operations.</em></p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 23 : Ansible Galaxy ────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 28 : Ansible Galaxy ───────────────────────────────── -->
|
||||
<section class="s-ansible">
|
||||
<h2>The community does the heavy lifting.</h2>
|
||||
<p><strong>Ansible Galaxy</strong> — 10,000+ ready-made roles and collections.<br>
|
||||
Don't write a playbook to install Docker from scratch. Someone already did.<br>
|
||||
<em>Just <code>ansible-galaxy install geerlingguy.docker</code>.</em></p>
|
||||
<ul>
|
||||
<li><strong>Ansible Galaxy</strong> — 10,000+ ready-made roles and collections</li>
|
||||
<li>Don't write a playbook to install Docker from scratch — someone already did</li>
|
||||
</ul>
|
||||
<p><em>Just <code>ansible-galaxy install geerlingguy.docker</code>.</em></p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 24 : Ansible platforms ────────────────────────────── -->
|
||||
<!-- ─── SLIDE 29 : Ansible platforms ────────────────────────────── -->
|
||||
<section class="s-ansible">
|
||||
<h2>Ansible at scale: open-source vs enterprise.</h2>
|
||||
<p>
|
||||
<strong>AWX</strong> — open-source web UI, API, and scheduler for Ansible<br>
|
||||
<strong>Ansible Automation Platform</strong> (Red Hat) — enterprise version of AWX, with support & integrations<br>
|
||||
<strong>Semaphore</strong> — lightweight open-source alternative to AWX<br>
|
||||
<em>The core Ansible engine remains Apache 2.0 — truly open-source.</em>
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>AWX</strong> — open-source web UI, API, and scheduler</li>
|
||||
<li><strong>Ansible Automation Platform</strong> (Red Hat) — enterprise AWX with support</li>
|
||||
<li><strong>Semaphore</strong> — lightweight open-source alternative</li>
|
||||
</ul>
|
||||
<p><em>Core engine remains Apache 2.0 — truly open-source.</em></p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 25 : Puppet intro ─────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 30 : Puppet intro ─────────────────────────────────── -->
|
||||
<section class="s-puppet">
|
||||
<h2><span class="puppet-col">Puppet</span></h2>
|
||||
<p>Your servers are configured. Now keep them that way.</p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 26 : Puppet concepts ─────────────────────────────── -->
|
||||
|
||||
<!-- ─── SLIDE 31 : What is Puppet ───────────────────────────────── -->
|
||||
<section class="s-puppet">
|
||||
<h2>What is Puppet?</h2>
|
||||
<ul>
|
||||
<li><strong>Configuration management</strong> tool for enforcing system state</li>
|
||||
<li>Created by <strong>Luke Kanies</strong> in 2005</li>
|
||||
<li>Puppet Inc. acquired by <strong>Perforce</strong> in 2022</li>
|
||||
<li>Written in <strong>Ruby</strong> and <strong>Clojure</strong></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 32 : Puppet concepts ──────────────────────────────── -->
|
||||
<section class="s-puppet">
|
||||
<h2>Pull, not push. Agents, not SSH.</h2>
|
||||
<p>Every 30 minutes, each puppet-agent polls the Puppet Server, compiles a catalog, and enforces it.<br>
|
||||
<em>Drift is corrected automatically — without anyone lifting a finger.</em></p>
|
||||
<ul>
|
||||
<li>Every 30 minutes, each <code>puppet-agent</code> polls the Puppet Server</li>
|
||||
<li>Compiles a catalog and enforces it locally</li>
|
||||
</ul>
|
||||
<p><em>Drift is corrected automatically.</em></p>
|
||||
<svg width="750" height="250" viewBox="0 0 750 250" xmlns="http://www.w3.org/2000/svg" style="margin-top:0.5em;">
|
||||
<defs>
|
||||
<marker id="a-pull" viewBox="0 0 10 7" refX="9" refY="3.5" markerWidth="9" markerHeight="7" orient="auto">
|
||||
@@ -833,7 +986,7 @@ resource "ovh_domain_zone_record" "web" {
|
||||
</svg>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 27 : Puppet code ──────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 33 : Puppet code ──────────────────────────────────── -->
|
||||
<section class="s-puppet">
|
||||
<p class="filename"># manifests/webserver.pp</p>
|
||||
<pre><code class="language-puppet" data-trim>
|
||||
@@ -856,12 +1009,34 @@ class webserver {
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 28 : Puppet drift detection ──────────────────────── -->
|
||||
<!-- ─── SLIDE 34 : Puppet CLI ───────────────────────────────────── -->
|
||||
<section class="s-puppet">
|
||||
<p class="filename">$ terminal</p>
|
||||
<pre><code class="language-bash" data-trim data-noescape>
|
||||
$ puppet agent -t
|
||||
Info: Using environment 'production'
|
||||
Info: Retrieving pluginfacts
|
||||
Info: Caching catalog for finistdevs-web.example.com
|
||||
Info: Applying configuration version '1713052408'
|
||||
|
||||
Notice: /Stage[main]/Webserver/Package[nginx]/ensure: created
|
||||
Notice: /Stage[main]/Webserver/File[/etc/nginx/nginx.conf]/content:
|
||||
--- /etc/nginx/nginx.conf
|
||||
+++ /tmp/puppet-file20260413
|
||||
Notice: /Stage[main]/Webserver/Service[nginx]/ensure: started
|
||||
|
||||
Notice: Applied catalog in 12.34 seconds
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 35 : Puppet drift detection ───────────────────────── -->
|
||||
<section class="s-puppet">
|
||||
<h2>Someone SSH'd in and changed something.</h2>
|
||||
<p>Puppet noticed. Puppet fixed it.<br>
|
||||
<em>Continuous compliance — not just at deploy time. Every. 30. Minutes.</em><br>
|
||||
No more gardening your servers by hand.</p>
|
||||
<ul>
|
||||
<li>Puppet noticed. Puppet fixed it.</li>
|
||||
<li>Continuous compliance — not just at deploy time. <strong>Every. 30. Minutes.</strong></li>
|
||||
<li>No manual remediation</li>
|
||||
</ul>
|
||||
<svg width="750" height="200" viewBox="0 0 750 200" xmlns="http://www.w3.org/2000/svg" style="margin-top:0.5em;">
|
||||
<defs>
|
||||
<marker id="a-cycle" viewBox="0 0 10 7" refX="9" refY="3.5" markerWidth="9" markerHeight="7" orient="auto">
|
||||
@@ -895,27 +1070,31 @@ class webserver {
|
||||
</svg>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 29 : Puppet platforms ────────────────────────────── -->
|
||||
<!-- ─── SLIDE 36 : Puppet platforms ─────────────────────────────── -->
|
||||
<section class="s-puppet">
|
||||
<h2>Puppet is for large fleets that can't afford drift.</h2>
|
||||
<p>Continuous compliance, auditability, and guaranteed state — at scale.<br>
|
||||
Best suited for enterprises with hundreds or thousands of long-lived servers.<br>
|
||||
<em>Fewer friendly SaaS options than Terraform or Ansible.<br>
|
||||
Puppet Enterprise and Foreman are self-hosted. No managed cloud offering.</em></p>
|
||||
<h2>Puppet: large fleets, zero drift.</h2>
|
||||
<ul>
|
||||
<li>Continuous compliance, auditability, and guaranteed state — at scale</li>
|
||||
<li>Best suited for enterprises with hundreds or thousands of long-lived servers</li>
|
||||
<li>Fewer SaaS options than Terraform or Ansible</li>
|
||||
</ul>
|
||||
<p><em>Puppet Enterprise and Foreman are self-hosted. No managed cloud offering.</em></p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 30 : Puppet community ────────────────────────────── -->
|
||||
<!-- ─── SLIDE 37 : Puppet community ─────────────────────────────── -->
|
||||
<section class="s-puppet">
|
||||
<h2>The ecosystem outlives the company.</h2>
|
||||
<p><strong>Vox Pupuli</strong> — 100+ open-source Puppet modules, community-maintained.<br>
|
||||
<strong>OpenVox</strong> — an emerging open-source fork of the Puppet core.<br>
|
||||
<em>The community is strong, with or without Puppet Inc.</em></p>
|
||||
<ul>
|
||||
<li><strong>Vox Pupuli</strong> — 100+ open-source Puppet modules, community-maintained</li>
|
||||
<li><strong>OpenVox</strong> — an emerging open-source fork of the Puppet core</li>
|
||||
</ul>
|
||||
<p><em>The community is strong, with or without Puppet Inc.</em></p>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 31 : They're complementary ───────────────────────── -->
|
||||
<!-- ─── SLIDE 38 : They're complementary ────────────────────────── -->
|
||||
<section>
|
||||
<h2>They're not competing. They're complementary.</h2>
|
||||
<p>Each one solves a different layer of the same problem.</p>
|
||||
<p>Each solves a different layer of the same problem.</p>
|
||||
<svg width="800" height="280" viewBox="0 0 800 280" xmlns="http://www.w3.org/2000/svg" style="margin-top:0.5em;">
|
||||
<defs>
|
||||
<marker id="a-down" viewBox="0 0 10 10" refX="5" refY="10" markerWidth="10" markerHeight="10" orient="auto">
|
||||
@@ -927,39 +1106,34 @@ class webserver {
|
||||
<text x="220" y="38" fill="#7B42BC" font-size="18" font-weight="bold" font-family="sans-serif">Terraform</text>
|
||||
<text x="338" y="38" fill="#5a2e8c" font-size="16" font-family="sans-serif">— Provision</text>
|
||||
<text x="220" y="56" fill="#8855cc" font-size="11" font-style="italic" font-family="sans-serif">VMs, networks, cloud resources</text>
|
||||
<text x="100" y="42" text-anchor="end" fill="#7B42BC" font-size="11" font-weight="bold" font-family="sans-serif">Day 0</text>
|
||||
<!-- Arrow -->
|
||||
<line x1="400" y1="76" x2="400" y2="94" stroke="#4d5592" stroke-width="2.5" marker-end="url(#a-down)"/>
|
||||
<!-- Arrow between Terraform and Ansible -->
|
||||
<line x1="400" y1="78" x2="400" y2="100" stroke="#4d5592" stroke-width="2.5" marker-end="url(#a-down)"/>
|
||||
<!-- Ansible layer -->
|
||||
<rect x="120" y="104" width="560" height="64" rx="10" fill="#CC0000" fill-opacity="0.1" stroke="#CC0000" stroke-width="2"/>
|
||||
<text x="220" y="132" fill="#CC0000" font-size="18" font-weight="bold" font-family="sans-serif">Ansible</text>
|
||||
<text x="306" y="132" fill="#a00" font-size="16" font-family="sans-serif">— Configure</text>
|
||||
<text x="220" y="150" fill="#cc3333" font-size="11" font-style="italic" font-family="sans-serif">packages, services, app deployment</text>
|
||||
<text x="100" y="136" text-anchor="end" fill="#CC0000" font-size="11" font-weight="bold" font-family="sans-serif">Day 1</text>
|
||||
<!-- Arrow -->
|
||||
<line x1="400" y1="170" x2="400" y2="188" stroke="#4d5592" stroke-width="2.5" marker-end="url(#a-down)"/>
|
||||
<!-- Arrow between Ansible and Puppet -->
|
||||
<line x1="400" y1="172" x2="400" y2="194" stroke="#4d5592" stroke-width="2.5" marker-end="url(#a-down)"/>
|
||||
<!-- Puppet layer -->
|
||||
<rect x="120" y="198" width="560" height="64" rx="10" fill="#A06010" fill-opacity="0.1" stroke="#A06010" stroke-width="2"/>
|
||||
<path d="M172,210 L188,216 L188,234 C188,244 172,250 172,250 C172,250 156,244 156,234 L156,216 Z" fill="none" stroke="#A06010" stroke-width="2"/>
|
||||
<polyline points="164,232 170,238 180,224" fill="none" stroke="#A06010" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<text x="220" y="228" fill="#A06010" font-size="18" font-weight="bold" font-family="sans-serif">Puppet</text>
|
||||
<text x="298" y="228" fill="#8a5010" font-size="16" font-family="sans-serif">— Enforce</text>
|
||||
<text x="220" y="246" fill="#b07020" font-size="11" font-style="italic" font-family="sans-serif">continuous compliance, drift correction</text>
|
||||
<text x="100" y="230" text-anchor="end" fill="#A06010" font-size="11" font-weight="bold" font-family="sans-serif">Day 2+</text>
|
||||
</svg>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 32 : Real-world stack ─────────────────────────────── -->
|
||||
<!-- ─── SLIDE 39 : Real-world stack ─────────────────────────────── -->
|
||||
<section>
|
||||
<h2>A common production setup:</h2>
|
||||
<ol>
|
||||
<li class="fragment"><span class="tf-col">Terraform</span> provisions the VM</li>
|
||||
<li class="fragment"><span class="ansible-col">Ansible</span> configures it and deploys the app</li>
|
||||
<li class="fragment"><span class="puppet-col">Puppet</span> continuously enforces compliance</li>
|
||||
<li><span class="tf-col">Terraform</span> provisions the VM</li>
|
||||
<li><span class="ansible-col">Ansible</span> configures it and deploys the app</li>
|
||||
<li><span class="puppet-col">Puppet</span> continuously enforces compliance</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<!-- ─── SLIDE 33 : Closing ──────────────────────────────────────── -->
|
||||
<!-- ─── SLIDE 40 : Closing ──────────────────────────────────────── -->
|
||||
<section class="title-slide">
|
||||
<h1>Questions?</h1>
|
||||
<p class="subtitle">Thank you!</p>
|
||||
@@ -967,6 +1141,7 @@ class webserver {
|
||||
Arnaud Prémel-Cabic · arnaud.premel-cabic@ovhcloud.com<br>
|
||||
Slides: <a href="https://ministicraft.pages.git.cloud.arnaud-pc.fr/finistdev-configuration-as-code/" target="_blank">ministicraft.pages.git.cloud.arnaud-pc.fr/finistdev-configuration-as-code/</a>
|
||||
</p>
|
||||
<p class="meta" style="margin-top:1.5em; font-size:0.45em; color:var(--ods-neutral-600);">🤖 Made with Claude & GitHub Copilot</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user