fix(deploy): init container migrate utilise build/ace.js (compilé)
All checks were successful
Build & Deploy App / build-and-deploy (push) Successful in 30s
All checks were successful
Build & Deploy App / build-and-deploy (push) Successful in 30s
Le pod plantait en Init:CrashLoopBackOff parce que le init container tournait depuis /app/apps/api avec \`node ace\` — qui charge le shim ace.js → bin/console.ts (TS source). Sans devDeps en runtime, pas de loader TS → ERR_UNKNOWN_FILE_EXTENSION. Fix : workingDir /app/apps/api/build + command \`node ace.js migration:run --force\`. build/ contient les .js compilés. Memory mise à jour pour documenter ce piège. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
f6776dd81c
commit
cc047013c6
@ -1,52 +1,139 @@
|
||||
# Deploy memory — rubis
|
||||
|
||||
## Infra
|
||||
- Namespace : `rubis`
|
||||
- Deployment : `rubis`
|
||||
- Container : `rubis`
|
||||
- NodePort : `30109`
|
||||
Ce repo contient **deux déploiements distincts** sur la même infra K3s,
|
||||
namespace `rubis` :
|
||||
|
||||
1. **Landing** statique (`rubis.arthurbarre.fr`) — image nginx-alpine.
|
||||
2. **App SaaS** (`app.rubis.arthurbarre.fr`) — image AdonisJS + React (V1).
|
||||
|
||||
Chacun a sa propre image, son propre Dockerfile, son propre workflow CI.
|
||||
|
||||
---
|
||||
|
||||
## 1. Landing (`rubis.arthurbarre.fr`)
|
||||
|
||||
### Infra
|
||||
- Deployment : `rubis` · Container : `rubis` · NodePort : `30109`
|
||||
- Image : `git.arthurbarre.fr/ordinarthur/rubis`
|
||||
- Domaine : https://rubis.arthurbarre.fr (sous-domaine **temporaire** — domaine définitif pas encore acheté)
|
||||
- Manifests : `k3s/` (namespace.yml, deployment.yml, service.yml)
|
||||
- Domaine : https://rubis.arthurbarre.fr (sous-domaine **temporaire** —
|
||||
domaine définitif `rubis-sur-l-ongle.fr` pas encore acheté)
|
||||
- Manifests : `k3s/{namespace,deployment,service}.yml`
|
||||
- Route Traefik : `~/dev/perso/proxmox/ansible/roles/traefik/templates/rubis.yml.j2`
|
||||
- Repo Gitea : https://git.arthurbarre.fr/ordinarthur/rubis (remote `gitea`)
|
||||
- Workflow CI : `.gitea/workflows/deploy.yml`
|
||||
- Source : `landing/` (servi par nginx)
|
||||
|
||||
## Mise à jour (à suivre pour les prochains /deploy)
|
||||
### Mise à jour
|
||||
Push git, le CI build + rollout auto (filter sur `landing/**`, `Dockerfile`,
|
||||
`k3s/{namespace,deployment,service}.yml`).
|
||||
|
||||
1. **Voie normale — push git, le CI build + rollout auto** :
|
||||
```bash
|
||||
git push gitea main
|
||||
```
|
||||
---
|
||||
|
||||
2. **Voie manuelle** (si Docker Desktop tourne sur le Mac) :
|
||||
```bash
|
||||
TAG=$(git rev-parse --short HEAD)
|
||||
docker build --platform linux/amd64 -t git.arthurbarre.fr/ordinarthur/rubis:$TAG .
|
||||
docker push git.arthurbarre.fr/ordinarthur/rubis:$TAG
|
||||
kubectl --kubeconfig ~/dev/perso/proxmox/k3s/kubeconfig.yaml \
|
||||
-n rubis set image deploy/rubis rubis=git.arthurbarre.fr/ordinarthur/rubis:$TAG
|
||||
kubectl --kubeconfig ~/dev/perso/proxmox/k3s/kubeconfig.yaml \
|
||||
-n rubis rollout status deploy/rubis
|
||||
```
|
||||
## 2. App SaaS (`app.rubis.arthurbarre.fr`)
|
||||
|
||||
3. Si changement route/domaine : `cd ~/dev/perso/proxmox/ansible && ansible-playbook playbooks/gateway.yml`
|
||||
### Infra
|
||||
- Deployment : `rubis-app` · Container : `app` · NodePort : `30110`
|
||||
- Init container `migrate` : `node ace.js migration:run --force` depuis
|
||||
`/app/apps/api/build` (idempotent)
|
||||
- Sidecar Redis : Deployment `rubis-redis` (ClusterIP, PVC 1Gi local-path,
|
||||
backend BullMQ + cache)
|
||||
- Image : `git.arthurbarre.fr/ordinarthur/rubis-app`
|
||||
- Domaine : https://app.rubis.arthurbarre.fr
|
||||
- Manifests : `k3s/app/{deployment.yml,service.yml,redis.yml}`
|
||||
- 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)
|
||||
|
||||
4. Vérif : `curl -I https://rubis.arthurbarre.fr`
|
||||
### Dépendances externes (déjà déployées)
|
||||
- **Postgres** : 10.10.10.3:5432, base `rubis_prod`, user `rubis`
|
||||
- **MinIO** : `minio.minio.svc.cluster.local:9000`, bucket
|
||||
`rubis-prod-invoices`, creds = root MinIO
|
||||
- **Redis** : interne au namespace `rubis`, pas de dépendance externe
|
||||
|
||||
## Quand le domaine définitif sera acheté
|
||||
### Secrets K3s (`rubis-app-secrets`)
|
||||
Posés une fois manuellement via `kubectl create secret generic` (jamais
|
||||
dans les manifests). Re-pose si rotation ou ajout :
|
||||
```bash
|
||||
kubectl --kubeconfig ~/dev/perso/proxmox/k3s/kubeconfig.yaml \
|
||||
-n rubis create secret generic rubis-app-secrets \
|
||||
--from-literal=APP_KEY=... \
|
||||
--from-literal=PG_PASSWORD=... \
|
||||
--from-literal=S3_ACCESS_KEY=... \
|
||||
--from-literal=S3_SECRET_KEY=... \
|
||||
--from-literal=RESEND_API_KEY=... \
|
||||
--from-literal=MISTRAL_API_KEY=... \
|
||||
--from-literal=REDIS_PASSWORD="" \
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
```
|
||||
|
||||
1. Créer le record A chez OVH (ou autre registrar) : `<nouveau-domaine>` → `51.38.62.199`
|
||||
2. Modifier la rule du fichier `~/dev/perso/proxmox/ansible/roles/traefik/templates/rubis.yml.j2` :
|
||||
`Host(\`<nouveau-domaine>\`)`
|
||||
3. Relancer le playbook `gateway.yml`
|
||||
4. (Optionnel) supprimer le record DNS `rubis.arthurbarre.fr` si plus utilisé
|
||||
### Mise à jour
|
||||
Push git, le CI build l'image (`Dockerfile.app`, multi-stage), apply les
|
||||
manifests `k3s/app/`, set image, rollout auto. Filter sur `apps/**`,
|
||||
`packages/**`, `Dockerfile.app`, `k3s/app/**`.
|
||||
|
||||
## Stack
|
||||
Landing statique, servie par **nginx:1.27-alpine** (Dockerfile à la racine, sert `public/`).
|
||||
Le rebuild est rapide (pas de bundler).
|
||||
### Particularités du Dockerfile.app
|
||||
- `node ace build` plante en CI avec `ERR_UNKNOWN_FILE_EXTENSION` car
|
||||
`@poppinss/ts-exec` ne s'enregistre pas à temps avant l'import de
|
||||
`bin/console.ts`. **Solution** : on appelle ace via `tsx` (esbuild),
|
||||
qui gère nativement les `.ts` → `pnpm exec tsx ace.js build --ignore-ts-errors`
|
||||
- `--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
|
||||
typecheck strict est exécuté côté CI séparément (`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
|
||||
cache `.tsbuildinfo` à cause de @tanstack/router-core.
|
||||
- SPA dist (`apps/web/dist`) copié dans `apps/api/build/public/` pour
|
||||
être servi par le static middleware AdonisJS. Une route wildcard
|
||||
(`start/routes.ts`) sert `index.html` pour les chemins non-API → SPA
|
||||
routing TanStack Router.
|
||||
|
||||
---
|
||||
|
||||
## Voie manuelle (debug, hors CI)
|
||||
|
||||
```bash
|
||||
TAG=$(git rev-parse --short HEAD)
|
||||
# Landing
|
||||
docker build --platform linux/amd64 -t git.arthurbarre.fr/ordinarthur/rubis:$TAG .
|
||||
docker push git.arthurbarre.fr/ordinarthur/rubis:$TAG
|
||||
kubectl --kubeconfig ~/dev/perso/proxmox/k3s/kubeconfig.yaml \
|
||||
-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 .
|
||||
docker push git.arthurbarre.fr/ordinarthur/rubis-app:$TAG
|
||||
kubectl --kubeconfig ~/dev/perso/proxmox/k3s/kubeconfig.yaml \
|
||||
-n rubis set image deploy/rubis-app app=git.arthurbarre.fr/ordinarthur/rubis-app:$TAG
|
||||
```
|
||||
|
||||
⚠️ Cross-compile ARM Mac → linux/amd64 plante sur `@swc/core` au build de
|
||||
l'app. Préférer pousser et laisser le CI Gitea (linux/amd64 natif).
|
||||
|
||||
Si changement route/domaine : `cd ~/dev/perso/proxmox/ansible && ansible-playbook playbooks/gateway.yml`. Penser à `sudo systemctl restart traefik`
|
||||
sur la gateway si un nouveau domaine ne récupère pas son cert ACME tout
|
||||
seul (le hot-reload de la dynamic config ne déclenche pas toujours le
|
||||
challenge LE).
|
||||
|
||||
---
|
||||
|
||||
## Quand le domaine définitif sera acheté (`rubis-sur-l-ongle.fr`)
|
||||
|
||||
1. Records DNS chez OVH : A `@`, A `app`, MX/SPF/DKIM pour Resend
|
||||
2. Modifier les rules dans `rubis.yml.j2` et `rubis-app.yml.j2` (Host)
|
||||
3. Replay `gateway.yml`
|
||||
4. Maj `MAIL_FROM_ADDRESS=relances@rubis-sur-l-ongle.fr` dans le secret
|
||||
5. (Optionnel) supprimer les A records `rubis.arthurbarre.fr` et
|
||||
`app.rubis.arthurbarre.fr` chez OVH
|
||||
|
||||
---
|
||||
|
||||
## Déjà fait — NE PAS refaire
|
||||
Dockerfile, manifests K3s, route Traefik (`rubis.yml.j2` + tâche dans `tasks/main.yml`),
|
||||
DNS OVH (A record `rubis.arthurbarre.fr` id 5413044152), repo Gitea + secrets CI
|
||||
(`KUBECONFIG`, `REGISTRY_PASSWORD`), namespace + secret registry K3s.
|
||||
- Dockerfile (landing) + Dockerfile.app (app)
|
||||
- Manifests `k3s/` (landing) + `k3s/app/` (app + Redis)
|
||||
- Routes Traefik `rubis.yml.j2` + `rubis-app.yml.j2`
|
||||
- DNS OVH : A records `rubis` (id 5413044152) + `app.rubis` (id 5413305619)
|
||||
- Repo Gitea + secrets CI (`KUBECONFIG`, `REGISTRY_PASSWORD`)
|
||||
- Namespace + secret registry K3s (`gitea-registry`)
|
||||
- Postgres : base `rubis_prod` + user `rubis` (10.10.10.3)
|
||||
- MinIO : bucket `rubis-prod-invoices`
|
||||
- Secret K3s `rubis-app-secrets` (APP_KEY, DB pwd, MinIO, Resend, Mistral)
|
||||
|
||||
Les prochains `/deploy` font uniquement build + rollout via push git.
|
||||
|
||||
@ -30,8 +30,11 @@ spec:
|
||||
initContainers:
|
||||
- name: migrate
|
||||
image: git.arthurbarre.fr/ordinarthur/rubis-app:latest
|
||||
workingDir: /app/apps/api
|
||||
command: ['node', 'ace', 'migration:run', '--force']
|
||||
# On exécute ace depuis build/ (compilé JS) — le shim ace.js de
|
||||
# /app/apps/api/ charge bin/console.ts (TS) qui n'a pas de loader
|
||||
# disponible en runtime sans devDeps.
|
||||
workingDir: /app/apps/api/build
|
||||
command: ['node', 'ace.js', 'migration:run', '--force']
|
||||
envFrom:
|
||||
- secretRef: { name: rubis-app-secrets }
|
||||
- configMapRef: { name: rubis-app-config }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user