[2026-09-23] hermes-docker-kraken: SSH контейнер→хост починен — passwd/group через bind-mount для uid 1000

This commit is contained in:
Alexey Martemyanov committed 2026-09-23 12:43:02 +06:00
1 parent d00c95d76b
commit a804c4a7cf
1 file changed
+48
+48
View File
@@ -267,6 +267,54 @@ USER kraken
**Открытый вопрос при применении:** второй вариант compose (с `config/.ssh → /root/.ssh`) — оставить
mount как есть и починить `$HOME`, или перевесить на `/opt/data/.ssh`? Alex ещё не решал.
## ✅ SSH контейнер → хост починен 2026-09-23 (passwd через bind-mount)
> **Симптом:** `docker exec hermes-kraken ssh kraken-host "…"` → `No user exists for uid 1000`. Старые доки называли это «passwd сбрасывается» — на деле причина глубже, см. ниже.
>
> **Проверенный диагноз (сырьё):**
> - Контейнер стартует под **uid 1000**, заданным `USER` в образе (`ps -o uid,pid,cmd` → PID 1 = `tini` под uid 1000). В compose строки `user:` НЕ было.
> - `/etc/passwd` образа создаёт только `hermes:x:10000` (`RUN useradd -u 10000 -m -d /opt/data hermes` в Dockerfile). Записи для uid 1000 **нет**.
> - `ssh` падает на `getpwuid(euid)` **до** чтения `~/.ssh/config` и ключа → пересоздание ключа не помогает.
> - `/etc/passwd` принадлежит `root:root`, процесс uid 1000 → `touch /etc/passwd` = `Permission denied`. **Записать запись изнутри контейнера невозможно.** Оригинальный `entrypoint.sh` поэтому и оборачивал всё в `if [ "$(id -u)" = "0" ]`, а `gosu hermes` / `usermod` / `chown` для uid 1000 не выполняются вообще.
> - `.ssh` монтировался в `/root/.ssh` (недоступен под uid 1000, `HOME=/opt/data`) — ключи до SSH не доезжали.
>
> **Фикс (2 файла, пересборки образа НЕ требует → версия Hermes не меняется):**
>
> 1. Создать копию passwd/group с записью для uid 1000:
> ```bash
> cd /srv/dev-disk-by-uuid-49e8f586-.../docker/hermes/config
> sudo docker exec hermes-kraken cat /etc/passwd > /tmp/passwd.new
> printf 'kraken:x:1000:1000::/opt/data:/bin/sh\n' >> /tmp/passwd.new
> sudo docker exec hermes-kraken cat /etc/group > /tmp/group.new
> printf 'kraken:x:1000:\n' >> /tmp/group.new
> sudo cp /tmp/passwd.new etc-passwd && sudo cp /tmp/group.new etc-group
> sudo chown root:root etc-passwd etc-group && sudo chmod 644 etc-passwd etc-group
> ```
> 2. В `hermes-build/docker-compose.yml`:
> ```yaml
> user: "1000:1000" # явно, раньше приходило из USER образа
> volumes:
> - …/docker/hermes/config/etc-passwd:/etc/passwd:ro
> - …/docker/hermes/config/etc-group:/etc/group:ro
> - …/docker/hermes/config/.ssh:/opt/data/.ssh # было /root/.ssh — мимо $HOME
> ```
> 3. Пересоздать: `docker compose up -d` (⚠️ **не** `--force-recreate`) — контейнер создан вручную, compose конфликтует по имени.
>
> **Приёмка (проверено 2026-09-23):**
> ```bash
> ssh kraken 'sudo docker exec hermes-kraken sh -c "getent passwd 1000; ssh kraken-host \"id; echo OK\""'
> # → kraken:x:1000:1000::/opt/data:/bin/sh
> # → uid=1000(kraken) ... OK
> ```
>
> **Питфоллы:**
> - `chown`/`cp` в `hermes-build/` и `docker/hermes/config/` требуют `sudo` — каталог принадлежит `root`, обычный `cp` даёт `Permission denied`.
> - `docker compose up -d --force-recreate` падает с `Conflict. The container name "/hermes-kraken" is already in use` — контейнер создан вне compose-проекта. Использовать `docker rm -f hermes-kraken` + `compose up -d`, либо просто `compose up -d`.
> - Правка `entrypoint.sh` (добавить `printf … >> /etc/passwd`) **не работает** — файл root-owned, запись пропускается на `[ -w /etc/passwd ]`.
> - `useradd` в контейнере тоже невозможен по той же причине.
> - `etc-passwd` — **статичный снимок** passwd образа. При смене базового образа (новые uid) файл надо пересоздать.
> - Не путать «контейнер поднялся, но внутри своя ошибка» с гонкой docker↔mount (см. `personal/tech/docker-data-root-mount-race.md`).
## Notes
- `network_mode: host` — port 8642 is directly on the Kraken host, no port mapping needed