feat: add CLI demo slides for Terraform, Ansible, and Puppet

Show realistic terminal sessions with commands and output:
- Slide 17: terraform init/plan/apply with OVH providers
- Slide 23: ansible-playbook run with task status and RECAP
- Slide 30: puppet agent -t with catalog apply and summary

Renumber slides 1-36.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-14 01:58:55 +02:00
parent 3bf622c3cc
commit eab99485dd

View File

@@ -129,20 +129,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>
</section>
<!-- ─── SLIDE 4 ─────────────────────────────────────────────────── -->
<!-- ─── SLIDE 4 ─────────────────────────────────────────────────── -->
<section>
<h2>You have a server. It works.</h2>
<p><em>Great.</em></p>
@@ -169,7 +169,7 @@
</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>
@@ -256,7 +256,7 @@
</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>
@@ -391,7 +391,7 @@
</svg>
</section>
<!-- ─── SLIDE 7 ─────────────────────────────────────────────────── -->
<!-- ─── SLIDE 7 ─────────────────────────────────────────────────── -->
<section>
<h2>Each one is unique. Unreproducible. Undocumented.</h2>
<p><em>Welcome to Snowflake Hell.</em></p>
@@ -400,7 +400,7 @@
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>
@@ -440,7 +440,7 @@
</svg>
</section>
<!-- ─── SLIDE 9 ─────────────────────────────────────────────────── -->
<!-- ─── 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>
@@ -471,7 +471,7 @@
<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>
@@ -513,7 +513,7 @@
</svg>
</section>
<!-- ─── SLIDE 11 ──────────────────────────────────────────────────── -->
<!-- ─── SLIDE 11 ────────────────────────────────────────────────── -->
<section>
<h2>Meet the three musketeers of infrastructure.</h2>
<p><span class="puppet-col">Puppet</span> &nbsp;·&nbsp; <span class="ansible-col">Ansible</span> &nbsp;·&nbsp; <span class="tf-col">Terraform</span> — each fights a different battle.</p>
@@ -693,7 +693,33 @@ resource "ovh_domain_zone_record" "web" {
</code></pre>
</section>
<!-- ─── SLIDE 17 : OpenTofu ──────────────────────────────────────── -->
<!-- ─── SLIDE 17 : Terraform CLI ────────────────────────────────── -->
<section class="s-tf">
<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 : OpenTofu ─────────────────────────────────────── -->
<section class="s-tf">
<h2>In 2023, HashiCorp changed Terraform's license.</h2>
<ul>
@@ -703,7 +729,7 @@ resource "ovh_domain_zone_record" "web" {
<p><em>Drop-in replacement. Fully compatible. Community-driven.</em></p>
</section>
<!-- ─── SLIDE 18 : Terraform platforms ──────────────────────────── -->
<!-- ─── SLIDE 19 : Terraform platforms ──────────────────────────── -->
<section class="s-tf">
<h2>Terraform at scale needs a platform.</h2>
<p>
@@ -714,13 +740,13 @@ resource "ovh_domain_zone_record" "web" {
</p>
</section>
<!-- ─── SLIDE 19 : Ansible intro ────────────────────────────────── -->
<!-- ─── SLIDE 20 : 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 21 : Ansible concepts ─────────────────────────────── -->
<section class="s-ansible">
<h2>Push, not pull. SSH, not agents.</h2>
<ul>
@@ -765,7 +791,7 @@ resource "ovh_domain_zone_record" "web" {
</svg>
</section>
<!-- ─── SLIDE 21 : Ansible code ─────────────────────────────────── -->
<!-- ─── SLIDE 22 : Ansible code ─────────────────────────────────── -->
<section class="s-ansible">
<p class="filename"># playbook/webserver.yml</p>
<pre><code class="language-yaml" data-trim>
@@ -793,7 +819,32 @@ resource "ovh_domain_zone_record" "web" {
</code></pre>
</section>
<!-- ─── SLIDE 22 : Ansible operations ───────────────────────────── -->
<!-- ─── SLIDE 23 : 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 24 : Ansible operations ───────────────────────────── -->
<section class="s-ansible">
<h2>Not just configuration. Operations.</h2>
<ul>
@@ -804,7 +855,7 @@ resource "ovh_domain_zone_record" "web" {
<p><em>Ansible is the tool you reach for when you need to do something — once, or every week.</em></p>
</section>
<!-- ─── SLIDE 23 : Ansible Galaxy ───────────────────────────────── -->
<!-- ─── SLIDE 25 : Ansible Galaxy ───────────────────────────────── -->
<section class="s-ansible">
<h2>The community does the heavy lifting.</h2>
<ul>
@@ -814,7 +865,7 @@ resource "ovh_domain_zone_record" "web" {
<p><em>Just <code>ansible-galaxy install geerlingguy.docker</code>.</em></p>
</section>
<!-- ─── SLIDE 24 : Ansible platforms ────────────────────────────── -->
<!-- ─── SLIDE 26 : Ansible platforms ────────────────────────────── -->
<section class="s-ansible">
<h2>Ansible at scale: open-source vs enterprise.</h2>
<p>
@@ -825,13 +876,13 @@ resource "ovh_domain_zone_record" "web" {
</p>
</section>
<!-- ─── SLIDE 25 : Puppet intro ─────────────────────────────────── -->
<!-- ─── SLIDE 27 : 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 28 : Puppet concepts ─────────────────────────────── -->
<section class="s-puppet">
<h2>Pull, not push. Agents, not SSH.</h2>
<ul>
@@ -875,7 +926,7 @@ resource "ovh_domain_zone_record" "web" {
</svg>
</section>
<!-- ─── SLIDE 27 : Puppet code ──────────────────────────────────── -->
<!-- ─── SLIDE 29 : Puppet code ──────────────────────────────────── -->
<section class="s-puppet">
<p class="filename"># manifests/webserver.pp</p>
<pre><code class="language-puppet" data-trim>
@@ -898,7 +949,27 @@ class webserver {
</code></pre>
</section>
<!-- ─── SLIDE 28 : Puppet drift detection ──────────────────────── -->
<!-- ─── SLIDE 30 : 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 31 : Puppet drift detection ───────────────────────── -->
<section class="s-puppet">
<h2>Someone SSH'd in and changed something.</h2>
<ul>
@@ -939,7 +1010,7 @@ class webserver {
</svg>
</section>
<!-- ─── SLIDE 29 : Puppet platforms ────────────────────────────── -->
<!-- ─── SLIDE 32 : Puppet platforms ────────────────────────────── -->
<section class="s-puppet">
<h2>Puppet is for large fleets that can't afford drift.</h2>
<ul>
@@ -950,7 +1021,7 @@ class webserver {
<p><em>Puppet Enterprise and Foreman are self-hosted. No managed cloud offering.</em></p>
</section>
<!-- ─── SLIDE 30 : Puppet community ────────────────────────────── -->
<!-- ─── SLIDE 33 : Puppet community ────────────────────────────── -->
<section class="s-puppet">
<h2>The ecosystem outlives the company.</h2>
<ul>
@@ -960,7 +1031,7 @@ class webserver {
<p><em>The community is strong, with or without Puppet Inc.</em></p>
</section>
<!-- ─── SLIDE 31 : They're complementary ───────────────────────── -->
<!-- ─── SLIDE 34 : 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>
@@ -997,7 +1068,7 @@ class webserver {
</svg>
</section>
<!-- ─── SLIDE 32 : Real-world stack ─────────────────────────────── -->
<!-- ─── SLIDE 35 : Real-world stack ─────────────────────────────── -->
<section>
<h2>A common production setup:</h2>
<ol>
@@ -1007,7 +1078,7 @@ class webserver {
</ol>
</section>
<!-- ─── SLIDE 33 : Closing ──────────────────────────────────────── -->
<!-- ─── SLIDE 36 : Closing ──────────────────────────────────────── -->
<section class="title-slide">
<h1>Questions?</h1>
<p class="subtitle">Thank you!</p>