Skip to content

Развёртывание песочницы и устранение неполадок ​

О процессе работы с навыками см. Каталог навыков и песочница, определение полей см. API песочницы и навыков. Здесь дополнительно описаны требования к развёртыванию, шаблонам, десктопу и интеграции бэкенда.

Бэкенд и шаблоны ​

Для пространств можно выбрать бэкенды Docker, CubeSandbox, E2B. В этой статье рассматриваются эти три вида. Lite-десктоп-клиент использует host-бэкенд с зависимостью от изоляции ОС — он не относится к серверной конфигурации пространств, требования к сборке см. ниже Локальная песочница Lite. Старый бэкенд local на хост-процессе удалён. Docker использует Engine API напрямую. E2B использует REST-контрольную плоскость и data-plane envd. Cube использует специальный адаптер для шаблонов и сетевых политик.

Стандартный образ собран по docker/Dockerfile.sandbox и содержит Python 3.12, Node.js 20, Bash, jq и /workspace. Команды и файловые операции по умолчанию выполняются от root внутри песочницы. Сохранён пользователь user с UID 1000 для явного запуска от его имени. Изоляция между сессиями обеспечивается контейнером или удалённой песочницей — нельзя трактовать соглашение о рабочей директории как ограничение прав root.

Целевой buildСуффикс тега образаНазначение
sandboxнетОбраз сессии для Docker; базовый образ шаблона E2B CLI
cube-cubeШаблон Cube CLI с envd
desktop-desktopБазовый образ шаблона E2B с графическим рабочим столом
desktop-cube-desktop-cubeШаблон Cube с графическим рабочим столом и envd

Имя образа: wechatopenai/weknora-sandbox:<версия><суффикс>. ID шаблона относится к конкретному кластеру/аккаунту — не копируйте ID из других развёртываний. Продуктовые шаблоны должны соответствовать проверенной версии приложения. Цели сборки и архитектура релиза определяются по Dockerfile в репозитории и workflow релиза.

Развёртывание Docker ​

Бэкенд Docker по умолчанию выключен. Системный администратор включает его в «Настройки системы → Сетевая безопасность». До сохранения в БД можно использовать флаг WEKNORA_SANDBOX_DOCKER_ENABLED=true. При отключении можно просматривать и удалять существующие конфигурации, но новые контейнеры не создаются.

Одна конфигурация подключается к одному daemon, одна сессия использует один долгоживущий контейнер. Кросс-хостовая диспетчеризация отсутствует. Если разные реплики приложения подключены к разным локальным daemon, нельзя предполагать, что они будут шарить контейнеры и снапшоты навыков.

ПараметрЗначение по умолчанию/требование
Адрес daemonПусто — автодетект DOCKER_HOST или текущего Docker context; для удалённого tcp://host:2376
Каталог TLS-сертификатовОбязателен для удалённого TCP, в доступном для приложения каталоге должны быть ca.pem, cert.pem, key.pem
CPU / память / PIDПо умолчанию 2 ядра / 2 ГиБ / 512 процессов
Idle TTLПо умолчанию 1800 секунд
Сетевой режимТолько bridge или none; не принимаются host, container:, кастомные сети
OCI runtimeМожно выбрать любой runtime, установленный на daemon, например runsc

Если приложение само работает в контейнере, нужно либо пробросить Docker socket, либо подключиться к удалённому daemon. Предоставление доступа к Docker socket даёт контроль над хостом — передавайте только доверенным экземплярам приложения. Точка входа при понижении привилегий настраивает группу для appuser по GID сокета; не открывайте сокет через chmod 666. Если сокет root:root и доступен только владельцу на запись, сначала настройте подходящую непривилегированную группу на хосте.

Предпочитайте стандартный образ. Кастомный образ должен удовлетворять требованиям адаптера: наличие root, Bash, GNU find -printf, coreutils timeout, а также доступной для записи рабочей области. Контрольные точки и откат файлов сессии также зависят от Git. Отмена HTTP-запроса не прерывает процесс в контейнере — адаптер ограничивает время выполнения команды через timeout внутри контейнера.

Очистка по неактивности запускается при Create/Connect и выполняется в фоне, сравнивая TTL, записанный при создании контейнера. Это не встроенный таймер daemon. Жёсткого максимального срока жизни нет — скрипт, выполняющий команды, может периодически обновлять отметку активности, поэтому на стороне развёртывания необходимо отдельно отслеживать долгоживущие контейнеры.

Снапшоты навыков и диск ​

Установка навыка через docker commit создаёт локальный образ weknora-skill/. Последующие сессии запускаются с этого снапшота. Снапшот сохраняет ФС, но не состояние памяти. Совместное использование томов между тенантами и графический десктоп Docker пока не поддерживаются.

Инкрементальные снапшоты наследуют слои старого образа; удаление старого тега не обязательно освобождает диск. Удаление навыка добавляет слой с пометкой удаления — исходные файлы могут оставаться в родительском слое. Текущий процесс не уплощает образы и не распространяет их между daemon. Следите за числом слоёв и объёмом диска, перед очисткой убедитесь в отсутствии ссылок на снапшот/сессии. Для смены базового образа создайте новую конфигурацию и переустановите навыки.

Интеграция CubeSandbox/E2B ​

  1. Подготовьте доступные контрольную плоскость, gateway data-plane и домен песочниц. В настройках пространства укажите API, Proxy, domain и учётные данные. Для приватных/loopback-эндпоинтов явно разрешите приватные адреса; адреса облачного метаданных по-прежнему запрещены.
  2. Нажмите «Подключить и продолжить» — проверка контрольной плоскости загрузит каталог шаблонов. Проверка только подтверждает доступность control-plane.
  3. При отсутствии стандартных шаблонов создайте их явно. Для десктопа создайте отдельный десктоп-шаблон. Дождитесь статуса READY перед выбором. Для Cube используйте вариант с envd (-cube); обычный Docker-образ не отдаёт :49983/health.
  4. Выполните «Полная валидация»: реально создастся песочница, выполнится пробник, затем песочница будет удалена. Это подтвердит работоспособность data-plane и скриптового окружения.
  5. Сохраните конфигурацию, выберите её для агента и проверьте чтение вложений, сохранение состояния команд и скачивание артефактов.

proxy_url предназначен для self-hosted gateway data-plane: при подключении через gateway сохраняется роутинг на хост песочницы — удобно в окружениях без wildcard-DNS. Если control-plane доступен, но выполнение падает — в первую очередь проверьте Proxy, домен песочницы, inbound-токены и доступность приложения до gateway.

DNS гостя в Cube настраивается в шаблоне. После изменения DNS/образа шаблон нужно пересобрать. Конфигурация с уже установленными навыками не может менять/пересобирать базовый шаблон и переключаться между CLI/десктопом — создавайте новую конфигурацию и переустанавливайте навыки, чтобы избежать рассинхронизации снапшота и базового шаблона.

Для нескольких реплик приложения обязательно настройте общий Redis для хранения связки session→sandbox и состояния десктопа. Для одиночного экземпляра в разработке можно использовать in-memory хранилище. Существующие песочницы не применяют изменения бэкенд-конфигурации автоматически. Стратегии обновления навыков next_turn/new_session описаны в Каталоге навыков и песочнице.

ЯвлениеНаправление диагностики
Ошибка подключения при валидацииAPI может быть ошибочно заполнен как адрес дашборда; проверить учётные данные, TLS, флаг приватных адресов
Подключение успешно, но команды не выполняютсяProxy, домен песочницы, роутинг gateway, inbound-токен, доступность до gateway
Сборка шаблона не удаласьПосмотреть ошибку сборки от кластера; доступен ли образ для скачивания, совпадает ли архитектура, есть ли envd у Cube-образа
Нет выхода в интернет из песочницыСетевые политики шаблона, гостевой DNS, исходящий прокси кластера; разрешение приватных адресов control-plane не означает разрешение исходящего трафика скриптов
Установка зависимостей падаетПри запрете исходящего — разрешить репозитории пакетов; установка навыка и сессия используют одну сетевую политику
После переподключения потерян статусОбщий ли Redis, не истёк ли TTL, не вызвало ли обновление навыка пересборку

Интерактивный терминал и графический десктоп ​

Терминал и десктоп в боковой панели диалога подключаются к песочнице сессии по WebSocket. Терминал поддерживается для Cube, E2B, Docker; десктоп — только для Cube/E2B. Браузер не может передавать заголовки авторизации при рукопожатии WebSocket, поэтому сначала через уже авторизованный POST запрашивается краткосрочный билет сроком 2 минуты, затем билет передаётся в query параметре рукопожатия:

ВозможностьПолучение билетаWebSocket
ТерминалPOST /api/v1/sessions/:session_id/sandbox/terminal-ticketGET /api/v1/sessions/:id/sandbox/terminal?ticket=...
ДесктопPOST /api/v1/sessions/:session_id/sandbox/desktop-ticketGET /api/v1/sessions/:id/sandbox/desktop?ticket=...

Входной прокси должен проксировать Upgrade WebSocket для этих путей, ослабить таймаут чтения и не логировать значение ticket в query. Стандартный Nginx фронтенда уже настроен с форматом лога без query для ^/api/v1/sessions/[^/]+/sandbox/(terminal|desktop)$. Для кастомного Ingress обработайте это самостоятельно. После подключения терминала сервер раз в минуту перепроверяет статус логина, членство в пространстве и принадлежность сессии — выход из аккаунта или исключение из пространства разорвут терминал. Параметры API см. Терминал API и Десктоп API.

Терминал и десктоп отключаются при простое по terminal_idle_disconnect_sec (по умолчанию 900 с, минимум 60 с, максимум 24 ч), после чего песочница приостанавливается по TTL провайдера. Для терминала активностью считаются клавиатурный ввод и вывод PTY; для десктопа — ввод мыши/клавиатуры.

Терминал Docker — это exec с TTY=true. Engine API не поддерживает повторное присоединение, поэтому поведение отличается от Cube/E2B:

  • Пока терминал открыт, периодически обновляется метка активности для предотвращения очистки по DockerIdleTTL; после закрытия контейнер утилизируется по обычному DockerIdleTTL.
  • При разрыве (закрытие панели, таймаут простоя, сетевой обрыв) aihelpme.ru посылает SIGHUP запущенной оболочке и её дочерним процессам — передний план завершится, фоновые с nohup сохранятся.
  • Фронтенд не автопереподключает терминал Docker; кнопка «Переподключиться» открывает новый shell.
  • Если песочница не запущена (контейнер остановлен/удалён по неактивности) выводится «Возможно, была очищена по неактивности». После запуска, если контейнер удалён — создастся новая песочница, прежние файлы не сохранятся.

Графический десктоп ​

Только десктоп-шаблоны Cube/E2B поддерживают десктоп в боковой панели диалога. При первом открытии бэкенд запускает процесс десктопа. В конфигурации должен быть выбран десктоп-шаблон и включён desktop_enabled. После установки навыков нельзя переключить базовый шаблон на месте.

text
Браузер noVNC → релей aihelpme.ru с билетом → gateway провайдера → websockify :6080 → локальный x11vnc :5900

Браузер не хранит Sandbox API Key, inbound-токен, пароль websockify. Десктоп-билет одноразовый, полное описание см. в API сессий. У десктоп-шаблона Cube в exposedPorts должен быть открыт только 49983 envd — не пробрасывайте 6080 наружу. Доступ к десктопу должен идти только через gateway и релей aihelpme.ru.

Одновременно для сессии разрешается только один десктоп-релей. Слоты между репликами координируются через Redis. После пересборки песочницы выводится уведомление SANDBOX_REBUILT с предложением отключиться — нельзя считать новый десктоп тем же экземпляром с временными файлами. Факт активности десктопа определяется по вводу RFB (клавиатура/мышь), запрос скриншота активностью пользователя не считается.

Локальная песочница Lite ​

Бэкенд host компилируется только в Lite-десктопном билде с тегом desktop (build:tags в cmd/desktop/wails.json). Серверный бинарь и однофайловый Lite его не содержат. Он выполняет команды в сессии без выбранной песочницы — см. Каталог навыков и песочница.

ПлатформаСтатус
macOSДля каждой команды используется системный sandbox-exec (Seatbelt). При старте проверяется доступность — если недоступен, функционал не включается
WindowsНе реализовано, при старте сообщается о недоступности, нет деградации без изоляции
LinuxНе поддерживается

Каждая команда — новый локальный процесс, сессия не хранит привязку к хост-песочнице и не делает checkpoint рабочей области. Каталоги проектов, одобренные через системный диалог выбора, сохраняются в desktop-prefs.json в поле project_dirs. Сессия может привязаться только к самому каталогу из списка, а не к подкаталогу и не к произвольно введённому пути. approval_mode поддерживает только auto (свободное чтение/запись внутри рабочей области, запрет выхода в сеть); прочие значения отвергаются. Расположение файла настроек см. Десктоп-клиент.

Валидация при разработке ​

Юнит-тесты не требуют реального daemon:

bash
go test ./internal/sandbox -run 'TestDocker' -count=1

Для интеграционного теста с реальным Docker сначала соберите стандартный образ — будут созданы тестовые контейнеры:

bash
docker build -f docker/Dockerfile.sandbox --target sandbox -t wechatopenai/weknora-sandbox:dev .
DOCKER_INTEGRATION_IMAGE=wechatopenai/weknora-sandbox:dev \
go test -tags=docker_integration ./internal/sandbox \
  -run '^TestDocker.*Integration' -count=1 -v -timeout=15m

Интеграционные тесты для удалённого подключения находятся в internal/sandbox/cube_integration_test.go и e2b_compatible_integration_test.go. Перед запуском настройте учётные данные тестового кластера согласно комментариям в файлах. Область проверки должна включать сохранение состояния сессии, переиспользование Shell, временное хранение вложений, сборку артефактов и таймауты — недостаточно ограничиваться только Health. После тестов обязательно убедитесь, что тестовые экземпляры удалены.

Версия v0.8.3 · MIT License