Технологии

Docker для ИИ-приложений: что упрощает а что усложняет

Контейнер решает задачу воспроизводимого окружения и создаёт две новые ровно там, где болит: доступ к экрану и доступ к видеокарте. Таблица «что упрощает / что ломает» и правило выбора между контейнером и нативным запуском.

«Заверни в Docker» — стандартный ответ на любой вопрос о развёртывании, и в большинстве случаев он правильный. У ИИ-приложений есть два исключения, и они неприятны тем, что попадают ровно в те функции, ради которых локальный ИИ обычно и ставят.

#Короткий ответ

Контейнер объективно мешает в двух случаях: когда приложению нужен доступ к экрану и когда ему нужен доступ к видеокарте. В первом случае это ограничение непреодолимое, во втором — преодолимое, но ценой платформенной зависимости, из-за которой контейнер перестаёт быть переносимым, то есть теряет главный смысл.

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

#Как это устроено

#Почему в контейнере нет экрана

Контейнер — это процесс на хосте с изолированным набором пространств имён. Изолируются файловая система, сеть, дерево процессов. Графическая сессия в этот набор не входит просто потому, что её у контейнера нет.

Библиотеки снятия экрана обращаются к оконной системе: к серверу отображения на Linux, к графическому интерфейсу операционной системы на Windows и macOS. Внутри контейнера нет ни того, ни другого: нет подключённого дисплея, нет сеанса пользователя, нет окон. Вызов не «работает медленно» и не «требует настройки» — снимать нечего.

Обходные пути существуют и все стоят дорого:

  • пробросить сокет оконной системы внутрь — работает только на Linux и только когда контейнер запущен тем же пользователем в той же сессии, то есть на сервере это бессмысленно;
  • запустить виртуальный дисплей внутри контейнера — вы получите снимки пустого виртуального экрана, а не своего рабочего стола;
  • на Windows и macOS — не работает никак: там графическая подсистема принципиально недоступна из контейнера Linux.

Практический вывод для Persona: в контейнере не работает захват экрана и всё, что из него следует — таймлайн, поиск по увиденному, распознавание текста с экрана. Контейнерный режим — это веб-интерфейс и приём данных, отправленных с вашего компьютера. Развёрнутый список того, что остаётся, а что отваливается, — в гайде про запуск Persona в контейнере.

#Почему с видеокартой сложнее, чем кажется

Ускоритель в контейнер пробрасывается, и это штатный сценарий. Но требований у него больше, чем в типовой инструкции:

  • драйвер нужной версии на хосте;
  • слой поддержки контейнеров от производителя ускорителя;
  • совместимость версии вычислительной библиотеки внутри образа с драйвером снаружи;
  • на Windows — работа через слой совместимости с Linux, что добавляет ещё один уровень, где что-то может не совпасть.

Каждый из этих пунктов делает образ привязанным к конкретному хосту. Контейнер, который заводится только на машине с тем же драйвером и тем же слоем поддержки, уже не «работает везде одинаково» — а именно это было причиной выбрать контейнер. Отдельный разбор конкретно этой связки — в статье про Ollama в Docker.

#Что из этого следует на практике

Что контейнер упрощает Что контейнер ломает или усложняет
Воспроизводимое окружение и версии зависимостей Захват экрана — не работает вовсе
Развёртывание на новой машине одной командой Доступ к видеокарте — работает, но с привязкой к хосту
Изоляция от системных пакетов хоста Доступ к звуковым устройствам и микрофону
Откат на предыдущий образ Доступ к горячим клавишам и активному окну
Одинаковый запуск у нескольких участников Пути к данным: том или потеря данных при пересоздании
Ограничение памяти и процессора штатными средствами Отладка: «в контейнере не воспроизводится»
Обновление без разрушения системы Локальная разработка: цикл правки становится длиннее

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

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

#Правило выбора

Не «контейнер или нативно вообще», а по функции.

  1. Нужен доступ к экрану, микрофону, активному окну, горячим клавишам? → нативный запуск. Обсуждать нечего.
  2. Нужен инференс на видеокарте, и это ваша единственная машина? → нативно проще. Контейнер добавит слой без выигрыша.
  3. Нужно разворачивать одно и то же на нескольких машинах или отдавать другим? → контейнер.
  4. Веб-приложение и база на арендованном сервере? → контейнер, и это его лучший сценарий.
  5. Смешанный случай: захват на вашем компьютере, приложение на сервере? → разделите. Нативная часть у вас, контейнер на сервере. Это самая жизнеспособная схема из всех.

Пятый пункт стоит развернуть, потому что он и есть типовой ответ. Ваш компьютер снимает экран и отправляет данные; арендованная машина в контейнере принимает, хранит, индексирует и отдаёт веб-интерфейс. Каждая часть работает там, где может. Как считать конфигурацию серверной части — в статье про выбор VPS под личный ИИ-сервис.

#Где интуиция подводит

«Контейнер — это виртуальная машина, значит там есть всё». Нет. Контейнер использует ядро хоста и его устройства; у него нет своего экрана, своей звуковой карты и своего сеанса пользователя. Виртуальная машина ближе к «есть всё» — но и у неё экран виртуальный, то есть ваш рабочий стол она тоже не увидит.

«Раз в контейнере не заработало — надо подобрать флаги». Для экрана — не надо: подходящих флагов не существует. Время, потраченное на их поиск, — чистая потеря; это структурное ограничение, а не настройка.

«Контейнер безопаснее». Он изолирует по умолчанию, и это хорошо. Но ровно те флаги, которые обычно добавляют ради доступа к устройствам — привилегированный режим, проброс устройств, монтирование сокетов, — изоляцию и снимают. Контейнер с половиной хоста внутри безопаснее нативного запуска ненамного.

«Контейнер решает вопрос эксплуатации». Он решает вопрос окружения. Автозапуск, деплой с проверкой версии, мониторинг, резервные копии остаются вашими — и именно они, а не сборка образа, съедают время при самостоятельном хостинге. Честный список — в статье про риски самостоятельного хостинга.

«В контейнере всё воспроизводимо». Только если образ собран с закреплёнными версиями. Файл сборки, который ставит зависимости «последних версий», через полгода соберётся во что-то другое — и это худший вид невоспроизводимости, потому что он выглядит как воспроизводимость.

#Частые вопросы

#Можно ли всё-таки снимать экран из контейнера?

На Linux — при пробросе сокета оконной системы и запуске от того же пользователя в той же графической сессии, то есть только на десктопе и только для своих задач. На сервере, на Windows и на macOS — нет. Если захват экрана ваш основной сценарий, планируйте нативный запуск.

#Стоит ли класть языковую модель в контейнер?

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

#Насколько контейнер замедляет работу?

Накладные расходы по процессору и памяти незначительны — это те же процессы хоста. Заметно замедляется дисковый ввод-вывод при неудачно выбранном типе хранилища и работа с сетью в некоторых режимах. Базу всегда выносите на том, а не в слой образа: там и сохранность, и скорость.

#Что делать с данными при обновлении образа?

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

#Контейнер или пакетный менеджер языка?

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

#Куда контейнер встраивается в общий маршрут?

На третьем этапе, при переезде с локального запуска на постоянно доступную машину, — см. статью о том, как поднять свой ИИ-сервис. Раньше он не нужен: контейнеризовать приложение, которое ещё не переживает перезагрузку, преждевременно.

Хотите ИИ, который помнит вас?

Persona держит контекст между чатами и работает на вашем железе — если развернуть её у себя и подключить локальную модель.

Создать аккаунт