OpenClaw Docker на Mac-облаке в 2026: Exit 137/OOM, права томов uid 1000, DNS и кратчайший путь к openclaw doctor
У операторов, которые запускают OpenClaw в Docker на арендованных Mac в облаке, часто всплывают код выхода 137, Permission denied на смонтированном конфиге или ситуация, когда HTTPS на хосте проходит, а внутри контейнера — нет; дальше начинаются дни переустановки образов. В статье зафиксировано, кому она адресована (SRE и одиночные разработчики на съёмных Mac), что вы получите (упорядоченный чеклист и матрицу симптомов в духе официальной практики Compose 2026) и как устроена логика изложения: сначала память и cgroups, затем тома с uid 1000, потом DNS Docker, далее openclaw doctor, порт 18789 и момент, когда разумнее отказаться от контейнеров в пользу нативного macOS.
В этой статье
1. Триада готовности: процесс поднят, порт проброшен, том доступен на запись
Официальные сценарии Docker и Docker Compose оборачивают шлюз OpenClaw в контейнер. Хост Mac-облака по-прежнему владеет квотами RAM и CPU, делает bind-mount каталога ~/.openclaw (или пользовательского пути к конфигу) и публикует 18789 или другой сопоставленный порт для проверок с loopback или через SSH-туннели. В отличие от ноутбука на столе, облачные Mac обычно приходят с ограниченной памятью, часто без GUI-сессии и с образами, где процесс типично идёт не от root, а от пользователя node с uid/gid 1000. Пока эти факты не усвоены, любая правка конфига делается не на том уровне абстракции.
Определите готовность как три наблюдаемых факта, которые можно вставить в тикет: контейнер работает или healthy, в выводе docker compose ps видна ожидаемая привязка ports, а команды вроде openclaw status или ваш health probe проходят внутри контейнера без ошибок прав. Маршрутизация моделей, вебхуки Slack и Cron имеют смысл только после того, как триада зелёная. Типичные ошибки Compose: пути на хосте, которых нет (Docker создаёт каталоги от root), read-only там, где шлюзу нужна запись состояния, или переполнение небольшого корневого тома слоями образов и кэшем сборки — снаружи это похоже на «случайные» падения, пока df -h не покажет правду.
Зафиксируйте имя compose-проекта, имена сервисов, опубликованные порты и абсолютные пути на хосте для конфига и рабочей области. Одна строка в runbook экономит часы, когда вы сверяетесь с гайдами по апгрейду, вебхукам или тихому разбору Cron: у всех одна и та же топология, а не догадки, о какой машине речь.
2. Разбор болевых точек (нумерованный)
- Exit 137 и OOM: Docker отображает лимиты памяти Linux cgroups на рабочую нагрузку. Когда срабатывает OOM killer ядра, Docker часто показывает код выхода 137 (128 + SIGKILL 9). Скачивание и сборка образов едят RAM сильнее, чем устойчивый трафик шлюза; узел, который «часами нормальный», может умереть за минуты на
docker compose build. Всегда отмечайте, 137 случился на этапе build или run — лечение разное. - Владение томом и uid 1000: Если вы создали
~/.openclawна хосте от root или под личным пользователем, процессnodeв контейнере не сможет писатьopenclaw.json, логи или файлы workspace. Сбой может выглядеть как тихий цикл перезапусков без явного стека и часто ошибочно списывается на «плохие release notes». - DNS Docker и корпоративный egress: Если
curl https://api.anthropic.comна хосте успешен, аdocker exec … curl— нет, почти всегда дело в неверных DNS в контейнере, переменных HTTP(S)_PROXY или в том, что доверенные сертификаты / прокси TLS-intercept не видны внутри. Менять API-ключи до починки сетевого пути — трата времени и квоты. - Health-check и гонки зависимостей: Агрессивный
depends_onбез достаточногоstart_periodзаливает логи «connection refused», похожими на баги приложения. Сначала докажите, что шлюз слушает порт, прежде чем зависимые сервисы начнут его долбить.
Вместе эти четыре паттерна объясняют большинство инцидентов «как в проде», которые мы видим у арендаторов Mac-облака; таблица ниже сжимает их в первые действия.
3. Матрица «симптом — первопричина»
Используйте таблицу как шпаргалку во время инцидента. Выберите ближайший симптом, выполните колонку «первые действия» до перехода ко вторым гипотезам.
| Наблюдаемый сигнал | Вероятная первопричина | Первые действия (по порядку) |
|---|---|---|
Цикл перезапусков, OOMKilled, exit 137 | Давление по памяти cgroup или хоста | Поднять лимит памяти Docker Desktop/Engine или mem_limit в compose; остановить конкурирующие RAM-задачи; повторить сборку с меньшим параллелизмом слоёв |
Permission denied на путях конфига или workspace | Bind-mount с неверным владельцем uid | На хосте: sudo chown -R 1000:1000 /path/to/mount; проверить RW в compose; подтвердить docker exec -u node … touch тестовым файлом |
| Сбои HTTPS или DNS только внутри контейнера | Резолвер контейнера или отсутствие proxy env | docker exec cat /etc/resolv.conf, curl -v; добавить dns: в compose или daemon.json; передать --env-file для корпоративных прокси |
| Процесс жив, но порт недоступен удалённо | Проброс порта, bind-адрес или security group облака | Сравнить ports: с задуманным 0.0.0.0 против 127.0.0.1; открыть правило SG; по гайдам по hardening предпочесть SSH-туннель |
openclaw doctor ругается на отсутствие credentials, хотя compose «их задаёт» | Переменные окружения не попали в PID контейнера | docker exec … env | grep OPENCLAW против блока environment в compose; исправить кавычки и наследование |
4. Шесть упорядоченных шагов устранения (не переставляйте без причины)
Порядок важен: последующие шаги предполагают, что предыдущие уже отсекли целые классы отказов. Прыжок сразу к ретегам образа уничтожает улики.
- Зафиксировать состояние: Выполнить
docker compose ps -a, затемdocker logs <service> --tail 200. Сохранить, был ли exit 137 при pull образа, сборке или в стабильном run. - Проверить запас по памяти: Временно выделить Docker порядка 4–8 ГБ для сборок (уточнить по документации провайдера). На хосте смотреть
memory_pressureили аналоги Activity Monitor; тяжёлый swap плюс нагрузка шлюза — рецепт нестабильного SIGKILL. - Нормализовать владение томами: Применить
chownко всем bind-путям, куда контейнер пишет. Перед возвращением к OpenClaw снова выполнить тривиальный тест записи от uid 1000 внутри контейнера. - Доказать сеть из контейнера: Изнутри обратиться к провайдеру LLM через
curl -sIилиopenssl s_client, если подозрительно TLS. При корпоративном MITM зеркалировать те же доверенные материалы или proxy-переменные, что на хосте. - Запустить диагностический CLI: Выполнить
openclaw doctor,openclaw statusиopenclaw models status(имена по актуальному CLI). Переустановку или смену тега образа — только если doctor остаётся красным с ошибками уровня установки после всего вышеперечисленного. - Приёмка на порту 18789:
curl -sI http://127.0.0.1:18789(или сопоставленный порт) с хоста; для удалённых админов проверить SSH-туннель или пути reverse proxy из статей по безопасности.
docker system prune -a, пока инцидент открыт — он удаляет кэш слоёв и контекст логов и увеличивает среднее время восстановления.5. Технические факты для цитирования (минимум три — перечисляем семь)
- Семантика exit 137: В Docker трактуйте как OOM в первую очередь; подтверждайте через
docker inspect … OOMKilled, когда поле доступно. - Контракт uid 1000: Официальные образы на базе Node ожидают записываемые тома для uid 1000; несовпадение — не дефект продукта.
- Порог по RAM: В сообществе и документации ~2 ГБ часто называют хрупким минимумом для работы с образами; сборки обычно требуют кратно большего запаса.
- Порт 18789: Во многих примерах — дефолтный маппинг шлюза/UI; публикация в интернет без ужесточения токенов противоречит прод-гайдам VPSMAC по hardening.
- Видимость окружения: Переменные Compose не волшебные — для
doctorсчитается только то, что наследует PID контейнера. - Дублирующие стеки: Два compose-проекта на одном host-порту или с общим каталогом конфига дают «иногда работает»; аудит через
docker psи inspect монтирований. - Базовые артефакты: Храните фрагмент последнего «зелёного»
docker inspectи транскрипт успешного doctor до апгрейдов, чтобы отличать регрессии от дрейфа.
6. Заключение: удобство Docker против нативного macOS на VPSMAC
Docker отлично подходит для воспроизводимых демо и изоляции мультитенантности, но каждый namespace и cgroup — ещё один прыжок, когда в полночь зовут на инцидент. Вы платите дублированием настроек DNS, акробатикой с uid на томах и худшей корреляцией между давлением swap на хосте и «смертельными спиралями» контейнера. Когда команды крутят образы вместо починки монтирований, накапливаются «снежинковые» compose-файлы, которые никто не хочет трогать — слабый исход для шлюза агента 7×24.
Нативная установка на bare-metal узле Mac-облака — SSH, официальный путь без контейнера, супервизия через launchd — схлопывает несколько областей отказа: тот же uid, что в ssh, пишет конфиг, настройки резолвера совпадают с вашей оболочкой, а openclaw doctor читает ту файловую систему, которой вы уже доверяете. Для нагрузок OpenClaw как для прод-сервисов, а не одноразовой лаборатории, такое уменьшение движущихся частей обычно выигрывает у очередного кастомного образа. Стеки «только Docker» добавляют постоянные накладные расходы на отладку и разброс производительности под длительной нагрузкой; выделенные физические Mac-хосты смягчают оба эффекта.
Аренда узла VPSMAC — прагматичный следующий шаг, когда триада готовности отказывается стабилизироваться: вы сохраняете совместимость с Apple Silicon и питание 24/7 без борьбы с эргономикой контейнеров поверх облачных квот. Сочтите узел со статьёй про развёртывание за пять минут для bootstrap и чеклистом прод-hardening для экспозиции — тот же toolchain, меньше «налога абстракций». Именно такой обмен рекомендует эта статья после честного исчерпания матрицы выше: не как лозунг, а потому что повторяющиеся циклы 137 и прав указывают на число слоёв, а не на качество модели.