[2026-09-23] eagle: family/how-to/hermes-docker-kraken.md personal/projects/personal-os/hermes-deployment-patterns.md
This commit is contained in:
1 parent
a804c4a7cf
commit
4f1b26fb45
2 files changed
+113
-70
No files matched your search
@@ -5,7 +5,7 @@ updated: '2026-09-23'
|
||||
type: tech
|
||||
namespace: personal
|
||||
tags: [hermes, docker, kraken, infra, how-to]
|
||||
status: active — план фикса uid 1000 согласован, НЕ применён
|
||||
status: active — SSH контейнер→хост РАБОТАЕТ (фикс uid 1000 применён 2026-09-23)
|
||||
related:
|
||||
- "[[tech/kraken-network]]"
|
||||
- "[[concepts/hermes-deployment-patterns]]"
|
||||
@@ -43,9 +43,12 @@ services:
|
||||
stdin_open: true
|
||||
tty: true
|
||||
restart: unless-stopped
|
||||
user: "1000:1000" # ← добавлено 2026-09-23 (было неявно из USER образа)
|
||||
volumes:
|
||||
- /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/docker/hermes/config:/opt/data
|
||||
- /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/docker/hermes/config/.ssh:/root/.ssh
|
||||
- /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/docker/hermes/config/.ssh:/opt/data/.ssh # ← было /root/.ssh
|
||||
- /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/docker/hermes/config/etc-passwd:/etc/passwd:ro
|
||||
- /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/docker/hermes/config/etc-group:/etc/group:ro
|
||||
- /home/kraken/obsidian:/vault:rw
|
||||
environment:
|
||||
- HERMES_ALLOW_ROOT_GATEWAY=1
|
||||
@@ -55,9 +58,13 @@ services:
|
||||
network_mode: host
|
||||
```
|
||||
|
||||
> ⚠️ **Обновлено 2026-09-23.** Ранее в доке был описан вариант с `build:` — **это устарело**. Сейчас compose тянет **готовый образ** `ghcr.io/mallexxx/hermes-kraken:latest` (собранный из `mallexxx/hermes-agent`, не upstream NousResearch). В compose **нет** строки `user:` — uid **1000 приходит из образа** (проверено: `tini` стартует под uid 1000).
|
||||
> ✅ **Обновлено 2026-09-23 — фикс применён, SSH работает.** Полный разбор — в разделе
|
||||
> «✅ SSH контейнер → хост починен 2026-09-23» ниже. Бэкап исходных файлов:
|
||||
> `/home/kraken/backups/hermes-uid1000-20260923-123803/`.
|
||||
>
|
||||
> ⚠️ **Третья точка монтирования:** `config/.ssh → /root/.ssh`. При `HOME=/opt/data` SSH этот путь **не читает**. См. раздел SSH ниже.
|
||||
> ⚠️ Ранее в доке был описан вариант с `build:` — **это устарело**. Сейчас compose тянет **готовый образ**
|
||||
> `ghcr.io/mallexxx/hermes-kraken:latest` (собранный из `mallexxx/hermes-agent`, не upstream NousResearch).
|
||||
> uid **1000** приходит из `USER` в образе; с 2026-09-23 он продублирован в compose явно.
|
||||
|
||||
## Managing the Container
|
||||
|
||||
@@ -107,9 +114,18 @@ ENTRYPOINT [ "/usr/bin/tini", "-g", "--", "/opt/hermes/docker/entrypoint.sh" ]
|
||||
| Host path | Container path | Purpose |
|
||||
|-----------|----------------|---------|
|
||||
| `hermes/config/` | `/opt/data` | `HERMES_HOME` — config, sessions, skills, memory |
|
||||
| `hermes/config/.ssh/` | `/root/.ssh` | ⚠️ SSH-ключи; при `HOME=/opt/data` **не читается** SSH |
|
||||
| `hermes/config/.ssh/` | `/opt/data/.ssh` | ✅ SSH-ключи — **перевешено 2026-09-23** (было `/root/.ssh`, при `HOME=/opt/data` не читалось) |
|
||||
| `hermes/config/etc-passwd` | `/etc/passwd` (ro) | ✅ создан 2026-09-23 — запись `kraken:x:1000` для uid контейнера |
|
||||
| `hermes/config/etc-group` | `/etc/group` (ro) | ✅ создан 2026-09-23 — `kraken:x:1000:` |
|
||||
| `/home/kraken/obsidian` | `/vault` | Obsidian vault read/write access |
|
||||
|
||||
> ℹ️ `etc-passwd`/`etc-group` — **статичные снимки** файлов образа + одна добавленная строка.
|
||||
> При смене базового образа (новые uid) их надо пересоздать:
|
||||
> ```bash
|
||||
> cd /srv/dev-disk-by-uuid-49e8f586-.../docker/hermes/config
|
||||
> sudo docker exec hermes-kraken cat /etc/passwd > /tmp/p && printf 'kraken:x:1000:1000::/opt/data:/bin/sh\n' >> /tmp/p && sudo cp /tmp/p etc-passwd
|
||||
> ```
|
||||
|
||||
## SSH из контейнера → хост (диагностика и фиксы)
|
||||
|
||||
> Перенесено из удалённого скилла `kraken-omv-maintenance` / `kraken-docker-ssh`. Актуальные пути и фиксы для случая, когда `ssh kraken-host` изнутри контейнера `hermes-kraken` не работает.
|
||||
@@ -117,18 +133,20 @@ ENTRYPOINT [ "/usr/bin/tini", "-g", "--", "/opt/hermes/docker/entrypoint.sh" ]
|
||||
**Архитектура (УТОЧНЕНО 2026-09-23 живой проверкой)**
|
||||
|
||||
```
|
||||
Container (hermes-kraken)
|
||||
uid=1000 gid=1000 ← из ОБРАЗА (USER), НЕ задан в compose
|
||||
Container (hermes-kraken) ← состояние ПОСЛЕ фикса 2026-09-23
|
||||
uid=1000 gid=1000 ← задан явно в compose (user: "1000:1000")
|
||||
HOME=/opt/data
|
||||
/etc/passwd содержит ТОЛЬКО: hermes:x:10000:10000::/opt/data:/bin/sh
|
||||
← записи для uid 1000 НЕТ ← КОРЕНЬ ПРОБЛЕМЫ
|
||||
config/.ssh смонтирован в /root/.ssh ← при HOME=/opt/data SSH его НЕ читает
|
||||
/opt/data/.ssh/ — есть authorized_keys, id_ed25519(600), known_hosts — но НЕТ config
|
||||
/etc/passwd — bind-mount из config/etc-passwd:
|
||||
hermes:x:10000:10000::/opt/data:/bin/sh
|
||||
kraken:x:1000:1000::/opt/data:/bin/sh ← ✅ добавлено 2026-09-23
|
||||
config/.ssh → /opt/data/.ssh ← ✅ перевешено с /root/.ssh
|
||||
/opt/data/.ssh/ — authorized_keys, id_ed25519(600), config, known_hosts, kraken-backup-push
|
||||
|
||||
Host (Kraken RPi5)
|
||||
User kraken (uid=1000) owns /home/kraken/.ssh/
|
||||
/home/kraken/.ssh/id_ed25519 — закрытый ключ (обязательно 600)
|
||||
/home/kraken/.ssh/authorized_keys — должен содержать публичный ключ
|
||||
/home/kraken/.ssh/authorized_keys — публичный ключ
|
||||
…/docker/hermes/config/etc-passwd + etc-group — root:root, 644 (bind-mount ro)
|
||||
```
|
||||
|
||||
**🔴 Симптом: `No user exists for uid 1000`**
|
||||
@@ -187,19 +205,36 @@ if [ "$(id -u)" = "0" ]; then ... exec gosu hermes "$0" "$@" ; fi
|
||||
7. Может быть несколько пар ключей: bind mount приносит хост-ключ, а агент может иметь свой в другом месте.
|
||||
8. Полный mount `/etc/ssh/` перезаписывает и host keys тоже.
|
||||
|
||||
**Диагностика по порядку**
|
||||
**Диагностика по порядку (актуальна и ПОСЛЕ фикса — для регрессий)**
|
||||
|
||||
```bash
|
||||
ssh kraken@<host> "echo OK && hostname" # доступен ли хост
|
||||
ssh kraken@<host> "sudo docker exec hermes-kraken id" # реальный uid
|
||||
ssh kraken@<host> "sudo docker exec hermes-kraken getent passwd 1000" # ← КЛЮЧЕВАЯ проверка, exit=2 = нет записи
|
||||
ssh kraken@<host> "sudo docker exec hermes-kraken getent passwd 10000"
|
||||
ssh kraken@<host> "sudo docker exec hermes-kraken ssh -o ConnectTimeout=5 -o BatchMode=yes kraken-host 'echo HELLO'" # ожидаем 'No user exists for uid 1000'
|
||||
ssh kraken@<host> "sudo docker exec hermes-kraken getent passwd 1000" # ← КЛЮЧЕВАЯ проверка; exit=2 = регрессия (mount отвалился)
|
||||
ssh kraken@<host> "sudo docker exec hermes-kraken ssh -o ConnectTimeout=5 -o BatchMode=yes kraken-host 'id; echo OK'" # приёмка
|
||||
ssh kraken@<host> "sudo docker exec hermes-kraken ls -lan /opt/data/.ssh" # ключ и права
|
||||
ssh kraken@<host> "ps -o uid,cmd -p \$(sudo docker inspect -f '{{.State.Pid}}' hermes-kraken)" # uid РЕАЛЬНОГО процесса (не exec!)
|
||||
ssh kraken@<host> "cd <compose dir> && sudo docker inspect hermes-kraken --format 'User=[{{.Config.User}}] Entrypoint={{.Config.Entrypoint}}'"
|
||||
ssh kraken@<host> "cd <compose dir> && sudo docker inspect hermes-kraken --format 'User=[{{.Config.User}}] Mounts={{range .Mounts}}{{.Destination}} {{end}}'"
|
||||
```
|
||||
|
||||
**🔁 Регрессия: что делать, если симптом вернулся**
|
||||
|
||||
Порядок проверки — по вероятности:
|
||||
|
||||
1. **Mount пропал** (чаще всего). `etc-passwd` не примонтирован → uid 1000 без записи.
|
||||
Проверить: `docker inspect hermes-kraken --format '{{range .Mounts}}{{.Destination}} {{end}}'` —
|
||||
должен быть `/etc/passwd`. Если нет — правку compose потеряли, вернуть строки и `compose up -d`.
|
||||
2. **Mount есть, но файл пустой/битый** — `config/etc-passwd` перезаписан или обрезан.
|
||||
Проверить хвост: `tail -3 .../docker/hermes/config/etc-passwd` → должна быть строка `kraken:x:1000…`.
|
||||
Лечится повторным созданием (команда в разделе Volumes).
|
||||
3. **Сменился uid контейнера** (например после `docker compose pull` нового образа с другим `USER`).
|
||||
Тогда строка в `etc-passwd` не совпадает с фактическим uid. Сверить `id` и `getent passwd`.
|
||||
4. **Сменился базовый образ** → `etc-passwd` устарел (в нём старый набор uid). Пересоздать из
|
||||
`docker exec … cat /etc/passwd` + добавить свою строку.
|
||||
|
||||
⚠️ **Порядок восстановления:** НЕ трогать ключи и НЕ пересоздавать образ — симптом `No user exists for
|
||||
uid N` всегда про passwd, никогда про ключ.
|
||||
|
||||
**Pitfalls**
|
||||
|
||||
- 🔴 **Главный:** uid, под которым стартует контейнер, ОБЯЗАН иметь запись в `/etc/passwd`. Иначе
|
||||
@@ -220,52 +255,31 @@ ssh kraken@<host> "cd <compose dir> && sudo docker inspect hermes-kraken --forma
|
||||
`sudo systemd-run --unit=<name> --collect --property=Type=oneshot chown -R ...`, потом проверять
|
||||
`systemctl is-active <name>`.
|
||||
|
||||
## ПЛАН: фикс uid 1000 (вариант A, согласован с Alex 2026-09-23)
|
||||
## ПЛАН: фикс uid 1000 — ⛔ ОТМЕНЁН 2026-09-23 (заменён рабочим решением)
|
||||
|
||||
> **Статус: СОГЛАСОВАН, НЕ ПРИМЕНЁН.** Alex выбрал вариант **A** — завести пользователя uid 1000 в образе.
|
||||
> **Статус: НЕ ПРИМЕНЁН И НЕ БУДЕТ ПРИМЕНЁН.** Оставлено для истории — почему отказались.
|
||||
|
||||
**Выбор:** A — заводим `kraken` с uid 1000 **в образе**; `user:` в compose не добавляем (uid 1000 уже
|
||||
идёт из `USER` в образе). Альтернатива **B** (убрать uid 1000, уйти на `hermes:10000`) отклонена, т.к.
|
||||
потребовала бы `chown -R` всего `/opt/data` на USB-диске (минуты, риск таймаута).
|
||||
**Что планировалось (вариант A):** завести `kraken` с uid 1000 **в образе** — правка `Dockerfile`
|
||||
(`RUN useradd -u 1000 … && USER kraken`), затем `docker compose build --no-cache` + пересоздание.
|
||||
|
||||
**Правка Dockerfile** — после `RUN useradd -u 10000 -m -d /opt/data hermes` добавить:
|
||||
```dockerfile
|
||||
RUN useradd -u 1000 -g 1000 -m -d /opt/data -s /bin/sh kraken \
|
||||
&& chown -R kraken:kraken /opt/data
|
||||
USER kraken
|
||||
```
|
||||
⚠️ Дополнительно проверить `USER` в базовом образе `ghcr.io/mallexxx/hermes-kraken:latest`: uid 1000 уже
|
||||
там, но **записи в passwd нет** — именно поэтому одно `useradd` (без согласования с `USER`) может
|
||||
не совпасть. После правки uid процесса и uid в passwd должны совпадать.
|
||||
**Почему отказались — три блокера, каждый проверен живьём:**
|
||||
|
||||
**Вторая часть фикса (SSH-конфиг).** `config/.ssh` монтируется в `/root/.ssh`, а процесс под 1000 с
|
||||
`HOME=/opt/data` → SSH его не читает, и `~/.ssh/config` отсутствует. Варианты (выбрать при применении):
|
||||
- либо перевесить mount на `/opt/data/.ssh`,
|
||||
- либо создать `config/.ssh/config` на хосте (тогда он приедет в `/root/.ssh`, но читаться не будет —
|
||||
можно дополнительно симлинкнуть или выставить `HOME`),
|
||||
- либо задать `-F /root/.ssh/config` явно.
|
||||
**Требует решения Alex при применении.**
|
||||
1. 🔴 **`docker compose build` некуда применить.** Compose тянет готовый
|
||||
`ghcr.io/mallexxx/hermes-kraken:latest` (`image:`, без `build:`). Локальный `Dockerfile` в
|
||||
`hermes-build/` её **не воспроизводит** (в нём нет `USER`, а uid 1000 приходит именно оттуда).
|
||||
Переключение на `build:` = подмена версии Hermes на другую ревизию → риск регрессии.
|
||||
2. 🔴 **В ветке про root: `entrypoint.sh` не спасает.** Вся логика `usermod`/`gosu`/`chown` обёрнута в
|
||||
`if [ "$(id -u)" = "0" ]`. Контейнер стартует под 1000 → ветка пропускается целиком.
|
||||
3. 🔴 **Запись в `/etc/passwd` изнутри невозможна.** Файл `root:root`, процесс uid 1000 →
|
||||
`touch /etc/passwd` = `Permission denied`. Ни `useradd`, ни `printf >> /etc/passwd` из
|
||||
`entrypoint.sh` не сработают (блок молча пропускался на `[ -w /etc/passwd ]`).
|
||||
|
||||
**Шаги (порядок как для боевых конфигов: коммит ДО → правка → заливка → ПРОВЕРКА → коммит ПОСЛЕ)**
|
||||
**Что сделали вместо — bind-mount passwd/group (без пересборки, версия Hermes не менялась).**
|
||||
Полный разбор и команды — в следующем разделе.
|
||||
|
||||
1. **Бэкап:** `Dockerfile`, `docker-compose.yml`, `.env`, `/etc/passwd` контейнера (`docker exec … cat /etc/passwd`)
|
||||
→ `/home/kraken/backups/hermes-uid-fix-20260923-<HHMMSS>/`.
|
||||
2. **Правка `Dockerfile`** (см. выше) — через локальную копию, залить обратно (не sed на удалённом хосте).
|
||||
3. **Пересборка + пересоздание:** `docker compose build` затем `up -d --force-recreate`.
|
||||
⚠️ Это **рестарт Hermes на Kraken** — нужен апрув Alex.
|
||||
⚠️ Образ сейчас тянется из **ghcr.io/mallexxx/hermes-kraken:latest** — уточнить, собирается ли он
|
||||
локально (`Dockerfile` в `hermes-build/`) или заливается в GHCR из другого места. Если GHCR — правку
|
||||
надо вносить в источнике сборки образа, иначе `docker compose pull` перезапишет фикс.
|
||||
4. **Проверка (приёмка — Alex запускает сам):**
|
||||
```bash
|
||||
sudo docker exec hermes-kraken id
|
||||
sudo docker exec hermes-kraken getent passwd 1000 # должен вернуть kraken:x:1000:1000
|
||||
sudo docker exec hermes-kraken ssh kraken-host 'id; echo OK' # ожидаем uid=1000(kraken) + OK
|
||||
```
|
||||
5. **Обновить эту доку** по факту применённого фикса (убрать «НЕ ПРИМЕНЁН», записать реальные пути).
|
||||
|
||||
**Открытый вопрос при применении:** второй вариант compose (с `config/.ssh → /root/.ssh`) — оставить
|
||||
mount как есть и починить `$HOME`, или перевесить на `/opt/data/.ssh`? Alex ещё не решал.
|
||||
**Урок:** при выборе «править Dockerfile vs обойти» сначала проверять, из чего реально запущен
|
||||
контейнер (`docker inspect --format '{{.Config.Image}}'` + есть ли `build:` в compose). Правка
|
||||
Dockerfile, который не участвует в сборке, — нулевой эффект.
|
||||
|
||||
## ✅ SSH контейнер → хост починен 2026-09-23 (passwd через bind-mount)
|
||||
|
||||
@@ -298,22 +312,42 @@ mount как есть и починить `$HOME`, или перевесить
|
||||
> - …/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 конфликтует по имени.
|
||||
> 3. Пересоздать:
|
||||
> ```bash
|
||||
> cd /srv/dev-disk-by-uuid-49e8f586-.../docker/hermes-build
|
||||
> sudo docker rm -f hermes-kraken && sudo docker compose up -d
|
||||
> # Порядок подтверждён рабочим 2026-09-23.
|
||||
> ```
|
||||
> ⚠️ `docker compose up -d --force-recreate` **падает** с
|
||||
> `Conflict. The container name "/hermes-kraken" is already in use` — контейнер создан вне
|
||||
> compose-проекта, поэтому compose не находит его как «свой». Поэтому и нужен явный `docker rm -f`.
|
||||
> ⚠️ `docker compose up -d` без `rm -f` в этой ситуации просто ничего не делает (контейнер уже есть).
|
||||
> 4. **Дополнительные монтирования** (проверено по факту):
|
||||
> `config/.ssh` при этом указывать на `/opt/data/.ssh`, а не `/root/.ssh`.
|
||||
>
|
||||
> **Приёмка (проверено 2026-09-23):**
|
||||
> **Приёмка (проверено 2026-09-23, Alex подтвердил: «ssh работает»):**
|
||||
> ```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
|
||||
> # → uid=1000(kraken) gid=1000(kraken) ... kraken ... HELLO_OK
|
||||
> ```
|
||||
>
|
||||
> **Результат:** SSH из контейнера `hermes-kraken` → хост Kraken работает без `-i` и без явных опций.
|
||||
> Ключи, права и конфиг трогать не потребовалось — только passwd/group и точка монтирования `.ssh`.
|
||||
>
|
||||
> **Что НЕ потребовалось (важно для будущих сессий):**
|
||||
> - Пересборка образа (`docker compose build`) — НЕ делалась, версия Hermes **не менялась**.
|
||||
> - Правка `Dockerfile` — НЕ делалась (см. отменённый план выше).
|
||||
> - Пересоздание/копирование ключей — НЕ делалось и не поможет (симптом не про ключ).
|
||||
>
|
||||
> **Питфоллы:**
|
||||
> - `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` в контейнере тоже невозможен по той же причине.
|
||||
> - `chown`/`cp` в `hermes-build/` и `docker/hermes/config/` требуют `sudo` — каталог принадлежит `root`, обычный `cp` даёт `Permission denied`. Это ловилось живьём при заливке compose.
|
||||
> - Правка `entrypoint.sh` (добавить `printf … >> /etc/passwd`) **не работает** — файл root-owned, запись молча пропускается на `[ -w /etc/passwd ]`. Блок остался в файле внутри контейнера как безвредный no-op; при пересоздании контейнера он и так исчезнет (файл берётся из образа). Копия исходника: `backups/hermes-uid1000-20260923-123803/entrypoint.sh`.
|
||||
> - `useradd` в контейнере тоже невозможен по той же причине (root-owned `/etc/passwd`).
|
||||
> - `etc-passwd` — **статичный снимок** passwd образа. При смене базового образа (новые uid) файл надо пересоздать.
|
||||
> - `/etc/group` тоже понадобился — без него `id` показывает `gid=1000` без имени группы.
|
||||
> - Не путать «контейнер поднялся, но внутри своя ошибка» с гонкой docker↔mount (см. `personal/tech/docker-data-root-mount-race.md`).
|
||||
> - 🔴 **Логи читать только из ТЕКУЩЕГО контейнера.** После `docker rm -f` старые ошибки (напр. Telegram `httpx.ConnectError`) остаются в буфере прошлого контейнера. Я процитировал их как актуальные — Alex опроверг: Telegram работал. Проверять `docker logs hermes-kraken 2>&1 | grep -ic <что>` на **новом** контейнере.
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
@@ -41,13 +41,22 @@ See [[claude-python-cli-proxy]] for full details and token-refresh procedure.
|
||||
|
||||
## Pattern 2: Kraken Docker (RPi5)
|
||||
|
||||
**Where:** Kraken RPi5, `docker run` (not compose)
|
||||
**Transport:** Zulip (same instance or separate)
|
||||
**Model backend:** Gemini or OpenRouter via Hermes gateway
|
||||
**Autostart:** `--restart unless-stopped` on the container
|
||||
**Where:** Kraken RPi5, `docker compose` из `docker/hermes-build/`
|
||||
(⚠️ ранее здесь было «`docker run`, not compose» — **это устарело**, проверено 2026-09-23)
|
||||
**Transport:** Zulip (same instance or separate)
|
||||
**Model backend:** Gemini or OpenRouter via Hermes gateway
|
||||
**Autostart:** `restart: unless-stopped` в compose
|
||||
|
||||
**Why docker run, not compose:** explicit restart behavior; avoids accidental
|
||||
`docker compose down` wipes. Config volume: `~/.hermes` on Kraken host.
|
||||
**Образ:** `ghcr.io/mallexxx/hermes-kraken:latest` (`image:`, **без** `build:`). uid процесса — **1000**
|
||||
(из `USER` в образе, продублирован в compose как `user: "1000:1000"`).
|
||||
Config volume: `…/docker/hermes/config` → `/opt/data` (`HERMES_HOME`).
|
||||
|
||||
⚠️ **Урок (2026-09-23), переносимый на любой Docker-деплой Hermes:** uid, под которым стартует
|
||||
контейнер, ОБЯЗАН иметь запись в `/etc/passwd`. Иначе `ssh`/`git` внутри контейнера падают с
|
||||
`No user exists for uid <N>` **до** чтения ключа. Записать запись изнутри нельзя (`/etc/passwd`
|
||||
root-owned) → либо bind-mount готового passwd, либо `useradd` в **Dockerfile**, если образ
|
||||
действительно собирается локально. Проверять `docker inspect --format '{{.Config.Image}}'` +
|
||||
наличие `build:` в compose **до** правки Dockerfile. Подробности: [[tech/hermes-docker-kraken]].
|
||||
|
||||
See [[tech/hermes-docker-kraken]].
|
||||
|
||||
|
||||
Reference in new issue
Block a user