xpeditis2.0/infra/prod/k8s/base/04-backend.yaml
David 99e01f97fc
Some checks failed
Dev CI / Security gate (push) Successful in 31s
Dev CI / Backend — Lint (push) Successful in 1m8s
Dev CI / Frontend — Lint & Type-check (push) Successful in 1m14s
Dev CI / Backend — Unit Tests (push) Successful in 1m10s
Dev CI / Frontend — Unit Tests (push) Successful in 46s
Dev CI / Notify Failure (push) Has been skipped
CD Preprod / Security gate (push) Successful in 29s
CD Preprod / Backend — Lint (push) Successful in 1m7s
CD Preprod / Frontend — Lint & Type-check (push) Successful in 1m13s
CD Preprod / Backend — Unit Tests (push) Successful in 1m6s
CD Preprod / Frontend — Unit Tests (push) Successful in 44s
CD Preprod / Backend — Integration Tests (push) Failing after 37s
CD Preprod / Build Log Exporter (push) Has been skipped
CD Preprod / Image security (${{ matrix.service }}, ${{ matrix.arch }}) (amd64, backend) (push) Has been skipped
CD Preprod / Build Backend (push) Has been skipped
CD Preprod / Build Frontend (push) Has been skipped
CD Preprod / Image security (${{ matrix.service }}, ${{ matrix.arch }}) (amd64, frontend) (push) Has been skipped
CD Preprod / Image security (${{ matrix.service }}, ${{ matrix.arch }}) (amd64, log-exporter) (push) Has been skipped
CD Preprod / Image security (${{ matrix.service }}, ${{ matrix.arch }}) (arm64, backend) (push) Has been skipped
CD Preprod / Image security (${{ matrix.service }}, ${{ matrix.arch }}) (arm64, frontend) (push) Has been skipped
CD Preprod / Image security (${{ matrix.service }}, ${{ matrix.arch }}) (arm64, log-exporter) (push) Has been skipped
CD Preprod / Deploy to Preprod (push) Has been skipped
CD Preprod / Notify Success (push) Has been skipped
CD Preprod / Notify Failure (push) Has been skipped
fix
2026-09-24 21:32:47 +02:00

246 lines
7.7 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
initContainers:
- name: seed-rates
image: rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:latest
command: [sh, -ec, 'cp -R /app/src/infrastructure/storage/csv-storage/rates/. /rates/']
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
resources:
requests: { cpu: 50m, memory: 64Mi }
limits: { cpu: 200m, memory: 128Mi }
volumeMounts:
- name: rates
mountPath: /rates
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"]
readOnlyRootFilesystem: true
volumeMounts:
- name: rates
mountPath: /app/src/infrastructure/storage/csv-storage/rates
- name: logs
mountPath: /app/logs
- name: tmp
mountPath: /tmp
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"]
volumes:
- name: rates
emptyDir:
sizeLimit: 1Gi
- name: logs
emptyDir:
sizeLimit: 512Mi
- name: tmp
emptyDir:
sizeLimit: 256Mi
---
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