Files
scripts/README.md
T
2026-07-18 01:04:35 +00:00

742 lines
20 KiB
Markdown

# Laboratorio k3d estable para ZimaOS
Este paquete reemplaza el `deploy-lab.sh` original por una versión idempotente y no destructiva.
## Qué corrige
- No elimina `lab-cluster` en cada ejecución.
- Crea el clúster solo cuando no existe.
- Usa `subnet: auto` para mantener IP internas estables tras reinicios.
- Conserva el datastore SQLite, certificados y token de K3s en `/DATA/AppData/k3d-lab/k3s/server`.
- Conserva los datos de `local-path-provisioner` fuera de los contenedores.
- Usa un token de clúster persistente.
- Mantiene fijos los puertos `46421`, `90` y `9443`.
- Valida que ZimaOS siga usando `192.168.68.61` antes de desplegar.
- Instala Argo CD con versión fijada y `server-side apply`.
- No crea el `argocd-manager` innecesario para desplegar en el mismo clúster.
- Crea RBAC de Headlamp y RBAC de solo lectura para la validación postdeploy.
- Regenera los archivos requeridos para los secrets de Gitea Actions.
- Instala opcionalmente un watchdog systemd para recuperar el clúster después del boot.
## Primera recuperación / creación
Ejecutar como el usuario `devops`, no con `sudo`:
```bash
chmod +x deploy-lab.sh
LAB_HOST_IP=192.168.68.61 \
./deploy-lab.sh bootstrap
```
Como Docker y k3d están actualmente vacíos, `bootstrap` creará un clúster nuevo. En ejecuciones posteriores iniciará y reconciliará el clúster existente.
## Validación
```bash
./deploy-lab.sh status
kubectl get nodes -o wide
kubectl get pods -A
kubectl get ingress -A
```
## Autostart después de reinicios
Ejecutar solamente después de que `bootstrap` termine correctamente:
```bash
sudo ./deploy-lab.sh install-autostart
```
Verificar:
```bash
systemctl status k3d-lab-ensure.timer --no-pager
journalctl -u k3d-lab-ensure.service -n 200 --no-pager
```
El timer se ejecuta 60 segundos después del arranque y posteriormente cada cinco minutos. El servicio intenta iniciar el clúster, regenera el kubeconfig y valida los tres nodos.
## Recuperación manual
```bash
./deploy-lab.sh recover
```
`recover` no crea ni elimina el clúster. Solo intenta iniciar uno existente y reconcilia Argo CD.
## Applications de Argo CD
Guarda los manifiestos `Application`, `ApplicationSet` o el `app-of-apps` en:
```text
/DATA/AppData/k3d-lab/bootstrap/
```
Al ejecutar nuevamente `bootstrap`, el script aplicará automáticamente todos los `.yaml` y `.yml` de ese directorio.
## Secrets para la validación postdeploy
Después de crear un clúster nuevo, se generan:
```text
/DATA/AppData/k3d-lab/gitea-actions-secrets/K8S_SERVER.txt
/DATA/AppData/k3d-lab/gitea-actions-secrets/K8S_CA_B64.txt
/DATA/AppData/k3d-lab/gitea-actions-secrets/K8S_TOKEN.txt
/DATA/AppData/k3d-lab/gitea-actions-secrets/K8S_TLS_SERVER_NAME.txt
```
Copia sus valores a los secrets equivalentes del repositorio `devops/apps-registry` en Gitea. No publiques el contenido de `K8S_TOKEN.txt`.
## Headlamp
Genera un token cuando sea necesario:
```bash
kubectl create token headlamp-admin -n headlamp
```
El script crea el RBAC, pero el Deployment/Ingress de Headlamp debe provenir del repositorio GitOps.
## Reset limpio
Solo cuando realmente quieras iniciar desde cero:
```bash
CONFIRM_RESET=DELETE-lab-cluster ./deploy-lab.sh reset
```
Antes de limpiar el estado, el script crea un archivo en:
```text
/DATA/AppData/k3d-lab/backups/
```
## Variables principales
```text
CLUSTER_NAME=lab-cluster
APP_DATA_PATH=/DATA/AppData/k3d-lab
KUBECONFIG_PATH=/DATA/.kube/config
LAB_HOST_IP=192.168.68.61
EXPECTED_HOST_IP=192.168.68.61
K3S_IMAGE=rancher/k3s:v1.35.5-k3s1
ARGOCD_VERSION=v3.2.0
```
Para aceptar conscientemente una IP distinta:
```bash
LAB_HOST_IP=192.168.68.X \
ALLOW_IP_CHANGE=true \
./deploy-lab.sh bootstrap
```
También deberás actualizar NPM y los secrets de Gitea Actions.
## Arranque automático reforzado v3
La versión v3 agrega:
- `subnet: auto` al crear el clúster para mantener IP estática por nodo.
- `restart=unless-stopped` solamente a los contenedores de `lab-cluster`.
- Dependencias systemd sobre el `DockerRootDir` real y `APP_DATA_PATH`.
- Inicio 90 segundos después del boot.
- Reintento automático del servicio cada 30 segundos si falla.
- Watchdog cada 5 minutos.
- Regeneración del kubeconfig.
- Recuperación de agentes `NotReady`.
- Re-registro automático de un agente persistentemente obsoleto.
- Validación de Traefik, Argo CD y el puerto HTTP publicado.
### Instalar
```bash
LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh bootstrap
sudo LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh install-autostart
```
### Prueba de reinicio
Antes:
```bash
./deploy-lab.sh status
systemctl status k3d-lab-ensure.timer --no-pager
systemctl cat k3d-lab-ensure.service
systemctl cat docker.service
```
Después del reboot, espera hasta 10 minutos y valida:
```bash
systemctl status k3d-lab-ensure.service --no-pager
journalctl -b -u k3d-lab-ensure.service --no-pager
./deploy-lab.sh status
curl -I -H 'Host: argocd.cruzcloud.net' http://127.0.0.1:90
curl -I -H 'Host: shop.cruzcloud.net' http://127.0.0.1:90
```
## Corrección v3.1 para ZimaOS
ZimaOS puede no incluir el comando `openssl`. El script ya no lo exige:
1. Usa `openssl` cuando está disponible.
2. Si no, usa `/dev/urandom` con `od`.
3. Como último fallback, usa `hexdump`.
Para crear o recuperar el laboratorio, no uses `sudo sh`:
```bash
LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh bootstrap
```
Solo la instalación de systemd requiere sudo:
```bash
sudo LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh install-autostart
```
## Corrección v3.2: rollout de Argo CD
- `argocd-server` solo se reinicia cuando `server.insecure` cambia.
- El timeout específico de Argo CD aumenta a 420 segundos.
- Si el rollout falla, el script muestra Pods y eventos.
- Si la réplica nueva ya está disponible y únicamente queda un Pod antiguo
atascado en `Terminating`, elimina solo ese Pod antiguo y reintenta.
- No fuerza la eliminación cuando todavía no existe una réplica nueva disponible.
Ejecución:
```bash
LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh bootstrap
```
## Corrección v3.3: permisos de credenciales Gitea Actions
La generación de credenciales ya no ejecuta `chmod` sobre todos los `.txt`
históricos. Cada archivo se genera temporalmente y se instala con:
- propietario: usuario que ejecuta `bootstrap`;
- grupo: grupo principal del usuario;
- permisos: `0600`.
Además se regenera `KUBE_CONFIG_DATA.txt` con un kubeconfig Base64 de
privilegios mínimos para `gitea-postdeploy-validator`, manteniendo
compatibilidad con el workflow anterior.
Para continuar:
```bash
LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh bootstrap
```
## Corrección v3.4: propietario sin asumir grupo `devops`
ZimaOS tiene al usuario `devops` con grupo principal `samba`; no existe
necesariamente un grupo llamado `devops`.
La v3.4:
- usa `chown devops` y no `chown devops:devops`;
- usa `install -o devops` sin forzar grupo para archivos privados;
- mantiene permisos `0700` en el directorio de secretos;
- mantiene permisos `0600` en credenciales y kubeconfigs;
- conserva el grupo existente del filesystem cuando solo cambia el propietario.
El grupo de la unidad systemd sigue obteniéndose dinámicamente con
`id -gn devops`, por lo que en ZimaOS será `samba`.
## Corrección v3.5: kubeconfig sin `current-context`
La v3.5 valida y corrige el kubeconfig antes de instalarlo:
- obtiene el kubeconfig directamente desde k3d;
- confirma que contenga al menos un contexto;
- activa explícitamente ese contexto;
- confirma que exista un API Server;
- instala `/DATA/.kube/config` con propietario `devops` y permisos `0600`;
- no depende de `.profile`;
- systemd continúa usando la ruta explícita de kubeconfig.
Reparación manual equivalente:
```bash
TMP_KUBECONFIG="$(mktemp)"
k3d kubeconfig get lab-cluster > "$TMP_KUBECONFIG"
CTX="$(KUBECONFIG="$TMP_KUBECONFIG" kubectl config get-contexts -o name | head -1)"
KUBECONFIG="$TMP_KUBECONFIG" kubectl config use-context "$CTX"
sudo install -d -m 0700 -o devops /DATA/.kube
sudo install -m 0600 -o devops "$TMP_KUBECONFIG" /DATA/.kube/config
rm -f "$TMP_KUBECONFIG"
```
## Corrección v3.6: systemd en ZimaOS sin `/usr/local/sbin`
ZimaOS no garantiza que `/usr/local/sbin` exista o sea escribible. La v3.6
instala la copia persistente del script en:
```text
/DATA/AppData/k3d-lab/bin/deploy-k3d-lab
```
La unidad usa Bash explícitamente:
```ini
ExecStart=/bin/bash /DATA/AppData/k3d-lab/bin/deploy-k3d-lab ensure
```
Esto también funciona cuando `/DATA` tiene la opción de montaje `noexec`.
Instalación:
```bash
sudo LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh install-autostart
```
## Corrección v3.7: watchdog systemd sin `sudo`
El servicio se ejecuta como `devops` y no dispone de una terminal para
introducir la contraseña de sudo. La v3.7 elimina `sudo` del camino de
ejecución del modo `ensure`.
Cambios:
- comprueba escritura en `/DATA/AppData/k3d-lab`, no en la raíz `/DATA`;
- regenera `/DATA/.kube/config` directamente como `devops`;
- prepara propietario y permisos durante `install-autostart`;
- no intenta iniciar Docker mediante sudo desde systemd;
- muestra automáticamente `systemctl status` y `journalctl` si la prueba
inicial del servicio falla.
Instalación:
```bash
sudo LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh install-autostart
```
## Corrección v3.8: PATH de systemd y ubicación de k3d
La shell interactiva de ZimaOS puede encontrar `k3d` en una ruta bajo
`/DATA`, mientras systemd utiliza un PATH mínimo. La v3.8:
- localiza automáticamente `k3d`, `kubectl`, `docker` y `curl`;
- agrega los directorios detectados al PATH de la unidad;
- guarda las rutas en `/etc/default/k3d-lab`;
- permite indicar rutas explícitas con `K3D_BIN`, `KUBECTL_BIN`,
`DOCKER_BIN` y `CURL_BIN`;
- muestra el PATH efectivo al terminar.
Instalación normal:
```bash
sudo LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh install-autostart
```
Fallback explícito:
```bash
K3D_BIN="$(command -v k3d)" \
KUBECTL_BIN="$(command -v kubectl)" \
DOCKER_BIN="$(command -v docker)" \
CURL_BIN="$(command -v curl)" \
sudo -E LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh install-autostart
```
# Bootstrap GitOps completo v4.0
La versión v4.0 agrega dos piezas al laboratorio:
1. **App-of-Apps**
- Aplica `root-apps-registry`.
- Fuente: `https://gitea.cruzcloud.net/devops/apps-registry.git`.
- Revisión: `main`.
- Ruta: `apps`.
- Espera las ocho Applications existentes en el repositorio.
- Informa cuáles siguen `Progressing`, `OutOfSync` o `Degraded`.
2. **Gitea Actions runner persistente**
- Contenedor: `gitea-runner`.
- Registro persistente: `/DATA/AppData/k3d-lab/gitea-runner/data/.runner`.
- Monta `/var/run/docker.sock`.
- Política `unless-stopped`.
- Etiqueta compatible con `runs-on: ubuntu-latest`.
- El servicio systemd también valida y recupera el runner.
## Primera adopción del runner existente
Primero confirma que no haya un workflow activo y ejecuta:
```bash
MIGRATE_EXISTING_RUNNER=true ./deploy-lab.sh runner
```
El script:
- detecta la imagen actual;
- copia `/data` desde el contenedor existente;
- guarda `.runner` fuera del contenedor;
- recrea `gitea-runner` con el volumen persistente;
- no requiere un token nuevo si `.runner` pudo recuperarse.
## Runner desde cero
Obtén un token desde Gitea:
```text
apps-registry -> Settings -> Actions -> Runners
```
Guárdalo sin mostrarlo:
```bash
sudo install -d -m 0700 -o devops /DATA/AppData/k3d-lab/secrets
sudo sh -c 'umask 077; cat > /DATA/AppData/k3d-lab/secrets/gitea-runner-registration-token'
```
Pega únicamente el token y finaliza con `Ctrl+D`. Después:
```bash
sudo chown devops /DATA/AppData/k3d-lab/secrets/gitea-runner-registration-token
sudo chmod 0600 /DATA/AppData/k3d-lab/secrets/gitea-runner-registration-token
./deploy-lab.sh runner
```
El token solo se utiliza para generar `/data/.runner`. El contenedor permanente no conserva el token de registro como variable de entorno.
## Repositorio privado de Argo CD
Cuando `apps-registry` sea privado, crea:
```bash
sudo sh -c 'umask 077; printf "%s\n" "devops" > /DATA/AppData/k3d-lab/secrets/argocd-repo-username'
sudo sh -c 'umask 077; cat > /DATA/AppData/k3d-lab/secrets/argocd-repo-password'
```
Pega un token de Gitea con lectura del repositorio y finaliza con `Ctrl+D`.
```bash
sudo chown devops /DATA/AppData/k3d-lab/secrets/argocd-repo-username
sudo chown devops /DATA/AppData/k3d-lab/secrets/argocd-repo-password
sudo chmod 0600 /DATA/AppData/k3d-lab/secrets/argocd-repo-*
```
## Aplicar solo GitOps al clúster actual
```bash
./deploy-lab.sh gitops
```
## Reconstrucción completa
```bash
LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh bootstrap
```
El orden es:
```text
k3d -> Argo CD -> repositorio Gitea -> root-apps-registry
-> Applications hijas -> RBAC postdeploy -> Gitea runner
```
## Reinstalar systemd
```bash
sudo LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh install-autostart
```
## Verificación
```bash
kubectl get applications.argoproj.io -n argocd
docker ps --filter name=gitea-runner
docker logs --tail 100 gitea-runner
```
# Caché Git persistente v4.1
La versión v4.1 no recrea `root-apps-registry` como fuente principal.
Antes de aplicar GitOps:
1. clona `apps-registry` cuando no existe;
2. ejecuta `git fetch --prune` cuando ya existe;
3. alinea la copia local con `origin/main`;
4. valida `application.yaml` y la carpeta `apps/`;
5. aplica `application.yaml` directamente desde el clon;
6. registra el commit utilizado;
7. conserva el clon en `/DATA` para una recuperación cuando Gitea esté
temporalmente fuera de servicio.
Ruta:
```text
/DATA/AppData/k3d-lab/git/apps-registry
```
Commit utilizado:
```text
/DATA/AppData/k3d-lab/git/apps-registry.commit
```
## Actualizar únicamente el clon
```bash
./deploy-lab.sh repo-sync
```
## Actualizar el clon y reconciliar Argo CD
```bash
./deploy-lab.sh gitops
```
## Reconstrucción desde cero
```bash
LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh bootstrap
```
El `bootstrap` intenta obtener primero la última versión de `main`. Cuando
Gitea no responde y ya existe un clon válido, utiliza el commit cacheado y
permite que Argo CD vuelva a reconciliarse cuando Gitea regrese.
El watchdog no hace `git fetch` cada cinco minutos por defecto. Solo usa el
clon para restaurar `root-apps-registry` si desaparece. Argo CD sigue siendo
el encargado de observar Git y desplegar cambios durante la operación normal.
Para actualizar el clon también durante `ensure`:
```bash
APP_REGISTRY_REFRESH_ON_ENSURE=true \
sudo LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh install-autostart
```
No se recomienda en el valor predeterminado porque haría una consulta a
Gitea en cada ejecución del watchdog.
# Corrección v4.2: descubrimiento dinámico y monitoring
## Applications esperadas
La lista ya no está codificada manualmente. El script descubre el
`metadata.name` real de cada `Application` dentro de:
```text
/DATA/AppData/k3d-lab/git/apps-registry/apps/
```
Esto evita falsos errores cuando el nombre real es, por ejemplo,
`monitoring-governance` y no `monitoring-governance-app`.
También se puede seguir forzando una lista explícita:
```bash
EXPECTED_GITOPS_APPS="ecommerce-app,monitoring-app" ./deploy-lab.sh gitops
```
## Diagnóstico de kube-prometheus-stack
```bash
./deploy-lab.sh monitoring-diagnose
```
El comando muestra:
- versión del chart;
- estado Sync/Health;
- operación de Argo CD;
- mensaje del hook;
- Jobs y Pods admission-create/admission-patch;
- eventos recientes;
- condiciones de la Application.
Para chart `58.2.1` o `58.2.2`, usa como mínimo `58.3.3` y agrega:
```yaml
helm:
parameters:
- name: prometheusOperator.admissionWebhooks.patch.ttlSecondsAfterFinished
value: "60"
```
# Multi-repo y governance v4.3
La versión v4.3 incorpora el segundo repositorio GitOps:
```text
https://gitea.cruzcloud.net/devops/platform-infra.git
```
El repositorio contiene los overlays Kustomize utilizados por las
Applications `*-governance`.
## Cachés persistentes
```text
/DATA/AppData/k3d-lab/git/apps-registry
/DATA/AppData/k3d-lab/git/platform-infra
```
## Validación Kustomize
El script descubre en `apps-registry/apps/*.yaml` todas las Applications
cuyo `repoURL` apunta a `platform-infra`, valida que sus rutas existan y
ejecuta:
```bash
kubectl kustomize <ruta>
```
Los snapshots renderizados quedan en:
```text
/DATA/AppData/k3d-lab/rendered/platform-infra/
```
Durante un bootstrap se aplican antes de crear las Applications de workload.
Esto garantiza que Namespace, ResourceQuota, LimitRange y NetworkPolicy
estén presentes antes de instalar Helm charts.
## Contrato obligatorio de monitoring
`monitoring-governance` debe contener un `LimitRange`, porque su
`ResourceQuota` exige requests y limits de CPU y memoria.
Se incluyen archivos de referencia en:
```text
repo-patches/platform-infra/monitoring-governance/
├── limitrange.yaml
└── kustomization.yaml
```
Copia `limitrange.yaml` al repositorio `platform-infra` y agrega el recurso
a su `kustomization.yaml`.
## Sincronizar ambos repositorios
```bash
./deploy-lab.sh repo-sync
```
## Reconciliar GitOps completo
```bash
LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh gitops
```
## Reinstalar watchdog
```bash
sudo LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh install-autostart
```
# Recuperación de operación obsoleta de Grafana
Grafana puede funcionar mientras Argo CD mantiene una operación antigua,
por ejemplo target `58.3.3` con operación activa `58.2.1`.
```bash
./deploy-lab.sh monitoring-diagnose
./deploy-lab.sh monitoring-recover
```
La recuperación valida el LimitRange, termina la operación anterior,
elimina únicamente los Jobs admission temporales, ejecuta hard refresh,
sincroniza la revisión actual y espera `Synced/Healthy`.
Cuando `argocd` no está instalado en ZimaOS se usa temporalmente la imagen
oficial de Argo CD con `--core` y `/DATA/.kube/config`.
El manifiesto funcional está en:
```text
repo-patches/apps-registry/apps/monitoring-app.yaml
```
# Corrección v4.4.1: compatibilidad CLI Argo CD 3.2
`argocd app terminate-op` y `argocd app sync` no aceptan
`--app-namespace` en la versión usada por el laboratorio.
La función `argocd_core_cli` ahora ejecuta:
```bash
argocd app terminate-op monitoring-app --core
argocd app sync monitoring-app --core --async --prune --assumeYes
```
Las Applications del laboratorio residen en `argocd`, el namespace de
control de Argo CD.
# Corrección v4.4.2
Se corrigen dos comportamientos:
1. Cuando `monitoring-app` ya tiene:
- revisión de operación igual al target;
- fase `Succeeded`;
- estado `Synced/Healthy`;
el script termina correctamente y no inicia otra sincronización.
2. En modo `argocd --core`, el kubeconfig temporal fija el namespace
actual en `argocd`. Esto evita:
```text
configmap "argocd-cm" not found
```
El flujo intenta primero hard refresh y auto-sync. Solo llama
`argocd app sync --core` si Argo CD no inicia la reconciliación.
# Corrección v4.4.3: Gitea runner y restart storm
El watchdog se ejecuta como `devops`; no puede pedir una contraseña de
`sudo`. La v4.4.3:
- crea las rutas persistentes del Gitea runner durante `install-autostart`;
- elimina `sudo` del flujo `ensure -> ensure_gitea_runner`;
- cambia el servicio `oneshot` a `Restart=no`;
- deja los reintentos exclusivamente al timer de cinco minutos;
- limita fallos con `StartLimitIntervalSec=15min` y `StartLimitBurst=3`;
- agrega `Persistent=true` al timer.
Esto evita ciclos como:
```text
restart counter is at 645
sudo: a terminal is required
Failed to allocate directory watch: Too many open files
```
Instalación:
```bash
sudo systemctl stop k3d-lab-ensure.timer
sudo systemctl stop k3d-lab-ensure.service || true
sudo systemctl reset-failed k3d-lab-ensure.service
sudo LAB_HOST_IP=192.168.68.61 ./deploy-lab.sh install-autostart
```