first commit
This commit is contained in:
@@ -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>
|
||||
```
|
||||
Reference in New Issue
Block a user