Главная / Статьи

Запуск агента Hermes локально в Podman без рут-доступа с использованием Ollama на GPU AMD

Запуск агента Hermes локально и безопасно: Podman без прав root, одна монтируемая папка, внутренняя сеть, Ollama на GPU AMD с ROCm и единица systemd.

Издатель: REACTAPP.TOP20 мин чтения4524 слов

Источники: Run Hermes Agent Locally (and securely) with Ollama and Rootless Podman on Arch Linux

Использование ИИ-агента для работы с локальными записями в формате Markdown и Obsidian кажется простым, пока не возникает вопрос об доступе. Hermes Agent от Nous Research может выполнять команды терминала, редактировать файлы, запускать код и вызывать другие инструменты. Однако передача ему модели с указанием работать только с одной папкой не создаёт защитных барьеров, поскольку инструкция представляет собой лишь текст. Сама документация Hermes подтверждает это: параметр HERMES_WRITE_SAFE_ROOT защищает обычные инструменты редактирования файлов, но инструменты терминала всё равно могут обращаться ко всему, к чему имеет доступ учётная запись операционной системы, на которой запущен Hermes.

Приведённая ниже конфигурация размещает сам Hermes внутри Podman без прав root, рядом с сервером Ollama, который запускает локальную модель на GPU AMD. Hermes может редактировать только одну специально монтируемую папку. Все остальные элементы файловой системы хоста просто отсутствуют в пространстве имён контейнера, поэтому он не может туда попасть. Hermes официально поддерживает работу в контейнерах, сохраняет постоянное состояние в папке /opt/data и работает с самостоятельно размещёнными серверами инференса, такими как Ollama, через конечную точку, совместимую с OpenAI.

Инструкция была протестирована на EndeavourOS, производном от Arch. Команды установки необходимо адаптировать под другие дистрибутивы.

Установка Podman без прав root

На Arch или EndeavourOS установите Podman с помощью Pacman:

sudo pacman -Syu podman

Pacman может спросить, какой OCI-среда выполнения использовать, предлагая три варианта:

1) crun
2) krun
3) runc

Выбранный здесь вариант — первый:

1

Этот движок выполнения — crun. Это окупается позже, поскольку функция Podman «keep-groups», которая передаёт дополнительные группы хоста в контейнер без корня, работает с crun.

Подтвердите установку, выведя версию и спросив у Podman, какой движок выполнения он использует:

podman --version
podman info --format '{{.Host.OCIRuntime.Name}}'

Вторая команда должна вернуть имя во время выполнения:

crun

Контейнерам без корня также требуются подчинённые сопоставления UID и GID для пользователя, поэтому убедитесь, что соответствующие записи существуют в обоих файлах:

grep "^$USER:" /etc/subuid
grep "^$USER:" /etc/subgid

Отныне все команды Podman выполняйте от имени обычного пользователя. Не добавляйте к ним префикс sudo.

Восстановление rootless OverlayFS при необходимости

Первая попытка загрузки образа на этом устройстве завершилась ошибкой: ядро не поддерживает использование overlay на файловой системе ext:

kernel does not support overlay fs:
'overlay' is not supported over extfs

Когда это произойдёт, установите реализацию в пользовательском пространстве:

sudo pacman -S fuse-overlayfs

Podman рекомендует использовать fuse-overlayfs в средах без корня, где не доступен встроенный overlay, и его можно явно указать в качестве программы монтирования для таких сред. Проверьте, установлен ли он:

which fuse-overlayfs

Ожидаемый путь:

/usr/bin/fuse-overlayfs

Конфигурация хранится в файле для каждого пользователя:

~/.config/containers/storage.conf

Если он уже существует, отредактируйте его вместо того, чтобы слепо заменять. В разделе хранения необходимо выбрать драйвер оверлея:

[storage]
driver = "overlay"

Во втором разделе следует указать имя программы монтирования:

[storage.options.overlay]
mount_program = "/usr/bin/fuse-overlayfs"

Затем проверьте действующие настройки, отфильтровав вывод информации о отладке Podman:

podman info --debug | grep -Ei 'graphDriverName|mount_program|overlay'

Перенос хранилища на более большой диск

Для этого проекта эта мера стала необходимой практически сразу. Одна только образ-контейнер Ollama занимает несколько гигабайт, модели часто добавляют ещё от 5 до 20 ГБ или даже больше, а Podman также использует временное пространство диска во время загрузки и распаковки слоев. Первая попытка загрузки Ollama в итоге завершилась с ошибкой о недостатке места в папке внутри временного каталога:

write /var/tmp/container_images_storage...:
no space left on device

Здесь задействованы два отдельных местоположения, что легко упустить из виду. Постоянное хранилище без корневой директории для изображений, контейнеров и томов обычно находится в поддиректории home:

$HOME/.local/share/containers/storage

Загруженные слои временно хранятся в следующем месте:

/var/tmp

Изменение параметра --tmpdir в Podman не приводит к перемещению каталога загрузки. В документации Podman рекомендуется вместо этого использовать переменную окружения TMPDIR.

При наличии более объемной локальной файловой системы создайте структуру, в которой будет один каталог для хранения данных и один — для временных файлов:

/path/to/large-drive/podman/
├── storage/
└── tmp/

Создать оба элемента и передать права владения текущему пользователю:

sudo mkdir -p /path/to/large-drive/podman/storage
sudo mkdir -p /path/to/large-drive/podman/tmp
sudo chown -R "$USER:$USER" /path/to/large-drive/podman

Затем откройте настройки хранилища для редактирования:

mkdir -p ~/.config/containers
nano ~/.config/containers/storage.conf

Укажите корень графика на новый каталог хранения, сохраняя драйвер накладки:

[storage]
driver = "overlay"
graphroot = "/path/to/large-drive/podman/storage"

И сохраните настройку программы монтирования fuse-overlayfs:

[storage.options.overlay]
mount_program = "/usr/bin/fuse-overlayfs"

Выберите для этого локальную файловую систему. В документации Podman предупреждается, что NFS и другие сетевые файловые системы могут некорректно функционировать в качестве хранилища для контейнеров без прав root.

Временные загрузки также требуют переноса, поэтому укажите TMPDIR для текущей оболочки:

export TMPDIR=/path/to/large-drive/podman/tmp

Чтобы сделать это постоянным в Bash, добавьте его в профиль и перезагрузите его:

echo 'export TMPDIR=/path/to/large-drive/podman/tmp' >> ~/.bashrc
source ~/.bashrc

Проверьте новые местоположения перед тем, как удалять что-либо из старого. Выполните вывод корня дерева и отфильтруйте вывод отладки для временной директории и программы монтирования:

podman info --format 'GraphRoot: {{.Store.GraphRoot}}'
podman info --debug | grep -Ei 'graphRoot|imageCopyTmpDir|mount_program'

Только при свежей установке Podman и только тогда, когда новый корень графа определённо верен, следует рассмотреть возможность удаления заброшенных данных, хранящихся на старом месте:

~/.local/share/containers/storage

Не делайте этого бездумно на существующей установке. Именно поэтому место хранения следует определить заранее перед созданием тома модели Ollama.

Один папка для Hermes, два тома для состояния

Выберите единственный хост-каталог, к которому может обращаться Hermes, и сделайте это осознанно. Экспортируйте его путь в переменную и создайте папку:

export HERMES_WORKSPACE="$HOME/path/to/Hermes-Workspace"
mkdir -p "$HERMES_WORKSPACE"

В Obsidian хорошим вариантом является отдельная папка внутри хранилища, например, папка для исследований, расположенная рядом с личными и рабочими папками:

Obsidian Vault/
├── Personal/
├── Work/
├── Research/
└── Agent Workspace/       ← only this folder is exposed

Все остальное в хранилище остаётся невидимым для агента.

Далее создайте два тома, которыми будет управлять сам Podman:

podman volume create hermes-data
podman volume create ollama-models

Первый хранит конфигурацию, память и постоянное состояние Hermes. Второй хранит локальную модель. Ни тот, ни другой не требуют предоставления агенту дополнительных каталогов хоста.

Предоставление контейнеру доступа к GPU AMD

Эта настройка предназначена для AMD ROCm, а не для NVIDIA CUDA. На карте AMD не устанавливайте nvidia-container-toolkit — это был обходной путь, использовавшийся ранее до того, как была обнаружена ошибка. Инструкции Ollama для контейнеров используют образ ollama/ollama:rocm для GPU AMD и передают в контейнер два узла устройств:

/dev/kfd
/dev/dri

Проверьте, существуют ли они на хосте:

ls -l /dev/kfd
ls -l /dev/dri/render*

Затем посмотрите на группы учётной записи:

groups

Если учётная запись отсутствует в группах видео и рендеринга, добавьте её:

sudo usermod -aG video,render "$USER"

Затем полностью выйдите из системы и снова войдите. Повторная загрузка списка групп в том же старом терминале не покажет новых участников, что приводит к ненужным затруднениям:

groups

После нового входа в систему запустите его ещё раз:

groups

Теперь результат должен включать обе группы:

video render

Параметр --group-add keep-groups в Podman позже передаёт эти дополнительные группы в контейнер без корня, чтобы тот мог использовать устройства GPU.

Проверка устройства TUN

Ещё одна проблема возникла из-за сетевой среды без корня. Pasta, стандартный механизм сети без корня в Podman, сообщил о невозможности открыть устройство TUN:

pasta failed with exit code 1:
Failed to open() /dev/net/tun: No such device

Ищите узел устройства:

ls -l /dev/net/tun

Если его нет, загрузите модуль ядра:

sudo modprobe tun

Затем проверьте снова. Если команда modprobe сообщает, что модуль отсутствует для текущей версии ядра, и система недавно обновлялась, сравните версию текущего ядра с содержимым каталогов модулей:

uname -r
ls /usr/lib/modules/

В дистрибутивах с гибкой настройкой, таких как Arch, у устройства может по-прежнему работать старый ядро, модули которого были удалены во время обновления. Перезагрузите устройство и попробуйте снова.

Выбор локальной модели

Для карт с объемом VRAM около 16 ГБ Ollama в настоящее время рекомендует использовать gemma4 в качестве локальной модели для Hermes, а для систем с объемом около 24 ГБ можно рассмотреть модели вроде qwen3.6. В приведенном примере используется вариант gemma4 с 12 миллиардами параметров:

gemma4:12b

Храните его в переменной, настраивая модель под конкретное оборудование:

export HERMES_MODEL="gemma4:12b"

Другим важным показателем является длина контекста. Ollama по умолчанию настраивает GPU с объемом VRAM менее 24 ГБ только на контекст 4K, тогда как оба проекта рекомендуют минимум 64 000 токенов при использовании агентов. Это настраивается более подробно далее.

Загрузка изображений и модели

Требуются три изображения: обычное изображение Ollama, версия для ROCm и изображение Hermes:

podman pull docker.io/ollama/ollama:latest
podman pull docker.io/ollama/ollama:rocm
podman pull docker.io/nousresearch/hermes-agent:latest

Обычная версия Ollama обеспечивает однократную загрузку модели. Версия для ROCm служит постоянным сервером инференса от AMD.

Загрузите модель в её постоянный том с помощью временного контейнера. Сначала удаляйте любые устаревшие контейнеры:

podman rm -f ollama-bootstrap 2>/dev/null

Затем запустите программу загрузки с монтированным томом модели и ничем больше:

podman run -d \
  --name ollama-bootstrap \
  -v ollama-models:/root/.ollama \
  docker.io/ollama/ollama:latest

Если сетевая связь без root-доступа по-прежнему не работает, для этого временного загрузчика подойдёт сетевая связь хоста. Снова удалите контейнер:

podman rm -f ollama-bootstrap 2>/dev/null

Начните с сети хоста:

podman run -d \
  --network host \
  --name ollama-bootstrap \
  -v ollama-models:/root/.ollama \
  docker.io/ollama/ollama:latest

В этот контейнер не подключено никакое рабочее пространство Hermes. Загрузите модель через него:

podman exec -it ollama-bootstrap \
  ollama pull "$HERMES_MODEL"

Подтвердите с помощью списка:

podman exec ollama-bootstrap ollama list

Выбранный модель должен отобразиться:

gemma4:12b

Удалите временный контейнер. Модель останется в том же объеме:

podman rm -f ollama-bootstrap

Если Podman сообщает, что имя контейнера уже занято:

container name "ollama-bootstrap" is already in use

Не придумывайте новые имена. Лучше очистите устаревший контейнер:

podman rm -f ollama-bootstrap

или укажите флаг --replace.

Внутренняя сеть и под

В первом варианте проектирования сеть вообще не использовалась:

--network none

Это было изменено на специальный внутренний мост Podman. Hermes и Ollama получают общий пространство имен сети, в котором они могут взаимодействовать друг с другом, в то время как Podman ограничивает доступ извне. Опция --internal существует именно для ограничения внешнего доступа в сетях с мостом. Создайте её:

podman network create \
  --ignore \
  --internal \
  hermes-internal

Затем создайте под в той сети:

podman pod create \
  --name hermes-local \
  --network hermes-internal \
  --userns=keep-id:uid=10000,gid=10000

Параметр keep-id помещает учетную запись хоста с ограниченными правами в пространство имен пользователя контейнера, причем числа, которые она там получает, можно выбрать. Контейнер Hermes запускается с параметрами 10000:10000, именно поэтому и отображаются эти значения.

Запуск Ollama с ROCm

Здесь возникла одна из менее очевидных проблем. Команда, которая в итоге сработала, выглядит следующим образом:

podman run -d \
  --name ollama \
  --pod hermes-local \
  --device /dev/kfd \
  --device /dev/dri \
  --group-add keep-groups \
  -e HOME=/root \
  -e OLLAMA_MODELS=/root/.ollama/models \
  -e OLLAMA_CONTEXT_LENGTH=64000 \
  -v ollama-models:/root/.ollama \
  docker.io/ollama/ollama:rocm

Его линейки, предназначенные специально для AMD, следующие:

--device /dev/kfd
--device /dev/dri
--group-add keep-groups
ollama/ollama:rocm

В этой конфигурации Podman не следует опускать две переменные окружения:

HOME=/root
OLLAMA_MODELS=/root/.ollama/models

Причиной стало загадочное сбой. Модель была загружена корректно, файлы blobs и manifest существовали, а том был правильно подключен. Однако при перечислении моделей не было найдено ничего:

podman exec ollama ollama list

Лог-файл контейнера рассказал всю историю:

podman logs ollama

В нём показано, что Ollama использует корневой каталог файловой системы в качестве домашнего каталога, а путь к моделям определяется на его основе:

HOME=/
OLLAMA_MODELS=/.ollama/models

в то время как модель на самом деле находилась в:

/root/.ollama/models

Ollama формирует путь к своей стандартной модели из домашней директории плюс .ollama/models, если только переменная OLLAMA_MODELS не задаёт иной путь. Поэтому модель никогда не отсутствовала — Ollama просто искал её в неверном месте. Явное установление обеих переменных сразу же решило проблему:

HOME=/root
OLLAMA_MODELS=/root/.ollama/models

Теперь в описании должна отображаться модель:

podman exec ollama ollama list

Подтверждение использования GPU

Поищите в журнале записи, содержащие ROCm и информацию о GPU:

podman logs ollama 2>&1 | grep -Ei 'gpu|rocm|amd|gfx'

Рабочая конфигурация AMD определяет вычислительное устройство ROCm. Затем запускается краткий тестовый запрос, требующий от модели точного ответа:

podman exec -it ollama \
  ollama run gemma4:12b \
  "Reply with exactly: AMD GPU test successful"

Сразу после этого посмотрите на работающие модели:

podman exec ollama ollama ps

Два столбца заслуживают внимания:

PROCESSOR
CONTEXT

В идеале в столбце с процессором должна отображаться информация о GPU, а не о переносе нагрузки на CPU, причем контекст должен быть следующим:

64000

Сама Ollama рекомендует проверять список своих процессов, чтобы увидеть как выделенный контекст, так и процесс переноса данных. Модель, заявляющая о большом объеме нативного контекста, не обязательно получает на самом деле столько же ресурсов.

Запуск Hermes с одним монтированием

Теперь создайте контейнер Hermes внутри того же пода:

podman run -d \
  --name hermes \
  --pod hermes-local \
  --security-opt=no-new-privileges \
  --pids-limit 512 \
  -v hermes-data:/opt/data \
  -v "$HERMES_WORKSPACE:/opt/data/workspace:rw,nodev,nosuid" \
  -w /opt/data/workspace \
  docker.io/nousresearch/hermes-agent:latest \
  sleep infinity

Важно то, чего в нём не хватает. Ничего из этого не присутствует:

/:/host
/home:/home
~/.ssh
~/.config
Docker socket
Podman socket

Единственное произвольное привязывание хоста — это папка рабочего пространства, которая мапируется в каталог данных контейнера:

$HERMES_WORKSPACE
        ↓
/opt/data/workspace

Собственное состояние Hermes находится в указанном томе, который монтируется по его пути к данным:

hermes-data
        ↓
/opt/data

Официальный контейнер использует /opt/data для хранения постоянного состояния и автоматически устанавливает в него значение HERMES_WRITE_SAFE_ROOT. Этот механизм защиты от записи считается частью многократной защиты, а не основной сандбоксом, поскольку в документации Hermes предупреждается, что команды терминала могут обойти ограничения, связанные с работой с файлами. Настоящей границей является пространство имен файловой системы Podman.

Проверка границы монтирования

Ознакомьтесь с тем, что хост фактически предоставляет Hermes:

podman inspect hermes \
  --format '{{range .Mounts}}{{println .Type .Source "->" .Destination}}{{end}}'

Ожидайте две строки: одну для объема данных и одну для разрешенной папки:

Podman volume -> /opt/data
your allowed folder -> /opt/data/workspace

Домашняя директория и сокет container-runtime не должны отображаться. Проверьте сокет явно:

podman exec hermes sh -c \
  'test ! -S /var/run/docker.sock && echo "No Docker socket exposed"'

Можно также проверять пути, чувствительные к хосту, например, узнавать, виден ли каталог SSH:

podman exec hermes sh -lc \
  'test -e "$HOME/.ssh" && echo "SSH directory visible" || echo "Host SSH directory not visible"'

Помните, что у контейнера есть собственные системные каталоги. Их наличие — это нормально, поскольку они принадлежат контейнеру, а не хосту.

Hermes и Ollama

Оба контейнера используют общий сетевой пространство имён пода, поэтому они взаимодействуют через луп-бэк. Проверьте API Ollama, совместимое с OpenAI, изнутри контейнера Hermes:

podman exec hermes python -c \
'import urllib.request; print(urllib.request.urlopen("http://127.0.0.1:11434/v1/models").read().decode())'

Ответ должен быть в формате JSON, содержащем локальную модель. При первой попытке использовался heredoc в Python, но ничего не было выведено:

podman exec hermes python - <<'PY'
...
PY

Причина была проста. Python читает свою программу из stdin в таком формате, но команде podman exec не было указано подключить stdin. Добавление флага интерактивного режима позволяет версии с heredoc корректно работать:

podman exec -i hermes python - <<'PY'
import urllib.request
print(
    urllib.request.urlopen(
        "http://127.0.0.1:11434/v1/models"
    ).read().decode()
)
PY

Отсутствие этого флага стоило нескольких дополнительных минут.

Доказательство недоступности внешнего мира

Попробуйте загрузить внешний веб-сайт изнутри контейнера Hermes:

podman exec hermes python -c \
'import urllib.request; print(urllib.request.urlopen("https://example.com", timeout=5).read())'

Это должно сработать некорректно, и это сделано намеренно. Hermes может получить доступ к Ollama внутри контейнера, но сеть не предоставляет никакого нормального внешнего доступа.

Не паникуйте, если список контейнеров будет выглядеть так:

podman ps

показывает порт рядом с Ollama:

11434/tcp

Это не означает, что порт был опубликован на хосте. Опубликованный порт будет выглядеть примерно так:

0.0.0.0:11434->11434/tcp

В данной конфигурации нигде не используется -p 11434:11434.

Направление Hermes на локальный Ollama

Запустите настройку Hermes от имени пользователя контейнера в рабочей среде:

podman exec -it \
  --user 10000:10000 \
  -w /opt/data/workspace \
  hermes \
  hermes model

В списке поставщиков приведено множество облачных сервисов. Не выбирайте вариант облака:

Ollama Cloud

Вместо этого выберите ручное введение конечной точки:

Custom endpoint (enter URL manually)

Для базового URL используйте адрес обратной связи и путь v1:

http://127.0.0.1:11434/v1

Если требуется API-ключ, оставьте его пустым. В текущих инструкциях по интеграции Hermes от Ollama используется именно такой формат с пользовательским конечным пунктом и пустым ключом для локального сервера. При вопросах об совместимости API выберите вариант чат-комплетаций, совместимый с OpenAI. Для имени модели введите:

gemma4:12b

А что касается длины контекста:

64000

В документации поставщика Hermes говорится, что локальная версия Ollama должна использовать конечную точку v1 и требует как минимум 64 Кб контекста для рабочих процессов агентов, использующих инструменты.

Использование локального терминального бэкенда внутри контейнера

Сначала это может показаться странным. Обычно Hermes предупреждает о настройке локального терминального бэкенда:

terminal:
  backend: local

экзекутирует команды терминала непосредственно на том же компьютере, что и Hermes, без какой-либо изоляции. При прямой установке Hermes это могло бы быть опасно. Однако сам Hermes уже находится внутри Podman, поэтому локальный бэкенд соотносится с контейнером Hermes:

Hermes "local"
      ↓
Hermes container

а не к рабочей станции:

Hermes "local"
      ↓
your Arch workstation

Установите серверную часть:

podman exec --user 10000:10000 hermes \
  hermes config set terminal.backend local

А рабочая директория:

podman exec --user 10000:10000 hermes \
  hermes config set terminal.cwd /opt/data/workspace

Также стоит установить предпочтение в пользу режима домашнего экрана на основе профиля:

podman exec --user 10000:10000 hermes \
  hermes config set terminal.home_mode profile

Не настраивайте Docker-бэкенд Hermes для данной схемы. Это потребует предоставления Hermes доступа к среде выполнения контейнеров, что сводит на нет одно из основных принципов изоляции.

Запуск Hermes

Интерактивная сессия начинается с того же шаблона выполнения, что и при настройке:

podman exec -it \
  --user 10000:10000 \
  -w /opt/data/workspace \
  hermes \
  hermes

Для улучшения структуры заметок запрос может предложить Hermes просмотреть Markdown-заметки в рабочем пространстве, упорядочить структуру и заголовки, исправить форматирование и грамматику, сохранить все технические детали, команды, ссылки и викиссылки Obsidian в неизменном виде, а также никогда не удалять реальный контент лишь для того, чтобы сократить заметку. Изменения сохраняются непосредственно в папке единственного подключенного хоста.

Запуск среды при загрузке

Как только всё будет работать интерактивно, под должен будет автоматически восстанавливаться после перезагрузки без необходимости вручную запускать Ollama и Hermes. Создайте пользовательскую единицу systemd:

mkdir -p ~/.config/systemd/user
nano ~/.config/systemd/user/hermes-local.service

Этот раздел начинается с описания и строки с номером заказа:

[Unit]
Description=Hermes Local AI Pod
After=default.target

Режим обслуживания — это одноразовая операция, которая запускает под, останавливает его с 30-секундным периодом торможения и предоставляет две минуты на его повторный запуск:

[Service]
Type=oneshot
RemainAfterExit=yesExecStart=/usr/bin/podman pod start hermes-local
ExecStop=/usr/bin/podman pod stop -t 30 hermes-localTimeoutStartSec=120
TimeoutStopSec=60[Install]
WantedBy=default.target

Если корень графа Podman находится на отдельном диске, этот диск должен монтироваться надежно при загрузке системы, а не интерактивно после входа в рабочий стол. Можно добавить необязательную проверку монтирования ExecStartPre, адаптированную под конкретную файловую систему.

Перезагрузите systemd:

systemctl --user daemon-reload

Включите единицу измерения:

systemctl --user enable hermes-local.service

Начните его:

systemctl --user start hermes-local.service

И проверьте это:

systemctl --user status hermes-local.service

Поскольку речь идет о одноразовом сервисе с включенным параметром RemainAfterExit, такое состояние является нормальным:

Active: active (exited)

В Podman существует более современный механизм Quadlet для декларативного определения контейнеров в рамках systemd. Однако при наличии уже собранной и проверенной вручную среды минимальным вмешательством оказалось использование небольшой пользовательской службы, запускающей под, которая уже доказала свою работоспособность.

Чтобы пользовательская служба без прав root запускалась при загрузке системы ещё до входа в рабочий стол, включите опцию lingering:

sudo loginctl enable-linger "$USER"

Проверьте это:

loginctl show-user "$USER" -p Linger

Ожидаемый результат:

Linger=yes

Функция linger в Systemd позволяет менеджеру служб пользователя запускаться при загрузке системы и оставаться доступным вне обычных сессий входа. После перезагрузки список контейнеров будет выглядеть так:

podman ps

Здесь уже должен отображаться под с запущенными Ollama и Hermes. Интерактивная сессия Hermes всё равно запускается с помощью команды exec:

podman exec -it \
  --user 10000:10000 \
  -w /opt/data/workspace \
  hermes \
  hermes

Служба загрузки запускает среду. Она не открывает интерактивный чат.

Фактически возникшие проблемы

Здесь приведён краткий список возникших на пути сбоев, каждый с описанием проблемы и способом её решения.

Ошибка оверлея от ядра:

Problem:
kernel does not support overlay fs

Проблема была решена путем установки fuse-overlayfs и настройки его в качестве программы монтирования overlay:

Fix:
Install fuse-overlayfs and configure it as the overlay mount program.

Не хватает места во временной директории:

Problem:
no space left on device under /var/tmp

Требовались как перемещение корня графа там, где это уместно, так и настройка TMPDIR, поскольку флаг tmpdir в Podman — это отдельная вещь:

Fix:
Move Podman's graphroot if needed AND set TMPDIR.
Changing Podman's --tmpdir is not the same thing.

Конфликт имён у контейнера bootstrap:

Problem:
ollama-bootstrap name already in use

Проблема устраняется путем удаления устаревшего контейнера:

Fix:
podman rm -f ollama-bootstrap

Приложение Pasta не может открыть устройство TUN:

Problem:
pasta cannot open /dev/net/tun

Проблема устраняется путем загрузки модуля tun или перезагрузки, если установленные модули не совпадают с действующим ядром:

Fix:
sudo modprobe tun
If the installed modules don't match the running kernel, reboot.

Инструментарий NVIDIA, установленный на компьютере с процессором AMD:

Problem:
Installed nvidia-container-toolkit on an AMD machine

Это просто не следует делать — вместо этого используйте изображение ROCm с устройствами kfd и dri:

Fix:
Don't.
Use ollama/ollama:rocm with /dev/kfd and /dev/dri.

Новые участники группы в разделе видео и рендеринга, которые не отображались в списке групп:

Problem:
Added myself to video/render but `groups` still didn't show them

Необходимо выход из системы и вход заново, поскольку существующая сессия сохраняет свои первоначальные группы:

Fix:
Log out and back in.
The existing login session retains its original supplementary groups.

Файлы моделей и манифест присутствуют, в то время как список Ollama пуст:

Problem:
Ollama model files and manifest exist, but `ollama list` is empty

Диагностика осуществляется путем просмотра журнала, и если пути к домашней директории и моделям указывают на корень файловой системы, в то время как том монтируется внутри каталога пользователя root, необходимо явно установить обе переменные:

Fix:
Check:
podman logs ollamaIf Ollama is using:
OLLAMA_MODELS=/.ollama/modelswhile the volume is mounted under:
 /root/.ollamaset explicitly:
HOME=/root
OLLAMA_MODELS=/root/.ollama/models

Тест на Python от Hermes к Ollama, который бесшумно ничего не вывел:

Problem:
Hermes → Ollama Python test silently prints nothing

Проблема была устранена путем добавления флага интерактивного режима при использовании heredoc или простым использованием формы встроенной команды:

Fix:
If using `python -` with a heredoc, add `podman exec -i`.
Or simply use `python -c`.

Меню поставщика без очевидной локальной записи Ollama:

Problem:
The Hermes provider menu doesn't contain "local Ollama"

Проблема была решена путем выбора ручного пользовательского конечного точки и ввода локального URL версии v1:

Fix:
Choose:
Custom endpoint (enter URL manually)Then:
http://127.0.0.1:11434/v1

И Гермес жалуется на недостаточную ширину окна контекста, хотя всё остальное работало нормально:

Problem:
Everything works, but Hermes reports an inadequate context window

Проблема решается путем установки длины контекста с серверной стороны на 64000, настройки Hermes на то же значение и проверки фактического выделения памяти с помощью списка процессов Ollama:

Fix:
Set OLLAMA_CONTEXT_LENGTH=64000 server-side and configure Hermes for the same value.
Verify the real allocation with:
ollama ps

Где должна находиться граница доверия

Основной урок здесь не связан ни с Ollama, ни с ROCm. Речь идет о том, чтобы определить, где располагается граница доверия. Инструкция, запрещающая читать любые файлы вне определенной директории, представляет собой поведенческое указание. Контейнер Podman, в котором не предусмотрен доступ к остальной файловой системе хоста, служит границей операционной системы. Функция безопасного записи данных в корневую директорию у Hermes полезна, но сам Hermes считает ее дополнительным слоем, а не настоящей «песочницей», поскольку команды оболочки могут обойти механизмы защиты файлов.

В результате получаемая модель доверия складывает слои от самого слабого к самому сильному: начиная с ограничений, заданных через инструкции, и защиты от записи файлов в Hermes, и заканчивая границей контейнера:

Prompt restrictions
        ↓
Hermes file write protections
        ↓
Hermes container filesystem
        ↓
Rootless Podman user namespace
        ↓
Host filesystem permissions

Даже если модель получает злонамеренную инструкцию, скрытую в файле Markdown, интересный вопрос заключается не в том, будет ли она подчиняться первоначальному запросу, а в том, до чего на самом деле сможет добраться скомпрометированный агент. В данной конфигурации ответ намеренно ограничен.

Отладка по слоям

И Hermes, и Ollama быстро развиваются. Текущая документация Hermes поддерживает самостоятельно размещаемые конечные точки, совместимые с OpenAI, включая Ollama, но также поступали сообщения о поведении инструментов через пользовательские конечные точки Ollama. Если обычный чат работает, но Hermes, по-видимому, описывает вызовы инструментов без их выполнения, проверьте текущий трекер проблем Hermes, прежде чем предполагать, что среда Podman сбойна.

Именно поэтому необходимо тестировать всю стек-систему как цепочку вопросов: сначала проверяется, видит ли Podman GPU, затем — видит ли Ollama модель, и, наконец, может ли Hermes взаимодействовать с Ollama.

Does Podman see the GPU?
        ↓
Does Ollama see the model?
        ↓
Does Ollama actually use the GPU?
        ↓
Is the context really 64K?
        ↓
Can Hermes reach /v1/models?
        ↓
Can Hermes perform an actual file operation?
        ↓
Can Hermes reach anything it shouldn't?

Не пытайтесь отлаживать все шесть слоев одновременно.

Что даёт готовая настройка

Результатом такой конфигурации являются возможности локальных вычислений, ускорение с помощью GPU AMD, постоянная память Hermes и одно рабочее пространство хоста с возможностью записи:

Local inference                YES
AMD GPU acceleration           YES
Hermes persistent memory       YES
One writable host workspace    YES

Он не требует облачной модели, не открывает файловую систему хоста, не предоставляет сокеты Podman или Docker и не имеет обычного выхода в Интернет:

Cloud LLM required             NO
Host filesystem exposed        NO
Podman/Docker socket exposed   NO
Normal Internet egress         NO
Entire Obsidian vault exposed  NO

Это гораздо более удобный способ экспериментировать с мощным локальным агентом. У Hermes всё ещё достаточно прав на доступ, чтобы быть полезным. Просто он не может самостоятельно решать, что означает достаточный уровень доступа.