chart 0.3.0: AddonClaim FUERA del chart Helm (ADR-066 del IDP)
Bug en chart 0.2.x: AddonClaim era Helm hook pre-install,pre-upgrade weight -10 SIN hook-delete-policy. El default Helm 3 es before-hook-creation → borra el claim en cada upgrade → finalizer cleanup-logical rotaba credenciales + atoraba release en pending-upgrade. Cambios: - helm/APP_NAME/templates/addonclaim.yaml eliminado. - manifests/addonclaim.yaml creado con placeholders sed. - scripts/pre-helm-detach.sh idempotente para migracion v1.0.0 → 1.1.0. - .gitea/workflows/APP_NAME-build.yaml: 2 nuevos steps detach + apply AddonClaim entre kubeconfig y helm upgrade. - Chart.yaml bump 0.2.0 → 0.3.0. - README reescrito (3 pasos workflow + tabla hooks sin AddonClaim + seccion Por que FUERA del chart + opt-out actualizado). - Comentarios stale del AddonClaim como hook -10 limpiados en networkpolicy.yaml, role-db-secret-reader.yaml, job-alembic-upgrade.yaml. ADR-066 del IDP documenta la decision arquitectural completa.
This commit is contained in:
84
README.md
84
README.md
@@ -26,7 +26,11 @@ tenant, los placeholders en mayúsculas se sustituyen automáticamente.
|
||||
│ ├── pyproject.toml
|
||||
│ ├── requirements.txt
|
||||
│ └── Dockerfile
|
||||
├── helm/__APP_NAME__/ ← Helm chart con AddonClaim + hook Alembic
|
||||
├── helm/__APP_NAME__/ ← Helm chart (Deployment, Job Alembic, NP, RBAC)
|
||||
├── manifests/
|
||||
│ └── addonclaim.yaml ← AddonClaim fuera del chart (ADR-066)
|
||||
├── scripts/
|
||||
│ └── pre-helm-detach.sh ← migración v1.0.0 → v1.1.0 (idempotente)
|
||||
└── .gitea/workflows/ ← CI: tests + build + deploy
|
||||
```
|
||||
|
||||
@@ -48,30 +52,57 @@ tenant, los placeholders en mayúsculas se sustituyen automáticamente.
|
||||
|
||||
---
|
||||
|
||||
## Orden de hooks Helm
|
||||
## Orden de aplicación — AddonClaim + hooks Helm
|
||||
|
||||
El workflow del tenant sigue este orden en cada `git push`:
|
||||
|
||||
| Paso | Acción | Motivo |
|
||||
|------|--------|--------|
|
||||
| 1 | `bash scripts/pre-helm-detach.sh` | Migración chart 1.0.0 → 1.1.0: si el AddonClaim tiene labels/annotations de un release Helm previo, las quita. Idempotente: skip si no aplica. Sunset tras ~2 semanas. |
|
||||
| 2 | `kubectl apply -f manifests/addonclaim.yaml` (con `sed` para placeholders) | Crea o actualiza el `AddonClaim`. Idempotente. `addon-provisioner` empieza a reconciliar en paralelo. |
|
||||
| 3 | `helm upgrade --install <release> ./helm/<APP_NAME> --wait --timeout 7m` | Aplica el chart Helm. Los hooks `pre-install,pre-upgrade` corren en orden de `hook-weight` (ver tabla abajo). El Job Alembic espera al Secret. |
|
||||
|
||||
El chart usa hooks `pre-install,pre-upgrade` con `hook-weight` para garantizar
|
||||
el orden de creación. El `helm upgrade --install` funciona **sin `--no-hooks`**:
|
||||
el orden de creación de SUS recursos (sin AddonClaim — ese vive fuera).
|
||||
`helm upgrade --install` funciona **sin `--no-hooks`**:
|
||||
|
||||
| Recurso | Template | `hook-weight` | Motivo |
|
||||
|---------|----------|---------------|--------|
|
||||
| `AddonClaim` | `addonclaim.yaml` | `-10` | Declara la intención de la app de tener una BD — el primero en aplicarse para que `addon-provisioner` empiece a reconciliar lo antes posible |
|
||||
| `NetworkPolicy` | `networkpolicy.yaml` | `-8` | Bajo el `default-deny` del namespace `apps`, esta NP permite DNS + apiserver + addons:3306. Debe existir antes que el InitContainer del Job Alembic intente conectarse al apiserver. |
|
||||
| `Role` + `RoleBinding` | `role-db-secret-reader.yaml` | `-7` | Permite al SA leer el Secret `<APP_NAME>-db-creds` (lo consume el InitContainer `wait-for-secret` del Job Alembic) |
|
||||
| `ServiceAccount` | `serviceaccount.yaml` | `-5` | Lo referencia el pod del Job Alembic — debe existir antes |
|
||||
| `Job` Alembic | `job-alembic-upgrade.yaml` | `0` | InitContainer `wait-for-secret` espera al Secret publicado por `addon-provisioner` (hasta 240s), luego corre `alembic upgrade head` |
|
||||
|
||||
El `AddonClaim` (hook weight `-10`) NO declara `hook-delete-policy` intencionalmente:
|
||||
así sobrevive entre `helm upgrade` (re-apply idempotente) y se evita disparar el
|
||||
finalizer `cleanup-logical` del controller en cada upgrade (que dropearía el
|
||||
user de la BD y regeneraría el password, causando ventana de downtime).
|
||||
Trade-off: `helm uninstall` deja el AddonClaim huérfano y MariaDB sigue
|
||||
aprovisionada. Es coherente con `deletionPolicy: Retain` — borrar BD productiva
|
||||
debe ser decisión explícita, no side-effect del uninstall. Cleanup explícito:
|
||||
### Por qué el `AddonClaim` vive FUERA del chart (ADR-066)
|
||||
|
||||
En chart 0.2.x el `AddonClaim` era hook `pre-install,pre-upgrade` weight `-10`.
|
||||
El default de Helm 3 (`hook-delete-policy: before-hook-creation`) borraba el
|
||||
claim previo antes de aplicar el nuevo en cada `helm upgrade --install`. El
|
||||
finalizer `addon-provisioner.idp.coralware.cloud/cleanup-logical` ejecutaba
|
||||
entonces `REVOKE` + `DROP USER` + delete del Secret en cada upgrade → rotación
|
||||
involuntaria de credenciales + release atorado en `pending-upgrade`.
|
||||
|
||||
Convertir el `AddonClaim` a manifest principal del chart (no hook) también
|
||||
falla: los hooks `pre-install,pre-upgrade` corren ANTES del manifest principal,
|
||||
así que el Job Alembic intentaría leer el Secret antes de que el AddonClaim
|
||||
exista — chicken-and-egg fatal.
|
||||
|
||||
La solución es desacoplar el lifecycle del CRD del lifecycle del release Helm:
|
||||
el `AddonClaim` lo aplica el workflow con `kubectl apply` (idempotente, sin
|
||||
ownership Helm), y Helm gobierna sólo la app + sus hooks Alembic/NP/RBAC.
|
||||
|
||||
`helm uninstall` no toca el AddonClaim — desacoplamiento garantizado.
|
||||
Borrar la BD lógica es decisión explícita:
|
||||
|
||||
```bash
|
||||
kubectl delete addonclaim <release>-db -n apps
|
||||
```
|
||||
|
||||
(Con `deletionPolicy: Retain` — default — preserva la BD lógica; el operador
|
||||
emite Event `OrphanLogicalDatabase`. Cambiar a `Delete` previo para `DROP DATABASE`.)
|
||||
|
||||
### Por qué el ServiceAccount es hook
|
||||
|
||||
El `ServiceAccount` se materializa como hook (no en la fase principal de Helm)
|
||||
porque el Job Alembic, que también es hook, declara `serviceAccountName`. Si el
|
||||
SA viviera en la fase principal se crearía **después** del Job → el pod del Job
|
||||
@@ -108,28 +139,33 @@ claves `DATABASE_URL` / `DATABASE_HOST` / `DATABASE_PORT` / `DATABASE_NAME` /
|
||||
`DATABASE_USER` / `DATABASE_PASSWORD` (y opcionalmente `MIGRATION_DATABASE_URL`).
|
||||
|
||||
El Secret lo materializa automáticamente la plataforma vía el flujo
|
||||
`AddonClaim` → `addon-provisioner` (ADR-052 + ADR-064):
|
||||
`AddonClaim` → `addon-provisioner` (ADR-052 + ADR-064 + ADR-066):
|
||||
|
||||
1. El chart aplica `helm/__APP_NAME__/templates/addonclaim.yaml` como hook
|
||||
`pre-install,pre-upgrade` weight `-10` — declara `addonType: mariadb`,
|
||||
`databaseName` derivado del Release name y el `secretName` esperado.
|
||||
1. El workflow del tenant aplica `manifests/addonclaim.yaml` con
|
||||
`kubectl apply -f -` (placeholders sustituidos con `sed`). El claim declara
|
||||
`addonType: mariadb`, `databaseName` derivado del nombre del release y el
|
||||
`secretName` esperado.
|
||||
2. `addon-provisioner` (corriendo en el plano de control IDP) reconcilia el
|
||||
`AddonClaim`: crea una BD lógica + user + grant en la instancia MariaDB
|
||||
compartida del tenant (ns `addons` del cluster tenant) vía Job DDL efímero.
|
||||
3. Publica el Secret `__APP_NAME__-db-creds` en el ns `apps`.
|
||||
4. El InitContainer `wait-for-secret` del Job Alembic espera al Secret (hasta
|
||||
240s), Alembic ejecuta `upgrade head`, y el Deployment rola.
|
||||
4. El workflow corre `helm upgrade --install`. El InitContainer
|
||||
`wait-for-secret` del Job Alembic (hook `pre-install,pre-upgrade`) espera al
|
||||
Secret (hasta 240s), Alembic ejecuta `upgrade head`, y el Deployment rola.
|
||||
|
||||
### Opt-out — apps stateless
|
||||
|
||||
Si tu app no necesita BD, en `values.yaml`:
|
||||
Si tu app no necesita BD:
|
||||
|
||||
```yaml
|
||||
database:
|
||||
enabled: false # no se aplica AddonClaim ni Role/RoleBinding
|
||||
alembic:
|
||||
enabled: false # no corre el Job Alembic
|
||||
```
|
||||
1. En `values.yaml`:
|
||||
```yaml
|
||||
database:
|
||||
enabled: false # no se aplica Role/RoleBinding al SA
|
||||
alembic:
|
||||
enabled: false # no corre el Job Alembic
|
||||
```
|
||||
2. Elimina el step "Aplicar AddonClaim" del workflow `.gitea/workflows/__APP_NAME__-build.yaml`
|
||||
(junto con `manifests/addonclaim.yaml` y el step `pre-helm-detach`).
|
||||
|
||||
Con `database.enabled=false` la app se despliega sin BD ni migraciones.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user