docs(deploy-memory): refonte split web/api 2 services
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
dd93249362
commit
985e817289
@ -30,18 +30,43 @@ Push git, le CI build + rollout auto (filter sur `landing/**`, `Dockerfile`,
|
|||||||
|
|
||||||
## 2. App SaaS (`app.rubis.arthurbarre.fr`)
|
## 2. App SaaS (`app.rubis.arthurbarre.fr`)
|
||||||
|
|
||||||
### Infra
|
**Architecture en 2 services** : nginx en frontal (web) + API Node interne.
|
||||||
- Deployment : `rubis-app` · Container : `app` · NodePort : `30110`
|
|
||||||
|
```
|
||||||
|
Traefik :443 → app.rubis.arthurbarre.fr:30110 → rubis-web (nginx)
|
||||||
|
├─ / → SPA static (try_files)
|
||||||
|
└─ /api/* → rubis-api (ClusterIP :3333)
|
||||||
|
```
|
||||||
|
|
||||||
|
### rubis-web — frontend (NodePort 30110, exposé)
|
||||||
|
- Image : `git.arthurbarre.fr/ordinarthur/rubis-web`
|
||||||
|
- Container : `web` (nginx-alpine + SPA Vite dist)
|
||||||
|
- Sert /assets/* (cache 1y immutable), / (SPA fallback try_files)
|
||||||
|
- Reverse-proxy /api/* → rubis-api.rubis.svc.cluster.local:3333
|
||||||
|
- Manifest : `k3s/app/web.yml`
|
||||||
|
- Workflow CI : `.gitea/workflows/deploy-web.yml`
|
||||||
|
- Source : `apps/web`, `packages/shared` + `apps/web/nginx.conf`
|
||||||
|
|
||||||
|
### rubis-api — backend (ClusterIP, interne uniquement)
|
||||||
|
- Image : `git.arthurbarre.fr/ordinarthur/rubis-api`
|
||||||
|
- Container : `api` (Node 22 + AdonisJS V7)
|
||||||
|
- Workers BullMQ dans le même process (cf. `start/queue.ts`)
|
||||||
- Init container `migrate` : `node ace.js migration:run --force` depuis
|
- Init container `migrate` : `node ace.js migration:run --force` depuis
|
||||||
`/app/apps/api/build` (idempotent)
|
`/app/apps/api/build` (idempotent)
|
||||||
- Sidecar Redis : Deployment `rubis-redis` (ClusterIP, PVC 1Gi local-path,
|
- Probes K3s sur `/api/v1/health`
|
||||||
backend BullMQ + cache)
|
- Manifest : `k3s/app/api.yml` (Deployment + Service ClusterIP + ConfigMap)
|
||||||
- Image : `git.arthurbarre.fr/ordinarthur/rubis-app`
|
- Workflow CI : `.gitea/workflows/deploy-api.yml`
|
||||||
- Domaine : https://app.rubis.arthurbarre.fr
|
- Source : `apps/api`, `packages/shared`
|
||||||
- Manifests : `k3s/app/{deployment.yml,service.yml,redis.yml}`
|
|
||||||
|
### rubis-redis — backend BullMQ + cache (ClusterIP)
|
||||||
|
- Image : `redis:7.4-alpine`
|
||||||
|
- PVC 1Gi local-path, AOF on, maxmemory 256mb allkeys-lru
|
||||||
|
- Manifest : `k3s/app/redis.yml`
|
||||||
|
- Re-déployé par le workflow API (path filter inclut `redis.yml`)
|
||||||
|
|
||||||
|
### Infra commune
|
||||||
|
- Domaine : https://app.rubis.arthurbarre.fr (DNS A 5413305619)
|
||||||
- Route Traefik : `~/dev/perso/proxmox/ansible/roles/traefik/templates/rubis-app.yml.j2`
|
- Route Traefik : `~/dev/perso/proxmox/ansible/roles/traefik/templates/rubis-app.yml.j2`
|
||||||
- Workflow CI : `.gitea/workflows/deploy-app.yml`
|
|
||||||
- Source : `apps/api`, `apps/web`, `packages/shared` (monorepo pnpm)
|
|
||||||
|
|
||||||
### Dépendances externes (déjà déployées)
|
### Dépendances externes (déjà déployées)
|
||||||
- **Postgres** : 10.10.10.3:5432, base `rubis_prod`, user `rubis`
|
- **Postgres** : 10.10.10.3:5432, base `rubis_prod`, user `rubis`
|
||||||
@ -66,25 +91,31 @@ kubectl --kubeconfig ~/dev/perso/proxmox/k3s/kubeconfig.yaml \
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Mise à jour
|
### Mise à jour
|
||||||
Push git, le CI build l'image (`Dockerfile.app`, multi-stage), apply les
|
Push git → un (ou les deux) workflow(s) CI se déclenchent selon les paths
|
||||||
manifests `k3s/app/`, set image, rollout auto. Filter sur `apps/**`,
|
modifiés. Build+rollout indépendants.
|
||||||
`packages/**`, `Dockerfile.app`, `k3s/app/**`.
|
|
||||||
|
|
||||||
### Particularités du Dockerfile.app
|
| Path modifié | Workflow déclenché |
|
||||||
- `node ace build` plante en CI avec `ERR_UNKNOWN_FILE_EXTENSION` car
|
|---|---|
|
||||||
|
| `apps/web/**`, `Dockerfile.web`, `k3s/app/web.yml` | deploy-web.yml |
|
||||||
|
| `apps/api/**`, `Dockerfile.api`, `k3s/app/api.yml`, `k3s/app/redis.yml` | deploy-api.yml |
|
||||||
|
| `packages/shared/**`, `pnpm-lock.yaml`, `tsconfig.base.json`, … | les deux |
|
||||||
|
|
||||||
|
### Particularités du Dockerfile.api
|
||||||
|
- `node ace build` plante avec `ERR_UNKNOWN_FILE_EXTENSION` car
|
||||||
`@poppinss/ts-exec` ne s'enregistre pas à temps avant l'import de
|
`@poppinss/ts-exec` ne s'enregistre pas à temps avant l'import de
|
||||||
`bin/console.ts`. **Solution** : on appelle ace via `tsx` (esbuild),
|
`bin/console.ts`. **Solution** : `pnpm exec tsx ace.js build
|
||||||
qui gère nativement les `.ts` → `pnpm exec tsx ace.js build --ignore-ts-errors`
|
--ignore-ts-errors` (tsx = esbuild, gère .ts nativement).
|
||||||
- `--ignore-ts-errors` car `tests/bootstrap.ts` référence un type généré
|
- `--ignore-ts-errors` car `tests/bootstrap.ts` référence un type généré
|
||||||
dans `.adonisjs/client/registry/schema.d.ts` qui arrive trop tard. Le
|
tardivement (`.adonisjs/client/registry/schema.d.ts`). Le typecheck
|
||||||
typecheck strict est exécuté côté CI séparément (`pnpm typecheck`).
|
strict est exécuté en CI séparée (`pnpm typecheck`).
|
||||||
- Vite build appelé directement (`pnpm exec vite build`) au lieu de
|
|
||||||
`pnpm build` qui fait `tsc -b && vite build` — le `tsc -b` plante sans
|
### Particularités du Dockerfile.web
|
||||||
cache `.tsbuildinfo` à cause de @tanstack/router-core.
|
- Vite build appelé directement (`pnpm exec vite build`) au lieu du
|
||||||
- SPA dist (`apps/web/dist`) copié dans `apps/api/build/public/` pour
|
script `tsc -b && vite build` qui plante sans cache `.tsbuildinfo` à
|
||||||
être servi par le static middleware AdonisJS. Une route wildcard
|
cause de @tanstack/router-core.
|
||||||
(`start/routes.ts`) sert `index.html` pour les chemins non-API → SPA
|
- nginx.conf inclut le upstream `rubis-api.rubis.svc.cluster.local:3333`.
|
||||||
routing TanStack Router.
|
Si on renomme le service API, c'est ici qu'il faut mettre à jour
|
||||||
|
(en plus du manifest).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -92,16 +123,28 @@ manifests `k3s/app/`, set image, rollout auto. Filter sur `apps/**`,
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
TAG=$(git rev-parse --short HEAD)
|
TAG=$(git rev-parse --short HEAD)
|
||||||
# Landing
|
# Landing (rubis.arthurbarre.fr)
|
||||||
docker build --platform linux/amd64 -t git.arthurbarre.fr/ordinarthur/rubis:$TAG .
|
docker build --platform linux/amd64 -t git.arthurbarre.fr/ordinarthur/rubis:$TAG .
|
||||||
docker push git.arthurbarre.fr/ordinarthur/rubis:$TAG
|
docker push git.arthurbarre.fr/ordinarthur/rubis:$TAG
|
||||||
kubectl --kubeconfig ~/dev/perso/proxmox/k3s/kubeconfig.yaml \
|
kubectl --kubeconfig ~/dev/perso/proxmox/k3s/kubeconfig.yaml \
|
||||||
-n rubis set image deploy/rubis rubis=git.arthurbarre.fr/ordinarthur/rubis:$TAG
|
-n rubis set image deploy/rubis rubis=git.arthurbarre.fr/ordinarthur/rubis:$TAG
|
||||||
# App
|
|
||||||
docker build --platform linux/amd64 -f Dockerfile.app -t git.arthurbarre.fr/ordinarthur/rubis-app:$TAG .
|
# App — web (frontend)
|
||||||
docker push git.arthurbarre.fr/ordinarthur/rubis-app:$TAG
|
docker build --platform linux/amd64 -f Dockerfile.web \
|
||||||
|
-t git.arthurbarre.fr/ordinarthur/rubis-web:$TAG .
|
||||||
|
docker push git.arthurbarre.fr/ordinarthur/rubis-web:$TAG
|
||||||
kubectl --kubeconfig ~/dev/perso/proxmox/k3s/kubeconfig.yaml \
|
kubectl --kubeconfig ~/dev/perso/proxmox/k3s/kubeconfig.yaml \
|
||||||
-n rubis set image deploy/rubis-app app=git.arthurbarre.fr/ordinarthur/rubis-app:$TAG
|
-n rubis set image deploy/rubis-web web=git.arthurbarre.fr/ordinarthur/rubis-web:$TAG
|
||||||
|
|
||||||
|
# App — api (backend)
|
||||||
|
docker build --platform linux/amd64 -f Dockerfile.api \
|
||||||
|
-t git.arthurbarre.fr/ordinarthur/rubis-api:$TAG .
|
||||||
|
docker push git.arthurbarre.fr/ordinarthur/rubis-api:$TAG
|
||||||
|
kubectl --kubeconfig ~/dev/perso/proxmox/k3s/kubeconfig.yaml \
|
||||||
|
-n rubis set image deploy/rubis-api api=git.arthurbarre.fr/ordinarthur/rubis-api:$TAG \
|
||||||
|
&& kubectl --kubeconfig ~/dev/perso/proxmox/k3s/kubeconfig.yaml \
|
||||||
|
-n rubis patch deploy/rubis-api --type=json \
|
||||||
|
-p="[{\"op\":\"replace\",\"path\":\"/spec/template/spec/initContainers/0/image\",\"value\":\"git.arthurbarre.fr/ordinarthur/rubis-api:$TAG\"}]"
|
||||||
```
|
```
|
||||||
|
|
||||||
⚠️ Cross-compile ARM Mac → linux/amd64 plante sur `@swc/core` au build de
|
⚠️ Cross-compile ARM Mac → linux/amd64 plante sur `@swc/core` au build de
|
||||||
@ -126,8 +169,9 @@ challenge LE).
|
|||||||
---
|
---
|
||||||
|
|
||||||
## Déjà fait — NE PAS refaire
|
## Déjà fait — NE PAS refaire
|
||||||
- Dockerfile (landing) + Dockerfile.app (app)
|
- Dockerfile (landing) + Dockerfile.web + Dockerfile.api (app split)
|
||||||
- Manifests `k3s/` (landing) + `k3s/app/` (app + Redis)
|
- nginx.conf (apps/web/nginx.conf) avec upstream rubis-api
|
||||||
|
- Manifests `k3s/` (landing) + `k3s/app/{api,web,redis}.yml`
|
||||||
- Routes Traefik `rubis.yml.j2` + `rubis-app.yml.j2`
|
- Routes Traefik `rubis.yml.j2` + `rubis-app.yml.j2`
|
||||||
- DNS OVH : A records `rubis` (id 5413044152) + `app.rubis` (id 5413305619)
|
- DNS OVH : A records `rubis` (id 5413044152) + `app.rubis` (id 5413305619)
|
||||||
- Repo Gitea + secrets CI (`KUBECONFIG`, `REGISTRY_PASSWORD`)
|
- Repo Gitea + secrets CI (`KUBECONFIG`, `REGISTRY_PASSWORD`)
|
||||||
@ -135,5 +179,6 @@ challenge LE).
|
|||||||
- Postgres : base `rubis_prod` + user `rubis` (10.10.10.3)
|
- Postgres : base `rubis_prod` + user `rubis` (10.10.10.3)
|
||||||
- MinIO : bucket `rubis-prod-invoices`
|
- MinIO : bucket `rubis-prod-invoices`
|
||||||
- Secret K3s `rubis-app-secrets` (APP_KEY, DB pwd, MinIO, Resend, Mistral)
|
- Secret K3s `rubis-app-secrets` (APP_KEY, DB pwd, MinIO, Resend, Mistral)
|
||||||
|
- ConfigMap `rubis-api-config` (env non-sensibles)
|
||||||
|
|
||||||
Les prochains `/deploy` font uniquement build + rollout via push git.
|
Les prochains `/deploy` font uniquement build + rollout via push git.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user