diff --git a/workloads/docs-portal/docs/arquitectura/sesion-tmux-persistente.md b/workloads/docs-portal/docs/arquitectura/sesion-tmux-persistente.md index 5f9f81e..5025b55 100644 --- a/workloads/docs-portal/docs/arquitectura/sesion-tmux-persistente.md +++ b/workloads/docs-portal/docs/arquitectura/sesion-tmux-persistente.md @@ -54,18 +54,79 @@ docker run -d \ --name tmux-host \ --restart unless-stopped \ -v /DATA:/DATA \ + -v /media/HDD-Storage:/media/HDD-Storage \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /DATA/AppData/k3d-lab-v3/claude-code-home:/root/.claude \ --network host \ - alpine sh -c "apk add --no-cache tmux docker-cli bash curl git kubectl nodejs npm && npm install -g @anthropic-ai/claude-code && tail -f /dev/null" + alpine sh -c "apk add --no-cache tmux docker-cli bash curl git kubectl nodejs npm && npm install -g @anthropic-ai/claude-code && git config --global --add safe.directory '*' && tail -f /dev/null" ``` | Volumen | Destino | Por qué | |---|---|---| | `/DATA` | `/DATA` | Acceso a los repos (`apps-registry`, `platform-infra`, `scripts`) y configs del lab, mismos paths que en el host | +| `/media/HDD-Storage` | `/media/HDD-Storage` | Ver "Gotcha: el symlink `/DATA/AppData`" abajo — sin esto, los repos no se ven dentro del contenedor pese a montar `/DATA` | | `/var/run/docker.sock` | `/var/run/docker.sock` | Seguir controlando Docker y k3d (contenedores, `k3d node`, etc.) desde dentro del contenedor | | `/DATA/AppData/k3d-lab-v3/claude-code-home` | `/root/.claude` | Persistir login/config de Claude Code — sobrevive no solo a un `docker restart`, sino a recrear el contenedor entero | +## Gotcha: el symlink `/DATA/AppData` + +Montar `-v /DATA:/DATA` **no alcanza** para ver los repos dentro del +contenedor. `/DATA/AppData` en el host es un symlink *absoluto*: + +``` +/DATA/AppData -> /media/HDD-Storage/AppData +``` + +Los repos del lab (`lab-cruzcloud`) viven físicamente en el disco +btrfs `/media/HDD-Storage`, no en el ext4 de `/DATA` — ZimaOS lo +expone dentro de `/DATA` como submount (`/DATA/.media/HDD-Storage/...`, +que sí viaja al contenedor porque Docker hace bind recursivo por +defecto) pero el path "bonito" `/DATA/AppData/...` que usan `CLAUDE.md` +y todos los scripts del lab llega ahí vía ese symlink absoluto, no vía +el submount. Un symlink absoluto que apunta fuera del árbol montado +queda roto dentro del contenedor aunque el submount subyacente esté +perfectamente accesible por otra ruta. + +**Cómo se detectó:** todo el trabajo de configuración inicial de este +mismo setup se hizo con `git`/`docker exec` corriendo *en el host*, no +dentro del contenedor — nadie había probado `cd +/DATA/AppData/k3d-lab-v3/lab-cruzcloud` desde una sesión `lab` real +hasta que se preguntó explícitamente por esto. `ls` devolvía "No such +file or directory" pese a que el volumen de `/DATA` estaba montado y +"andando". + +**Fix:** montar también `-v /media/HDD-Storage:/media/HDD-Storage`, +para que el symlink resuelva exactamente igual que en el host. + +## Gotcha: git "dubious ownership" dentro del contenedor + +Con el mount anterior ya arreglado, `git status`/`git log` dentro del +contenedor fallan con: + +``` +fatal: detected dubious ownership in repository at '/media/HDD-Storage/...' +``` + +Los archivos en `/DATA`/`/media/HDD-Storage` pertenecen al usuario +`devops` del host (via samba), pero los procesos dentro del +contenedor corren como `root` (UID 0) — git, desde la versión que +introdujo la protección CVE-2022-24765, rechaza operar sobre un repo +cuyo dueño no coincide con el UID del proceso, a menos que el path +esté explícitamente marcado como seguro. + +**Fix:** `git config --global --add safe.directory '*'` dentro del +contenedor. El wildcard (en vez de listar cada repo) es intencional +acá: este contenedor ya tiene acceso root-equivalente al host vía el +volumen de `/var/run/docker.sock`, así que restringir `safe.directory` +por repo no suma aislamiento real. + +**Por qué está en el comando de arranque y no como paso manual +aparte:** igual que los paquetes `apk`, esta configuración vive en el +filesystem efímero del contenedor (`/root/.gitconfig`, que no está +bajo el volumen de `/root/.claude`) — se perdería si el contenedor se +recrea. Ponerla en el `sh -c` de arranque la deja recreándose sola +cada vez, sin pasos manuales que recordar. + Sobre paquetes: alpine (imagen `alpine` sin pin de versión, la misma que uso este setup) sí trae `kubectl` en sus repos — no hizo falta cambiar de imagen base ni instalarlo por binario aparte, contrario a @@ -119,3 +180,10 @@ un archivo de prueba escrito en `/root/.claude` dentro del contenedor apareció de inmediato en `/DATA/AppData/k3d-lab-v3/claude-code-home` en el host, confirmando el bind mount de credenciales. + +Después de agregar el mount de `/media/HDD-Storage` y el +`safe.directory`, se validó además: `md5sum` de `CLAUDE.md` idéntico +leído desde el host y desde dentro del contenedor (vía el path con +symlink `/DATA/AppData/...`), y `git log`/`git status` corriendo sin +error sobre `apps-registry` y `scripts` desde una shell dentro de +`tmux-host`.