# 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 /platform-backend: backend/ docker build -t /platform-frontend: frontend/ docker push /platform-backend: docker push /platform-frontend: ``` ## 2. Certificat : issuers (une seule fois) ```bash kubectl create secret generic cloudflare-api-token-vitrine -n cert-manager \ --from-literal=api-token='' 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 # Les mots de passe doivent être identiques ici et dans le backend ci-dessous. helm install postgresql charts/postgresql -n --set-string auth.password='' helm install redis charts/redis -n --set-string auth.password='' helm install backend charts/backend -n \ --set image.repository=/platform-backend \ --set image.tag= \ --set secrets.JWT_SECRET="$(openssl rand -base64 48)" \ --set secrets.DB_PASSWORD='' \ --set secrets.REDIS_PASSWORD='' \ --set env.MEDIA_LOCAL_BASE_URL=https:///uploads helm install frontend charts/frontend -n \ --set image.repository=/platform-frontend \ --set image.tag= helm install ingressroute charts/ingressroute -n --set 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= kubectl get certificate,pods,svc,ingressroute -n curl -I https:// ```