Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018BAUeCFpDkRD6tU5wGsc1C
217 lines
6.9 KiB
YAML
217 lines
6.9 KiB
YAML
# =============================================================================
|
|
# Backend NestJS
|
|
# =============================================================================
|
|
---
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: xpeditis-backend
|
|
namespace: xpeditis-prod
|
|
labels:
|
|
app.kubernetes.io/name: xpeditis-backend
|
|
app.kubernetes.io/component: api
|
|
app.kubernetes.io/part-of: xpeditis
|
|
spec:
|
|
replicas: 2
|
|
revisionHistoryLimit: 5
|
|
strategy:
|
|
type: RollingUpdate
|
|
rollingUpdate:
|
|
# Aucun pod retire avant qu'un remplacant ne soit pret : zero coupure.
|
|
maxUnavailable: 0
|
|
maxSurge: 1
|
|
selector:
|
|
matchLabels:
|
|
app.kubernetes.io/name: xpeditis-backend
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app.kubernetes.io/name: xpeditis-backend
|
|
app.kubernetes.io/component: api
|
|
app.kubernetes.io/part-of: xpeditis
|
|
annotations:
|
|
# Force le redemarrage des pods quand la configuration change : sans
|
|
# cela, modifier le ConfigMap ne produit aucun effet visible.
|
|
# La valeur est recalculee par scripts/deploy.sh.
|
|
xpeditis.com/config-checksum: "PLACEHOLDER"
|
|
spec:
|
|
imagePullSecrets:
|
|
- name: regcred
|
|
# 2 replicas sur 1 noeud : la contrainte est "preferred", sinon le second
|
|
# pod resterait indefiniment en Pending. Elle deviendra effective le jour
|
|
# ou un second noeud sera ajoute (phase 2 du plan de charge).
|
|
topologySpreadConstraints:
|
|
- maxSkew: 1
|
|
topologyKey: kubernetes.io/hostname
|
|
whenUnsatisfiable: ScheduleAnyway
|
|
labelSelector:
|
|
matchLabels:
|
|
app.kubernetes.io/name: xpeditis-backend
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
runAsUser: 1001
|
|
runAsGroup: 1001
|
|
fsGroup: 1001
|
|
seccompProfile:
|
|
type: RuntimeDefault
|
|
# 60 s : laisse le temps aux requetes en cours et aux connexions
|
|
# WebSocket de se fermer proprement.
|
|
terminationGracePeriodSeconds: 60
|
|
containers:
|
|
- name: backend
|
|
# Le tag est remplace au deploiement (kubectl set image).
|
|
image: rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:latest
|
|
imagePullPolicy: IfNotPresent
|
|
ports:
|
|
- name: http
|
|
containerPort: 4000
|
|
protocol: TCP
|
|
envFrom:
|
|
- configMapRef:
|
|
name: xpeditis-backend-config
|
|
- secretRef:
|
|
name: xpeditis-backend-secrets
|
|
env:
|
|
- name: POD_NAME
|
|
valueFrom:
|
|
fieldRef:
|
|
fieldPath: metadata.name
|
|
|
|
# Le demarrage inclut l'attente de PostgreSQL puis la verification
|
|
# des migrations : la sonde de demarrage laisse jusqu'a 150 s avant
|
|
# de declarer le pod perdu, sans penaliser les redemarrages rapides.
|
|
startupProbe:
|
|
httpGet:
|
|
path: /api/v1/health/live
|
|
port: http
|
|
initialDelaySeconds: 10
|
|
periodSeconds: 5
|
|
failureThreshold: 30
|
|
timeoutSeconds: 3
|
|
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /api/v1/health/live
|
|
port: http
|
|
periodSeconds: 20
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
|
|
# LIMITE CONNUE : /health/ready renvoie toujours "ready" sans tester
|
|
# PostgreSQL ni Redis (health.controller.ts). Un pod incapable de
|
|
# joindre la base sera donc declare pret. Correctif recommande apres
|
|
# la mise en ligne : @nestjs/terminus avec des indicateurs reels.
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /api/v1/health/ready
|
|
port: http
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 10
|
|
timeoutSeconds: 3
|
|
failureThreshold: 3
|
|
|
|
resources:
|
|
requests:
|
|
cpu: 300m
|
|
memory: 512Mi
|
|
limits:
|
|
cpu: 1500m
|
|
memory: 1536Mi
|
|
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
capabilities:
|
|
drop: ["ALL"]
|
|
# NON active volontairement : le conteneur ecrit dans /app/logs et
|
|
# dans /app/src/infrastructure/storage/csv-storage/rates (chemin
|
|
# resolu au runtime par le chargeur de grilles CSV). Monter des
|
|
# emptyDir par-dessus masquerait les fichiers livres dans l'image.
|
|
readOnlyRootFilesystem: false
|
|
|
|
lifecycle:
|
|
preStop:
|
|
exec:
|
|
# Laisse Traefik retirer le pod de son pool avant que le
|
|
# processus ne commence a refuser des connexions.
|
|
command: ["sh", "-c", "sleep 10"]
|
|
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: xpeditis-backend
|
|
namespace: xpeditis-prod
|
|
labels:
|
|
app.kubernetes.io/name: xpeditis-backend
|
|
annotations:
|
|
# Sessions collantes : obligatoires pour Socket.IO. La negociation
|
|
# long-polling echoue si deux requetes d'un meme handshake atterrissent sur
|
|
# des replicas differents.
|
|
#
|
|
# ATTENTION -- limite non resolue par ce reglage : le gateway
|
|
# (notifications.gateway.ts) garde la carte userId -> sockets EN MEMOIRE et
|
|
# n'utilise pas @socket.io/redis-adapter. Une notification emise par le
|
|
# replica A n'atteint donc pas un utilisateur connecte au replica B.
|
|
# Cf. docs/mise-en-prod/15-exploitation-incidents.md, "Points de vigilance".
|
|
traefik.ingress.kubernetes.io/service.sticky.cookie: "true"
|
|
traefik.ingress.kubernetes.io/service.sticky.cookie.name: "xpd_be"
|
|
traefik.ingress.kubernetes.io/service.sticky.cookie.secure: "true"
|
|
traefik.ingress.kubernetes.io/service.sticky.cookie.httponly: "true"
|
|
traefik.ingress.kubernetes.io/service.sticky.cookie.samesite: "lax"
|
|
spec:
|
|
type: ClusterIP
|
|
selector:
|
|
app.kubernetes.io/name: xpeditis-backend
|
|
ports:
|
|
- name: http
|
|
port: 4000
|
|
targetPort: http
|
|
protocol: TCP
|
|
|
|
---
|
|
apiVersion: policy/v1
|
|
kind: PodDisruptionBudget
|
|
metadata:
|
|
name: xpeditis-backend
|
|
namespace: xpeditis-prod
|
|
spec:
|
|
minAvailable: 1
|
|
selector:
|
|
matchLabels:
|
|
app.kubernetes.io/name: xpeditis-backend
|
|
|
|
---
|
|
apiVersion: autoscaling/v2
|
|
kind: HorizontalPodAutoscaler
|
|
metadata:
|
|
name: xpeditis-backend
|
|
namespace: xpeditis-prod
|
|
spec:
|
|
scaleTargetRef:
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
name: xpeditis-backend
|
|
minReplicas: 2
|
|
# Plafond a 4 : au-dela, le CPX41 sature. Passer a 3 noeuds avant d'augmenter
|
|
# (cf. 15-exploitation-incidents.md, section montee en charge).
|
|
maxReplicas: 4
|
|
metrics:
|
|
- type: Resource
|
|
resource:
|
|
name: cpu
|
|
target:
|
|
type: Utilization
|
|
averageUtilization: 70
|
|
- type: Resource
|
|
resource:
|
|
name: memory
|
|
target:
|
|
type: Utilization
|
|
averageUtilization: 80
|
|
behavior:
|
|
scaleUp:
|
|
stabilizationWindowSeconds: 60
|
|
scaleDown:
|
|
# Descente lente : evite de retirer un pod juste avant un nouveau pic.
|
|
stabilizationWindowSeconds: 600
|