De Docker Compose à Kubernetes
La plupart des dépôts d'architecture s'arrêtent au
docker compose up. Celui-ci va jusqu'à un cluster — parce que
c'est là que les décisions prises dans le code se paient, ou se vérifient.
Pourquoi aller jusqu'au cluster#
Un docker-compose.yml suffit à faire tourner l'application. Il ne
suffit pas à montrer ce qui nous intéresse ici : la continuité entre les
décisions de code et les décisions d'exploitation.
En mode transaction, PgBouncer peut affecter une connexion serveur différente à chaque transaction. Les usages liés à une session (LISTEN, SET persistant, verrous de session) demandent une connexion dédiée ou un autre mode. Les requêtes préparées au niveau protocole peuvent être prises en charge selon la configuration du pooler ; les détails sont au chapitre 01.
| Où | Conséquence |
|---|---|
URL de connexion (api-deployment.yaml) | ?prepared_statement_cache_size=0 |
Moteur SQLAlchemy (persistence/database.py) | nom d'énoncé unique par client, pool_pre_ping |
Migrations (migrate-job.yaml) | Alembic attaque PostgreSQL en direct (task-manager-db-rw), jamais le pooler |
Ces choix existent aussi sous Compose. Kubernetes ajoute la réplication, les changements de primaire et le dimensionnement de plusieurs poolers, ce qui oblige à vérifier ensemble les réglages des manifests et du moteur SQLAlchemy.
La topologie#
Correspondance Compose → Kubernetes#
| Service Compose | Équivalent Kubernetes | Ce que ça change |
|---|---|---|
postgres | Cluster CNPG, 3 instances | Failover automatique, réplication en flux |
pgbouncer | Pooler CNPG, 2 instances | Deux processus ; la séparation des nœuds reste à vérifier |
rabbitmq | RabbitmqCluster, 3 nœuds | Credentials générés par l'opérateur |
valkey | StatefulSet, 1 replica | Identique (le cache est jetable) |
migrate | Job db-migrate | Barrière avant l'API et le worker |
api | Deployment ×2 + HPA 2→6 | Montée en charge automatique |
worker | Deployment mail-worker ×2 | Consommateurs concurrents sur la file |
frontend | Deployment ×2 + HPA 2→4 | Derrière la Gateway |
mailpit, prometheus, redisinsight | Deployment ×1 | Exposés par hostnames *.localhost |
| ports publiés | Gateway + HTTPRoute (Gateway API) | Un seul point d'entrée, exposé en NodePort (ch. 04) |
Le principe de traduction est simple : ce qui était un conteneur avec un port publié devient un Deployment derrière un Service, et ce qui demandait de la disponibilité passe sous un opérateur plutôt que sous un script maison.
Ce que cette section couvre#
- 00Docker ComposeLe point de départ : healthchecks et ordre de démarrage garanti
- 01Les donnéesCloudNativePG, le pooler, et pourquoi les migrations le contournent
- 02Les workloadsDurcissement des pods, configuration, sondes, la même image pour trois rôles
- 03RésilienceAnti-affinité, HPA, PodDisruptionBudget, ce que fait un drain
- 04RéseauNeuf NetworkPolicy, la Gateway API, et les consoles de dev
- 05ExploitationDéploiement, sauvegardes vérifiées, RPO/RTO/SLO
- 06Le stockagePVC, StorageClass, et pourquoi HA du calcul ≠ HA du stockage
- 07SécuritéServiceAccount sans jeton, Pod Security Admission, egress fermé
Versions déclarées et limites de reproductibilité#
Les versions proviennent de k8s/deploy.sh et des manifests. Elles ne sont pas toutes figées : Metrics Server utilise latest, plusieurs images des tags mobiles, PostgreSQL le défaut de l’opérateur, et l’image Kind n’est pas spécifiée. Un laboratoire reproductible doit enregistrer les versions et digests effectivement utilisés.
| Composant | Version | Installation |
|---|---|---|
| CloudNativePG | 1.30.0 | kubectl apply --server-side |
| Opérateur RabbitMQ Cluster | v2.15.0 | manifeste de release |
| Gateway API (CRD) | v1.6.1, embarquées par Envoy Gateway | — |
| Envoy Gateway | v1.9.1 | kubectl apply --server-side |
| Metrics Server | latest + patch --kubelet-insecure-tls | requis par le HPA |
| PostgreSQL | image par défaut de CNPG 1.30 | — |
| Valkey | valkey/valkey:8-alpine | StatefulSet |
| Prometheus | prom/prometheus:v3.1.0 | Deployment |
Le Metrics Server est installé puis patché avec
--kubelet-insecure-tls. Sans ce drapeau, il refuse les certificats
auto-signés des kubelets de Kind, ne remonte aucune métrique — et le HPA
reste bloqué sur <unknown> sans jamais dire pourquoi. C'est le
genre de détail qui coûte une soirée quand il n'est écrit nulle part.
Il faut dire aussi ce qu'il fait : il désactive la vérification du certificat des kubelets. Le Metrics Server le documente comme for testing purposes only. Sur un vrai cluster, la voie propre est une CA qui signe les certificats kubelet — ce contournement n'a sa place qu'ici.