2026-09-20 12:10:35 +02:00
2026-09-14 20:50:19 +02:00
2026-09-14 20:50:19 +02:00
2026-09-14 20:50:19 +02:00
2026-09-14 20:50:19 +02:00
2026-09-14 20:50:19 +02:00
2026-09-20 12:10:35 +02:00

Helm charts

Six charts indépendants, déployés sur un cluster k3s avec Traefik + cert-manager déjà en place :

Chart Rôle
backend API Go/Gin (+ Jobs de migration et de seed)
frontend SPA Vite/React derrière nginx
postgresql Postgres 16 (StatefulSet + PVC Longhorn)
redis Redis 7 avec mot de passe (StatefulSet + PVC Longhorn)
ingressroute IngressRoute Traefik + Certificate TLS du host
cert-manager ClusterIssuers DNS-01 (Cloudflare), manifestes bruts (pas un chart Helm)

Backend et frontend sont servis sur le même host : ingressroute envoie /api/ et /uploads/ au backend, / au frontend. Le navigateur ne voit qu'une origine, ce qui garde les cookies de refresh-token same-site sans aucune config CORS (reproduit le proxy dev de frontend/vite.config.ts).

Prérequis

  • Traefik (namespace traefik) avec les Middlewares waf-chain et security-headers.
  • cert-manager installé (ne pas le réinstaller s'il l'est déjà).
  • Postgres et Redis : fournis par les charts postgresql et redis. Par défaut le backend vise les Services postgres et redis du namespace (database.host, redis.host), qui sont les fullnameOverride par défaut de ces deux charts, et la base vitrine_db / l'utilisateur postgres (database.name, database.user).
  • DNS : le host pointe vers l'IP du LoadBalancer Traefik.

1. Images

docker build -t <registry>/platform-backend:<tag> backend/
docker build -t <registry>/platform-frontend:<tag> frontend/
docker push <registry>/platform-backend:<tag>
docker push <registry>/platform-frontend:<tag>

2. Certificat : issuers (une seule fois)

kubectl create secret generic cloudflare-api-token-vitrine -n cert-manager \
  --from-literal=api-token='<token Zone:DNS:Edit>'
kubectl apply -f charts/cert-manager/cluster-issuer.yml

Ne pas appliquer cert-manager/networkpolicy.yml sur un cluster où cert-manager existe déjà.

3. Déploiement

Les secrets ne sont jamais commités : passer un fichier de values privé (gitignoré) ou --set-string.

kubectl create namespace <ns>

# Les mots de passe doivent être identiques ici et dans le backend ci-dessous.
helm install postgresql charts/postgresql -n <ns> --set-string auth.password='<mot de passe DB>'
helm install redis charts/redis -n <ns> --set-string auth.password='<mot de passe Redis>'

helm install backend charts/backend -n <ns> \
  --set image.repository=<registry>/platform-backend \
  --set image.tag=<tag> \
  --set secrets.JWT_SECRET="$(openssl rand -base64 48)" \
  --set secrets.DB_PASSWORD='<mot de passe>' \
  --set secrets.REDIS_PASSWORD='<mot de passe>' \
  --set env.MEDIA_LOCAL_BASE_URL=https://<host>/uploads

helm install frontend charts/frontend -n <ns> \
  --set image.repository=<registry>/platform-frontend \
  --set image.tag=<tag>

helm install ingressroute charts/ingressroute -n <ns> --set host=<host>

Les noms de release backend et frontend sont ceux que ingressroute attend (Services backend-platform-backend et frontend). Avec d'autres noms, surcharger backend.serviceName / frontend.serviceName côté ingressroute.

Premier essai TLS : ajouter --set tls.certificate.issuerName=letsencrypt-dns-vitrine-staging à l'install d'ingressroute (pas de quota Let's Encrypt), puis repasser sur letsencrypt-dns-vitrine.

Chaque chart valide ses valeurs obligatoires au rendu (helm template / install échoue avec un message clair : secrets.JWT_SECRET pour le backend, host pour ingressroute).

Premier install : compte admin

backend/cmd/seed n'est pas idempotent (échoue si l'admin existe déjà) : c'est un hook post-install uniquement. Il ne s'exécute donc que lors du tout premier helm install : ajouter ces valeurs à la commande helm install backend ci-dessus.

  --set seedJob.enabled=true \
  --set secrets.SEED_ADMIN_PASSWORD='<12+ caractères>'

Un helm upgrade ne relance jamais le seed. Pour créer l'admin après coup, réinstaller la release ou lancer /app/seed à la main dans un Pod du backend.

Migrations

migrationJob.enabled (défaut true) exécute backend/migrations (embarquées dans l'image) en hook pre-install/pre-upgrade. migrate up est idempotent : on peut le laisser actif à chaque upgrade. Le Secret du backend est lui aussi un hook (pre-install/pre-upgrade) pour exister avant ce Job ; helm uninstall ne le supprime donc pas.

Stockage des médias

Par défaut (MEDIA_STORAGE_DRIVER=local) les uploads et les pièces de vérification sont sur deux PVC ReadWriteOnce (persistence.uploads, persistence.verification, classe longhorn-replicated). Cela impose 1 seul replica (défaut : replicaCount: 1, autoscaling.enabled: false, stratégie Recreate). Passer à S3 (MEDIA_STORAGE_DRIVER=s3 + env.S3_* / secrets.S3_*) avant d'augmenter les replicas ou d'activer l'autoscaling.

Vérifier

helm lint charts/backend --set secrets.JWT_SECRET=x
helm lint charts/frontend
helm lint charts/ingressroute --set host=<host>

kubectl get certificate,pods,svc,ingressroute -n <ns>
curl -I https://<host>
S
Description
No description provided
Readme
2.1 MiB
Languages
TypeScript 50.8%
Go 43.2%
CSS 5.4%
Dockerfile 0.5%