# 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 ```