first commit

This commit is contained in:
Xor290
2026-09-20 12:10:35 +02:00
parent 3091fb4020
commit af77f3b19a
+125
View File
@@ -0,0 +1,125 @@
# 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
```bash
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)
```bash
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`.
```bash
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.
```bash
--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
```bash
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>
```