Compare commits

..
Author SHA1 Message Date
devops 61c57fbf28 docs: corrige receta de tmux-host (symlink /DATA/AppData + git ownership)
El comando docker run documentado no funcionaba realmente desde
dentro del contenedor: /DATA/AppData es un symlink absoluto a
/media/HDD-Storage/AppData, que queda roto si solo se monta /DATA.
Agrega el mount que falta, el git safe.directory necesario (baked en
el arranque, no persiste en el volumen de credenciales), y documenta
ambos gotchas con como se detectaron.
2026-08-27 22:33:27 -05:00
devops a31a0d96b6 Merge fix/docs-sesion-tmux-persistente into main
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Failing after 7m38s
Build and Push Docs Portal / Escaneo de Secretos (Gitleaks) (push) Successful in 25s
Merge local directo (sin PR de Gitea) por acuerdo del usuario; ver
feedback_git_fix_branches en memoria del proyecto para el porque de
este flujo estandar.
2026-08-27 22:18:48 -05:00
@@ -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`.