Files
Talks/slides/kubernetes-operators/slides.md
T
Le Prévost-Corvellec Arnault 354c8cd9ef Add Makefile, package.json, and initial configuration for VitePress and Slidev integration
- Introduced a Makefile for streamlined commands related to building, running, and managing presentations.
- Created package.json to define project metadata, dependencies, and scripts for development and testing.
- Added .gitignore entries to exclude build artifacts and temporary files from version control.
- Included playwright.config.mjs for end-to-end testing setup with Playwright.
- Added README.md for project documentation, outlining setup instructions and development guidelines.
2026-04-11 15:59:20 +02:00

578 lines
14 KiB
Markdown

---
theme: default
title: Kubernetes Operators — De l'enfer au paradis
info: |
Mental model Kubernetes, boucles de contrôle, opérateurs, exemples et pièges.
highlighter: shiki
# Comme Reveal « center: true » : planche centrée (layout intégré Slidev).
defaults:
layout: center
---
# Kubernetes Operators — De l'enfer… au paradis
> Kubernetes n'est **pas** compliqué.
> Mais **mal compris**… c'est un enfer.
<!--
On parle surtout de pourquoi les opérateurs changent la manière de travailler — puissants mais dangereux si le mental model est faux.
-->
---
## Kubernetes : délire d'Ops ?
> On nous l'a surtout vendu comme un truc d'infra.
> *Moi aussi, je suis passé par ce réflexe.*
- « Trop complexe »
- Réservé aux spécialistes plateforme
- Magie noire / pas « mon » métier
<!--
Souvent présenté comme réservé aux spécialistes — en réalité proche de ce qu'on fait déjà en dev.
-->
---
## Kubernetes c'est un délire de dev
> Kubernetes c'est un délire de dev
<!--
Transition : contraste avec la slide précédente.
-->
---
## Kubernetes = API + état + boucle
- API REST
- Base d'état (etcd)
- Boucle de réconciliation → events
- Pas de mystère → mécanismes explicites (controllers, kubelet, containerd, etc.)
<!--
Pas de magie — des patterns qu'on retrouve ailleurs en dev.
-->
---
## De vos outils au noyau Linux
```mermaid
flowchart LR
B[kube-api]
subgraph Clients["Clients"]
A01[kubectl]
A02[Helm]
A03[Kustomize]
end
A01 --> B
A02 --> B
A03 --> B
B --> C[(etcd)]
B --> D[Controllers]
D --> B
D --> E[kubelet]
E --> F[containerd]
F --> G[Kernel Linux]
```
- **kube-api** — point d'entrée
- **etcd** — source de vérité
- **kubelet** — agent sur chaque nœud
- **container runtime** (ex. containerd) — exécution des conteneurs
<!--
Helm, kubectl, Flux… appellent l'API. L'API parle à etcd, les controllers poussent vers les kubelets, le runtime lance les conteneurs.
-->
---
## Kubernetes ne fait pas tourner vos apps : la boucle de contrôle
Il **orchestre** · il **délègue** · il **observe**
```mermaid
flowchart LR
DS["Spec · désir"] --> AP[kube-apiserver]
AP <-->|objets cluster| ET[(etcd)]
AP --> EV["Watch · événements"]
EV --> CTRL[Controllers]
CTRL -->|réconciliation · requêtes API| AP
subgraph NODE["Nœud"]
K[kubelet] -->|CRI| CD[containerd]
end
AP -->|spec Pods · synchro| K
K -->|status| AP
```
**↻** Les changements d'objets vivent dans l'API ; le **kubelet** **synchronise** depuis l'API, traduit en **CRI** vers **containerd**. Le **status** remonte par le kubelet.
<!--
Aligné sur la doc Kubernetes : observer, rapprocher le courant du spec ; informers / watches → files d'événements. etcd derrière l'API.
-->
---
## Sous containerd : cgroups et namespaces
```mermaid
flowchart TD
F[containerd] --> K[Linux Kernel]
```
- **cgroups**
- **namespaces**
<!--
Derrière containerd, le noyau — vous ne voulez pas manipuler les fichiers à la main au quotidien.
-->
---
## Kubernetes vous évite de vivre dans le noyau
- Manipuler les **cgroups** à la main
- Gérer **isolation**, **CPU**, **mémoire** sur vos nœuds
> À côté de ça, un cluster qui râle, c'est presque du repos.
---
## CNI, CSI, CRI : de l'infra branchable
- **CNI** → réseau (ex. Istio, Cilium, Calico, Flannel…)
- **CSI** → stockage (ex. Ceph, Longhorn, Amazon…)
- **CRI** → runtime (ex. containerd, CRI-O…)
- Ici : brancher l'infra — pas encoder la logique métier (*≠* opérateur)
---
## Brancher l'infra ou coder le métier ?
| Type | Rôle |
|------|------|
| **CNI / CSI / CRI** | Infrastructure |
| **Opérateur** | Logique métier |
<!--
D'un côté briques branchables ; de l'autre du code qui encode le comportement dans le cluster. Icônes : icônes K8s officielles, CNCF Landscape, Simple Icons.
-->
---
## Qui écrit la logique du cluster ?
<!--
Qui décide quand l'état réel diverge ? (pause)
-->
---
## La logique vit dans les controllers
*Ils ferment la boucle : observation, décision, action.*
<!--
L'intelligence du cluster est dans les controllers.
-->
---
## Les opérateurs : des controllers spécialisés
<!--
Même mécanisme, focalisé sur un domaine métier ou un logiciel (base, queue…).
-->
---
## Sans opérateur : scripts, crons, humains dans la boucle
- Scripts bash
- Cron jobs
- Interventions humaines
- État incohérent
---
## Automatisation éclatée : la logique reste dans les têtes
- Runbooks Confluence
- Scripts bash « magiques »
- Cron jobs oubliés
- Interventions humaines
**La logique est dans la tête des gens, pas dans le système.**
---
## Drift, pas de reproductibilité, 3 h du matin
- Drift de configuration
- Actions non reproductibles
- Dépendance aux humains
- Incidents à 3 h du matin
- Pas **reproductible** / pas **observable** cluster / pas **fiable** dans le temps
- Impossible de **raisonner globalement** sur l'état
---
## Vous déclarez ; le système réconcilie
```yaml
kind: Database
spec:
size: 3
```
<!--
État voulu → le contrôleur fait les transitions répétitives.
-->
---
## Spec, opérateur, cluster : ça tourne en boucle
```mermaid
flowchart LR
A[Spec] --> B[Operator]
B --> C[Cluster]
C --> B
```
*Dès que le réel diverge, la réconciliation repart.*
<!--
Exemples : annotations sur ressources natives, puis vrais CRD ; projet maison pour ancrer le discours.
-->
---
## Reflector & Reloader : la puissance des annotations
| Outil | Idée | Déclencheur typique |
|-------|------|---------------------|
| **Reflector** (EmberStack) | Copie / réplique **Secrets** et **ConfigMaps** (autres ns, miroirs) | Annotations sur la ressource source ou la copie |
| **Reloader** (Stakater) | **Redémarre** les Pods si Secret / ConfigMap référencé change | Annotation sur **Deployment** / **StatefulSet** / etc. |
- Reflector : `reflector.v1.k8s.emberstack.com/*`
- Reloader : `reloader.stakater.com/auto: "true"`
<!--
Pas toujours un gros opérateur CRD — parfois contrôleur sur objets standards + annotations. Liens : kubernetes-reflector, Reloader sur GitHub.
-->
---
## Exemple Reflector : secret DB → namespace applicatif
*Le secret « source de vérité » vit avec la base ; Reflector recrée un miroir là où l'app tourne.*
```yaml
# Namespace database — secret maître
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
namespace: database
annotations:
reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"
reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "app-shop"
stringData:
DATABASE_URL: "postgres://…"
```
- Reflector maintient un **Secret du même nom** dans `app-shop`, à jour quand la source change.
- Alternative : `reflector.v1.k8s.emberstack.com/reflects: "database/db-credentials"`
---
## Exemple Reloader : rollout quand le secret miroir change
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: shop-api
namespace: app-shop
annotations:
reloader.stakater.com/auto: "true"
spec:
template:
spec:
containers:
- name: api
envFrom:
- secretRef:
name: db-credentials
```
- Rotation dans `database/db-credentials` → Reflector met à jour `app-shop/db-credentials` → Reloader déclenche un **rollout**.
- Sans Reloader, les Pods gardent l'ancienne valeur en mémoire.
---
## Cert-manager, Postgres, Keycloak : la spec devient une entité
| Opérateur | CRD (exemples) | Ce que ça matérialise |
|-----------|----------------|----------------------|
| **cert-manager** | `Certificate`, `Issuer`, `ClusterIssuer` | Secrets TLS, ACME / PKI |
| **Postgres Operator** (Zalando) | `postgresql` (`acid.zalan.do`) | Cluster PG (Patroni, volumes, users…) |
| **Keycloak Operator** | `Keycloak`, `KeycloakRealm`, `KeycloakClient`… | Instances, royaumes, clients |
La spec décrit l'état métier ; le contrôleur crée / met à jour Deployments, Services, Secrets…
<!--
Trois domaines, même mécanisme CRD + réconciliation. Liens cert-manager.io, Zalando postgres-operator, Keycloak operator.
-->
---
## Un certificat déclaratif, tout le cycle TLS en dessous
```yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: api-example
spec:
dnsNames:
- api.example.com
```
Suite dérivée automatiquement : `CertificateRequest`, challenge ACME, Secret TLS.
---
## Certificats : du Certbot au renouvellement automatique
*Avant — sans opérateur*
- Certbot manuel
- Scripts cron
- Cert expiré = prod down
*Avec cert-manager*
- Déclaratif
- Auto-renouvellement
- Observabilité native (`Certificate`, conditions, events)
<!--
Complexité énorme encapsulée — pertinent quand le domaine est clair, répétitif et critique.
-->
---
## Postgres répliqué sans bricoler le failover à la main
```yaml
apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
name: my-cluster
spec:
numberOfInstances: 3
```
Derrière : réplication, failover, backup, users / rôles.
---
## Quelle techno pour développer votre opérateur ?
| Piste | Outils typiques | À retenir |
|-------|-----------------|-----------|
| **Go** (référence) | **Kubebuilder**, `controller-runtime`, client-go | Même patterns upstream ; sous charge : goroutines, files, back-off — peu de RAM en plus. |
| **Operator SDK** | CLI Red Hat · Go · Ansible / Helm | Go solide ; Ansible/Helm = wrapper — court si la logique métier épaissit. |
| **Autres** | Python **Kopf**, Rust **kube-rs**, Java… | Selon l'équipe ; moins d'exemples core. |
**Go + controller-runtime** pour un opérateur maison sérieux ; sinon celui que l'équipe **maintient** le mieux.
*Charge ↑ : un runtime qui gonfle la RAM par événement mange votre quota.*
---
## Quand un opérateur est légitime
- Système **complexe**
- **Règles** claires et stables
- **État** critique pour l'activité
- Opérations **répétitives**
<!--
Si tu ne peux pas formaliser « si X alors Y » proprement — très mauvaise idée en opérateur.
-->
---
## Keycloak Credential Manager — le même schéma, chez moi
- Objectif : **réconcilier** des **credentials Keycloak** avec ce qui est **déclaré dans le cluster** (CRD, Secrets annotés…).
- Montrer le **même schéma** : *observe → compare → corrige* sur **ton** domaine.
- **Incident / compromission** : reload Keycloak → événements côté IdP ; l'opérateur **interroge** (ex. toutes les minutes), repère l'écart et **propage** la correction.
<!--
Pas pour vendre un produit — prouver que la logique est la même : API K8s, état désiré, code à la place du runbook.
-->
---
## Exemple — `KeycloakClientCredential`
*CRD* `secrets.carbogame.com/v1alpha1` — `spec.source` (realm, client) → `spec.target` (Secret, rafraîchissement, mapping).
```yaml
apiVersion: secrets.carbogame.com/v1alpha1
kind: KeycloakClientCredential
metadata:
name: gitea-creds
namespace: keycloak
spec:
source:
keycloakServer: prod-keycloak
realm: operator
clientId: gitea
target:
secretName: gitea-secret-creds
namespace:
- gitea
refreshPeriod: 10m
fields:
clientId: key
clientSecret: secret
```
*En chart Helm, `namespace` et `keycloakServer` sont souvent injectés via templates.*
---
## Développer son opérateur : réutiliser les autres
- **Ne pas tout recoder** : s'appuyer sur des contrôleurs existants pour ce qu'ils font déjà bien.
- Ex. **Secrets / ConfigMaps** vers d'autres namespaces : brancher **Reflector** plutôt que dupliquer la logique — une politique de réflexion, **un RBAC** à raisonner.
- Votre code se concentre sur **le métier**.
---
## Ce qu'un opérateur bien choisi vous apporte
- Automatiser du **répétitif**
- **Encapsuler** de la complexité
- **Stabiliser** un système
… mais les opérateurs peuvent aussi devenir un enfer.
---
## Quand ne pas écrire d'opérateur
- Logique **floue** ou en perpétuelle négociation métier
- Processus **instables**
- Dépendances **externes** imprévisibles
- **One-shot** sans cycle de vie
---
## Cinq signaux qu'un opérateur part en vrille
- Spec **incompréhensible** sans lire le code
- Effets **implicites** (créations ailleurs invisibles)
- **Couplage** externe fort
- **Debug** impossible sans les mainteneurs
- **État** non observable (pas de conditions / status utiles)
> Un opérateur mal conçu, c'est un microservice dont plus personne ne tient les règles du jeu.
---
## Débugger un opérateur : describe, events, status, logs
- `kubectl describe` (resource + events)
- **Events** du namespace
- **Status / conditions** sur la CRD
- **Logs** du contrôleur
---
## Un opérateur, c'est un produit logiciel — pas un script
- **Code** et revues
- **Tests** (unitaires, intégration, e2e si possible)
- **Maintenance** dans la durée
- **Compatibilité** avec les versions Kubernetes
- **Migrations** de CRD / spec
---
## Quand l'opérateur devient l'enfer
- Logique **implicite**, **effets de bord**, **debugging** difficile, **couplage** fort
En pratique :
- Tout mettre en opérateur
- Logique métier **floue**
- Effets **cachés**
---
## Kubernetes, plateforme de programmation
- Kubernetes évite **l'enfer de l'infrastructure** bas niveau.
- Les **bons** opérateurs évitent **l'enfer du manuel** — les **mauvais** y renvoient autrement.
<!--
Fil : pas magique → API + boucle → controllers / opérateurs → avant/après → exemples → bon usage / pièges → conclusion.
-->
---
## Avant d'écrire un opérateur : la checklist
- Répétitif
- Règles claires
- Déclaratif possible
- Idempotent
- Observable
Si une case importante manque : **reculez**.
---
## Votre logique, exécutée par le cluster au lieu d'un humain
- « OK, je comprends enfin le cadre Kubernetes. »
- « Les opérateurs : puissants, à manier avec précision. »
Un opérateur, c'est votre logique métier — **lisible**, **testable**, **bornée**.
---
## Kubernetes simplifie l'infra — les opérateurs, ça peut simplifier ou empirer
Les **bons** **encapsulent** une complexité maîtrisée ; les **mauvais** recréent un enfer **plus sophistiqué**.
---
## Merci
Merci pour votre attention.
**Des questions ?**
<ClosingQr />
- Dépôt : [git.specificat.io/arnault/Talks](https://git.specificat.io/arnault/Talks)
- Site : [specificat.io](https://specificat.io/)
- Index des slides : portail talks (page d'accueil des présentations)
<!--
Laisser le temps pour les questions ; rappeler l'URL du dépôt à l'oral.
-->