«Заверни в Docker» — стандартный ответ на любой вопрос о развёртывании, и в большинстве случаев он правильный. У ИИ-приложений есть два исключения, и они неприятны тем, что попадают ровно в те функции, ради которых локальный ИИ обычно и ставят.
#Короткий ответ
Контейнер объективно мешает в двух случаях: когда приложению нужен доступ к экрану и когда ему нужен доступ к видеокарте. В первом случае это ограничение непреодолимое, во втором — преодолимое, но ценой платформенной зависимости, из-за которой контейнер перестаёт быть переносимым, то есть теряет главный смысл.
Во всех остальных случаях — веб-приложение, база, фоновая обработка, приём данных извне — контейнер удобен и уместен.
#Как это устроено
#Почему в контейнере нет экрана
Контейнер — это процесс на хосте с изолированным набором пространств имён. Изолируются файловая система, сеть, дерево процессов. Графическая сессия в этот набор не входит просто потому, что её у контейнера нет.
Библиотеки снятия экрана обращаются к оконной системе: к серверу отображения на Linux, к графическому интерфейсу операционной системы на Windows и macOS. Внутри контейнера нет ни того, ни другого: нет подключённого дисплея, нет сеанса пользователя, нет окон. Вызов не «работает медленно» и не «требует настройки» — снимать нечего.
Обходные пути существуют и все стоят дорого:
- пробросить сокет оконной системы внутрь — работает только на Linux и только когда контейнер запущен тем же пользователем в той же сессии, то есть на сервере это бессмысленно;
- запустить виртуальный дисплей внутри контейнера — вы получите снимки пустого виртуального экрана, а не своего рабочего стола;
- на Windows и macOS — не работает никак: там графическая подсистема принципиально недоступна из контейнера Linux.
Практический вывод для Persona: в контейнере не работает захват экрана и всё, что из него следует — таймлайн, поиск по увиденному, распознавание текста с экрана. Контейнерный режим — это веб-интерфейс и приём данных, отправленных с вашего компьютера. Развёрнутый список того, что остаётся, а что отваливается, — в гайде про запуск Persona в контейнере.
#Почему с видеокартой сложнее, чем кажется
Ускоритель в контейнер пробрасывается, и это штатный сценарий. Но требований у него больше, чем в типовой инструкции:
- драйвер нужной версии на хосте;
- слой поддержки контейнеров от производителя ускорителя;
- совместимость версии вычислительной библиотеки внутри образа с драйвером снаружи;
- на Windows — работа через слой совместимости с Linux, что добавляет ещё один уровень, где что-то может не совпасть.
Каждый из этих пунктов делает образ привязанным к конкретному хосту. Контейнер, который заводится только на машине с тем же драйвером и тем же слоем поддержки, уже не «работает везде одинаково» — а именно это было причиной выбрать контейнер. Отдельный разбор конкретно этой связки — в статье про Ollama в Docker.
#Что из этого следует на практике
| Что контейнер упрощает | Что контейнер ломает или усложняет |
|---|---|
| Воспроизводимое окружение и версии зависимостей | Захват экрана — не работает вовсе |
| Развёртывание на новой машине одной командой | Доступ к видеокарте — работает, но с привязкой к хосту |
| Изоляция от системных пакетов хоста | Доступ к звуковым устройствам и микрофону |
| Откат на предыдущий образ | Доступ к горячим клавишам и активному окну |
| Одинаковый запуск у нескольких участников | Пути к данным: том или потеря данных при пересоздании |
| Ограничение памяти и процессора штатными средствами | Отладка: «в контейнере не воспроизводится» |
| Обновление без разрушения системы | Локальная разработка: цикл правки становится длиннее |
Правая колонка не аргумент против контейнеров. Это перечень того, что надо решить до упаковки, а не после.
Отдельная строка про данные заслуживает выделения: контейнер по умолчанию эфемерен, и база, оказавшаяся внутри образа вместо тома, исчезает при первом же пересоздании. Ошибка совершается один раз и запоминается надолго.
#Правило выбора
Не «контейнер или нативно вообще», а по функции.
- Нужен доступ к экрану, микрофону, активному окну, горячим клавишам? → нативный запуск. Обсуждать нечего.
- Нужен инференс на видеокарте, и это ваша единственная машина? → нативно проще. Контейнер добавит слой без выигрыша.
- Нужно разворачивать одно и то же на нескольких машинах или отдавать другим? → контейнер.
- Веб-приложение и база на арендованном сервере? → контейнер, и это его лучший сценарий.
- Смешанный случай: захват на вашем компьютере, приложение на сервере? → разделите. Нативная часть у вас, контейнер на сервере. Это самая жизнеспособная схема из всех.
Пятый пункт стоит развернуть, потому что он и есть типовой ответ. Ваш компьютер снимает экран и отправляет данные; арендованная машина в контейнере принимает, хранит, индексирует и отдаёт веб-интерфейс. Каждая часть работает там, где может. Как считать конфигурацию серверной части — в статье про выбор VPS под личный ИИ-сервис.
#Где интуиция подводит
«Контейнер — это виртуальная машина, значит там есть всё». Нет. Контейнер использует ядро хоста и его устройства; у него нет своего экрана, своей звуковой карты и своего сеанса пользователя. Виртуальная машина ближе к «есть всё» — но и у неё экран виртуальный, то есть ваш рабочий стол она тоже не увидит.
«Раз в контейнере не заработало — надо подобрать флаги». Для экрана — не надо: подходящих флагов не существует. Время, потраченное на их поиск, — чистая потеря; это структурное ограничение, а не настройка.
«Контейнер безопаснее». Он изолирует по умолчанию, и это хорошо. Но ровно те флаги, которые обычно добавляют ради доступа к устройствам — привилегированный режим, проброс устройств, монтирование сокетов, — изоляцию и снимают. Контейнер с половиной хоста внутри безопаснее нативного запуска ненамного.
«Контейнер решает вопрос эксплуатации». Он решает вопрос окружения. Автозапуск, деплой с проверкой версии, мониторинг, резервные копии остаются вашими — и именно они, а не сборка образа, съедают время при самостоятельном хостинге. Честный список — в статье про риски самостоятельного хостинга.
«В контейнере всё воспроизводимо». Только если образ собран с закреплёнными версиями. Файл сборки, который ставит зависимости «последних версий», через полгода соберётся во что-то другое — и это худший вид невоспроизводимости, потому что он выглядит как воспроизводимость.
#Частые вопросы
#Можно ли всё-таки снимать экран из контейнера?
На Linux — при пробросе сокета оконной системы и запуске от того же пользователя в той же графической сессии, то есть только на десктопе и только для своих задач. На сервере, на Windows и на macOS — нет. Если захват экрана ваш основной сценарий, планируйте нативный запуск.
#Стоит ли класть языковую модель в контейнер?
Если у вас одна машина — нет, выигрыша не будет, а слой совместимости с драйвером добавит вам новый источник отказов. Если моделей несколько и их надо изолировать друг от друга по версиям библиотек — да, тогда контейнер оправдан.
#Насколько контейнер замедляет работу?
Накладные расходы по процессору и памяти незначительны — это те же процессы хоста. Заметно замедляется дисковый ввод-вывод при неудачно выбранном типе хранилища и работа с сетью в некоторых режимах. Базу всегда выносите на том, а не в слой образа: там и сохранность, и скорость.
#Что делать с данными при обновлении образа?
Данные должны жить на именованном томе или в примонтированном каталоге хоста и переживать пересоздание контейнера. Проверяется это ровно одним способом: пересоздать контейнер на стенде и убедиться, что данные на месте, — до того, как вы сделаете это в рабочем окружении.
#Контейнер или пакетный менеджер языка?
Виртуальное окружение решает вопрос версий библиотек, но не решает вопрос системных зависимостей: движка распознавания текста, кодеков, системных библиотек. Если их у вас нет — виртуального окружения хватает. Если есть — контейнер избавляет от разбирательств «почему на другой машине не собирается».
#Куда контейнер встраивается в общий маршрут?
На третьем этапе, при переезде с локального запуска на постоянно доступную машину, — см. статью о том, как поднять свой ИИ-сервис. Раньше он не нужен: контейнеризовать приложение, которое ещё не переживает перезагрузку, преждевременно.