Развёртывание песочницы и устранение неполадок
О процессе работы с навыками см. Каталог навыков и песочница, определение полей см. 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
- Подготовьте доступные контрольную плоскость, gateway data-plane и домен песочниц. В настройках пространства укажите API, Proxy, domain и учётные данные. Для приватных/loopback-эндпоинтов явно разрешите приватные адреса; адреса облачного метаданных по-прежнему запрещены.
- Нажмите «Подключить и продолжить» — проверка контрольной плоскости загрузит каталог шаблонов. Проверка только подтверждает доступность control-plane.
- При отсутствии стандартных шаблонов создайте их явно. Для десктопа создайте отдельный десктоп-шаблон. Дождитесь статуса
READYперед выбором. Для Cube используйте вариант с envd (-cube); обычный Docker-образ не отдаёт:49983/health. - Выполните «Полная валидация»: реально создастся песочница, выполнится пробник, затем песочница будет удалена. Это подтвердит работоспособность data-plane и скриптового окружения.
- Сохраните конфигурацию, выберите её для агента и проверьте чтение вложений, сохранение состояния команд и скачивание артефактов.
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-ticket | GET /api/v1/sessions/:id/sandbox/terminal?ticket=... |
| Десктоп | POST /api/v1/sessions/:session_id/sandbox/desktop-ticket | GET /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. После установки навыков нельзя переключить базовый шаблон на месте.
Браузер 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:
go test ./internal/sandbox -run 'TestDocker' -count=1Для интеграционного теста с реальным Docker сначала соберите стандартный образ — будут созданы тестовые контейнеры:
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. После тестов обязательно убедитесь, что тестовые экземпляры удалены.
