Déploiement¶
mic-struct ne dicte pas le déploiement. Voici les modèles observés sur
les services qui l'utilisent.
Mode autonome — python -m¶
Chaque service généré a un point d'entrée :
Il démarre uvicorn sur Settings.host:Settings.port (défaut 0.0.0.0:8000).
Conteneur Docker¶
Dockerfile minimal :
FROM python:3.14-slim
WORKDIR /app
# Build multi-stage optionnel pour réduire la taille
COPY pyproject.toml ./
RUN pip install --no-cache-dir .
COPY src/ ./src/
ENV PORT=8000
EXPOSE 8000
CMD ["python", "-m", "my_service"]
Build et lancement :
docker build -t my-service:latest .
docker run -p 8000:8000 \
-e DATABASE_URL=postgresql+psycopg://... \
-e SERVICE_AUTH_ENABLED=true \
-e SERVICE_AUTH_SECRETS=secret1,secret2 \
my-service:latest
Worker en parallèle¶
Pour les services avec un worker (mail-out par ex.), un deuxième conteneur démarre le worker :
docker-compose.yml :
services:
api:
image: my-service:latest
command: python -m my_service
ports: ["8000:8000"]
worker:
image: my-service:latest
command: python -m my_service.worker
depends_on: [api, postgres]
Kubernetes — Deployment + Service + ServiceMonitor¶
Squelette Helm (à adapter) :
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-service
spec:
replicas: 2
selector: { matchLabels: { app: my-service } }
template:
metadata: { labels: { app: my-service } }
spec:
containers:
- name: api
image: registry.example.com/my-service:1.0.0
ports: [{ containerPort: 8000 }]
env:
- name: DATABASE_URL
valueFrom: { secretKeyRef: { name: my-service-db, key: url } }
- name: SERVICE_AUTH_SECRETS
valueFrom: { secretKeyRef: { name: my-service-auth, key: secrets } }
livenessProbe:
httpGet: { path: /health, port: 8000 }
periodSeconds: 10
readinessProbe:
httpGet: { path: /health, port: 8000 }
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector: { app: my-service }
ports: [{ port: 80, targetPort: 8000 }]
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-service
spec:
selector: { matchLabels: { app: my-service } }
endpoints:
- port: http
path: /metrics
interval: 30s
Probes k8s¶
livenessProbe→/health: si KO, k8s redémarre le pod.readinessProbe→/health: si KO, k8s ne route pas le trafic.
/health retourne 200 dès que l'app a fini son prepare() (DB
connectable + schéma OK). Avant : 503 implicite (pod en CrashLoopBackOff).
Migrations Alembic¶
Convention : un job k8s pré-deploy qui exécute alembic upgrade
head avant que le Deployment soit promu :
apiVersion: batch/v1
kind: Job
metadata:
name: my-service-migrate-{{ .Release.Revision }}
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: alembic
image: registry.example.com/my-service:1.0.0
command: ["alembic", "upgrade", "head"]
Helm pre-upgrade hook fait l'affaire.
Secrets¶
Stack : OpenBao + ExternalSecrets Operator. Les secrets sont résolus à l'admission du Pod, pas codés en dur dans les valeurs Helm.
Observabilité¶
/metricscollecté par Prometheus via ServiceMonitor.- Logs JSON sur stdout → fluentbit / promtail → Loki.
- Sentry / GlitchTip configurés côté initialisation du logging (à câbler côté service consommateur, MIC ne le fait pas pour vous).