Développement local avec kind¶
Ce guide permet de faire tourner FastAPI + PostgreSQL localement sur un cluster kind, sans dépendre d'AWS.
Depuis #161 : le backend vit sous backend/¶
Le workload FastAPI a été déplacé sous backend/, symétrique de frontend/ (ADR 030).
Trois gestes du quotidien changent :
- Les tests se lancent depuis
backend/:cd backend && pytest. Les tests importentfrom app.main import app, donc lancés depuis la racine ils ne résolvent plus rien. - Le build d'image prend
backend/comme contexte :docker build -t fastapi:local backend/. .envet.env.dockervivent sousbackend/.app/config.pydéclareenv_file=".env", résolu par rapport au répertoire courant. Ces deux fichiers étant gitignorés, ungit pullne les déplace pas : le faire à la main, sinonSettings()échoue au démarrage sur des variables manquantes.
mv .env .env.docker backend/ # une seule fois, après avoir récupéré la branche
Prérequis¶
- Docker Desktop (ou Docker dans WSL)
kindv0.25+kubectlv1.31+
Vérification rapide :
docker version
kind version
kubectl version --client
Démarrage rapide¶
1. Créer le cluster¶
kind create cluster --name fastapi-local
kubectl cluster-info --context kind-fastapi-local
2. Builder et charger l'image¶
cd ~/Project-DEVOPS-FASTAPI-2026
# Build
docker build -t fastapi:local backend/
# Charger dans kind (contourne le registry)
kind load docker-image fastapi:local --name fastapi-local
3. Déployer¶
kubectl apply -k k8s/overlays/local-kind/ --context kind-fastapi-local
4. Vérifier que les pods sont Running¶
kubectl get pods -n fastapi --context kind-fastapi-local
Attendre que les deux pods fastapi-* et postgres-* soient 1/1 Running.
5. Tester¶
# Port-forward en arrière-plan
kubectl port-forward -n fastapi svc/fastapi 8080:80 --context kind-fastapi-local &
# Test basique
curl http://localhost:8080/
# Swagger UI (ouvrir dans un navigateur)
# http://localhost:8080/docs
# Test CORS
curl -H "Origin: http://localhost:3000" -v http://localhost:8080/ 2>&1 | grep -i access-control
Cycle de développement¶
Après chaque modification du code :
docker build -t fastapi:local backend/
kind load docker-image fastapi:local --name fastapi-local
kubectl rollout restart deployment/fastapi -n fastapi --context kind-fastapi-local
kubectl rollout status deployment/fastapi -n fastapi --context kind-fastapi-local
Ce que fait l'overlay local-kind¶
| Paramètre | Base (EKS) | Local (kind) |
|---|---|---|
DB_HOSTNAME |
endpoint RDS AWS | postgres (service k8s) |
DB_NAME |
fastapi_db |
fastapi |
| PostgreSQL | RDS managé | Pod avec emptyDir |
| Image | ${ECR_IMAGE} (CI) |
fastapi:local |
imagePullPolicy |
Always |
Never |
| Replicas | 2 | 1 |
| Secrets | External Secrets Operator | Secret k8s local |
Debugging¶
| Symptôme | Cause probable | Fix |
|---|---|---|
ImagePullBackOff sur fastapi:local |
Image pas chargée dans kind | kind load docker-image fastapi:local --name fastapi-local |
Init:Error sur migrations |
PostgreSQL pas encore ready | Attendre, le pod va retry |
Init:CrashLoopBackOff |
Erreur Alembic ou config manquante | kubectl logs -n fastapi <pod> -c migrations |
Pydantic ValidationError |
Secret incomplet | Vérifier DB_PASSWORD + SECRET_KEY dans secret.yaml |
Pod en Pending |
Resource limits trop hauts | Réduire les limits dans le base |
readOnlyRootFilesystem bloque |
Lib qui écrit hors /tmp |
Ajouter un emptyDir sur le chemin concerné |
| Données postgres perdues | emptyDir est éphémère |
Normal — supprimer le pod postgres pour reset |
# Logs migrations
kubectl logs -n fastapi <pod-fastapi> -c migrations --context kind-fastapi-local
# Logs app
kubectl logs -n fastapi <pod-fastapi> -c fastapi --context kind-fastapi-local
# Reset base de données (supprime toutes les données)
kubectl delete pod -n fastapi -l app=postgres --context kind-fastapi-local
Teardown¶
# Supprimer uniquement les ressources (garde le cluster)
kubectl delete -k k8s/overlays/local-kind/ --context kind-fastapi-local
# Supprimer le cluster entier
kind delete cluster --name fastapi-local
Test cross-origin front/back via docker-compose (#110)¶
Le docker-compose-dev.yaml inclut le service frontend : il reproduit en local la topologie cross-origin de la prod (app. → api.). La SPA est servie sur localhost:3000, l'API sur localhost:8080 → origines distinctes → le navigateur applique CORS exactement comme en prod. On valide donc le vrai fetch /posts/public + les en-têtes CORS avant de pousser.
docker compose -f docker-compose-dev.yaml up --build frontend api db
# Front : http://localhost:3000 (fetch -> http://localhost:8080/posts/public)
# L'API autorise http://localhost:3000 via le defaut ALLOWED_ORIGINS de backend/app/config.py.
L'URL de l'API est lue au runtime dans /config/config.js (#156), plus figée au build. En local, le compose monte frontend/local-config/ sur /usr/share/nginx/html/config : c'est l'équivalent exact du ConfigMap monté par overlay dans le cluster, donc le mécanisme testé en local est celui qui tourne en prod. Pour viser une autre API, éditer frontend/local-config/config.js et redémarrer le conteneur — pas de rebuild. Une base vide → liste vide ; créer un post via POST /posts/ (authentifié) pour peupler /posts/public.