FastAPI Hexagonal Code source

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.

TL;DR — Un cluster Kind à 4 nœuds, PostgreSQL en haute disponibilité par CloudNativePG, RabbitMQ par son opérateur officiel, treize NetworkPolicy (neuf en ingress, quatre en egress), HPA et PDB. Tout se monte par un script. Et une contrainte d'infra — le pooler en mode transaction — remonte jusque dans le moteur SQLAlchemy de l'application.

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#

CLUSTER KIND « TASK-MANAGER » control-plane worker-1 worker-2 worker-3 entrée NodePort 80 → 30080 443 → 30443 postgres-1 postgres-2 postgres-3 anti-affinité REQUISE anti-affinité REQUISE anti-affinité REQUISE api · worker · front pooler · rabbitmq répartis (préférée) api · worker · front pooler · rabbitmq répartis (préférée) api · worker · front pooler · rabbitmq répartis (préférée) Anti-affinité requise pour PostgreSQL : la perte d'un nœud n'emporte qu'une instance. Anti-affinité préférée pour le reste : le scheduler répartit sans jamais bloquer.
Ce que Kind ne simule pas Ces « nœuds » sont des conteneurs Docker sur la même machine. Kind reproduit la topologie multi-nœuds — anti-affinité, reschedule, drain, failover — pas la redondance matérielle. Si l'hôte ou Docker tombe, tout tombe ensemble. C'est un banc d'essai pour les comportements Kubernetes, pas une preuve de haute disponibilité.

Correspondance Compose → Kubernetes#

Service ComposeÉquivalent KubernetesCe que ça change
postgresCluster CNPG, 3 instancesFailover automatique, réplication en flux
pgbouncerPooler CNPG, 2 instancesDeux processus ; la séparation des nœuds reste à vérifier
rabbitmqRabbitmqCluster, 3 nœudsCredentials générés par l'opérateur
valkeyStatefulSet, 1 replicaIdentique (le cache est jetable)
migrateJob db-migrateBarrière avant l'API et le worker
apiDeployment ×2 + HPA 2→6Montée en charge automatique
workerDeployment mail-worker ×2Consommateurs concurrents sur la file
frontendDeployment ×2 + HPA 2→4Derrière la Gateway
mailpit, prometheus, redisinsightDeployment ×1Exposés par hostnames *.localhost
ports publiésGateway + 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#

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.

ComposantVersionInstallation
CloudNativePG1.30.0kubectl apply --server-side
Opérateur RabbitMQ Clusterv2.15.0manifeste de release
Gateway API (CRD)v1.6.1, embarquées par Envoy Gateway—
Envoy Gatewayv1.9.1kubectl apply --server-side
Metrics Serverlatest + patch --kubelet-insecure-tlsrequis par le HPA
PostgreSQLimage par défaut de CNPG 1.30—
Valkeyvalkey/valkey:8-alpineStatefulSet
Prometheusprom/prometheus:v3.1.0Deployment
Patch spécifique à Kind — à ne jamais transposer

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.