📖 Recommandations — Best Practices Consolidées
Distillé des 30 incidents. À lire avant de coder. 🚀
🔧 Pipeline CI/CD
Variables & Secrets
- ✅ Masked = cache la valeur dans logs (pour toutes les branches)
- ❌ Protected = uniquement branches protégées (main, develop)
- 📌 Règle : Masked par défaut, Protected pour secrets production SEULEMENT
Variables Priorité (haute → basse)
1. Trigger/Schedule variables
2. Settings → CI/CD → Variables (TRÈS haute)
3. Variables fichier YAML
4. Variables groupe
→ Si les variables projet écrasent tes values YAML : utiliser before_script export
Kaniko vs Docker-in-Docker
- ✅ Kaniko : pas besoin Docker daemon, plus léger, plus rapide
- ❌ Docker-in-DinD : lourd, Alpine incompatible
- 📌 Pattern : candidate → scan → promote (jamais push sans scan)
Image scanning
stages:
- build # Kaniko → ECR (tag: SHA-candidate)
- scan-image # Trivy depuis ECR
- promote # Si OK → tag SHA + latest
Outils spéciaux (entrypoint)
jobs:
terraform:
image: alpine/terraform:latest
entrypoint: [""] # ← OBLIGATOIRE pour images non-standard
kaniko:
image: gcr.io/kaniko-project/executor:latest
entrypoint: [""] # ← OBLIGATOIRE
🏗️ Terraform & Infrastructure
State & Locks
- ⏸️ Ne JAMAIS interrompre
terraform apply/destroy(Ctrl+C = state lock) - 📌 Utiliser
tmuxpour les longues opérations - 🔓 Si bloqué :
terraform force-unlock LOCK_IDouaws s3 rm s3://bucket/.tflock
Workspaces (persistent vs ephemeral)
persistent/ → ECR, IAM (jamais détruits)
ephemeral/ → VPC, EKS, RDS (destroy quotidien)
Ressources hors state
- ❌ Ne jamais créer de ressources AWS manuellement (console)
- 🔄 En prod : toujours
terraform importavant restructurer - 🗑️ En dev :
terraform destroy→ restructurer →terraform apply
EKS requirements
- ✅ NAT Gateway OBLIGATOIRE pour nodes dans subnets privés
- ✅ Cleanup K8s AVANT terraform destroy (sinon ENIs orphelins)
- 📌 Ordre critique :
kubectl delete gateway→ attendre 30s →terraform destroy
Coûts AWS (ephemeral)
NAT Gateway : 0.045$/h → 0.18$/jour (4h)
EKS Control : 0.10$/h → 0.40$/jour
t3.medium : 0.047$/h → 0.19$/jour
RDS micro : 0.02$/h → 0.08$/jour
─────────────────────────────────
Total : → ~0.85$/jour → ~17$/mois
RDS snapshots
- ✅ Dev/ephemeral :
skip_final_snapshot = true - ⚠️ Production :
skip_final_snapshot = false+ gestion snapshots - 🔍 Attention aux coûts cachés (snapshots, EBS, etc)
☸️ Kubernetes & EKS
Deployments & Probes
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30 # ← FastAPI slow startup
timeoutSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 20
Database Migrations (Alembic)
# ✅ Init container pattern
initContainers:
- name: migrate
image: fastapi:latest
command: ["alembic", "upgrade", "head"]
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secret
key: url
containers:
- name: fastapi
image: fastapi:latest
# App démarre APRÈS migrations
ServiceAccount & RBAC
# ✅ Pour les jobs qui ont besoin de K8s API
serviceAccountName: fastapi-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: fastapi-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: fastapi-sa
namespace: fastapi
Metrics & HPA
# IMPORTANT : metrics-server OBLIGATOIRE
helm install metrics-server metrics-server/metrics-server -n kube-system
# HPA ne fonctionne que si metrics-server est actif
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: fastapi-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: fastapi
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
ConfigMaps & Secrets
- ✅ Vérifier que ConfigMap/Secret existe :
kubectl get configmap/secret - ✅ Vérifier le mountPath : doit correspondre au path attendu en app
- ✅ Mettre à jour
configMapKeyRef/secretKeyRefsi changements
Image Pull Secrets (ECR)
imagePullSecrets:
- name: ecr-secret
---
# Créer le secret :
kubectl create secret docker-registry ecr-secret \
--docker-server=199167114788.dkr.ecr.eu-west-3.amazonaws.com \
--docker-username=AWS \
--docker-password=$(aws ecr get-login-password --region eu-west-3)
🔐 Sécurité & Dépendances
Audit régulier
# Python
pip-audit
trivy fs .
semgrep --config p/security-audit .
# Docker image
trivy image fastapi:latest
Dépendances abandonnées = DANGER 🚨
- ❌ passlib (2023) → remplacé par bcrypt
- ❌ python-jose (peu maintenu) → remplacé par PyJWT
- 📌 Toujours vérifier : dernière release, issues, mainteneurs actifs
- 🔗 Outils : deps.dev, snyk.io, PyPI stats
Multi-stage Docker (CVEs réduites)
# ✅ Élimine packages de build, réduit CVEs
FROM python:3.12-slim AS builder
COPY requirements.txt .
RUN pip install --user -r requirements.txt
FROM python:3.12-slim AS runtime
COPY --from=builder /root/.local /root/.local
ENV PATH=/root/.local/bin:$PATH
COPY app /app
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0"]
CVEs & .trivyignore
# ✅ TOUJOURS justifier + dater
CVE-2024-XXXXX
expiry: 2026-06-01
justification: "Build dependency, not runtime"
📦 Dependencies (requirements.in → requirements.txt)
Utiliser pip-tools
# requirements.in
fastapi==0.100.0
sqlalchemy==2.0.0
pydantic==2.0.0
alembic==1.12.0
PyJWT>=2.12.0
bcrypt>=4.0.0
# Générer requirements.txt
pip-compile requirements.in
Principle of Least Dependency
- ❌ N'installer QUE ce qui est utilisé
- 📌 Auditer régulièrement :
pip list --outdated,pip-audit - 🗑️ Supprimer
http-tools,mitmproxy, etc. si non utilisés
🚀 Déploiement & Monitoring
Logs
# FastAPI logs
kubectl logs -n fastapi -l app=fastapi -f
# Tous les containers d'un pod
kubectl logs POD_NAME -c CONTAINER_NAME
# Previous crash
kubectl logs POD_NAME --previous
Port forwarding
# Local dev
kubectl port-forward -n fastapi svc/fastapi 8080:80
# Puis http://localhost:8080
Health checks
# app/main.py
@app.get("/health")
async def health():
return {"status": "ok"}
🎯 Checklist avant production
- [ ] Terraform : pas de Ctrl+C, tmux obligatoire
- [ ] Dépendances : pip-audit, deps.dev, pas de projects abandonnés
- [ ] Image : Trivy scan, CVEs justifiées, multi-stage build
- [ ] K8s : RBAC, ServiceAccount, probes configurées, metrics-server
- [ ] Migrations : Alembic en init container, pas dans main pod
- [ ] Secrets : jamais en plaintext, utiliser AWS Secrets Manager
- [ ] Logs : structurés, pas de passwords
- [ ] GitLab CI : avant_script export pour credentials sensibles
- [ ] Cleanup : kubectl delete ressources AVANT terraform destroy
À jour : 2026-05-18 ✅