Как устроена архитектура с контейнерами
Что проверяют
Понимаете ли вы, что контейнер это изолированный процесс, а не маленькая виртуалка, и умеете ли упаковать ML-нагрузку так, чтобы она одинаково запускалась у вас, в CI и на кластере. Следом обычно спрашивают, как отдать контейнеру GPU и где держать веса модели.
Как отвечать
Начните с механики:
- изоляция: контейнер это процесс на ядре хоста, отделённый namespaces (PID, сеть, файловая система) и ограниченный cgroups по CPU и памяти. Своего ядра нет, отсюда быстрый старт и изоляция слабее, чем у ВМ;
- образ: неизменяемый набор слоёв по спецификации OCI, склеенных через overlayfs. Каждая инструкция
Dockerfileдаёт слой, неизменившиеся слои берутся из кэша; - реестр: образы лежат в Harbor, GitLab Registry или облачном реестре, в проде их фиксируют по digest;
- оркестрация: Kubernetes раскладывает поды по узлам, перезапускает упавшие, масштабирует. Для ML поверх него Kubeflow, KServe, Airflow с
KubernetesPodOperator.
Затем ML-специфика. Драйвер NVIDIA стоит на хосте, CUDA-библиотеки едут в образе (база nvidia/cuda или образ PyTorch), GPU в контейнер пробрасывает NVIDIA Container Toolkit, в Kubernetes device plugin и ресурс nvidia.com/gpu. Порядок слоёв «зависимости раньше кода», чтобы правка скрипта не переустанавливала torch. Датасеты и веса подтягивают при старте из S3 или реестра моделей вроде MLflow, образ остаётся лёгким.
Разделите обучение и инференс: обучение это батч-джоб с доступом к данным, инференс это сервис с health-check, лимитами ресурсов и автомасштабированием (Triton, vLLM, KServe).
Где спотыкаются
Называют контейнер лёгкой виртуальной машиной. Отсюда ожидание, что образ с новой CUDA заработает на хосте со старым драйвером или что root внутри контейнера безопасен.
Не фиксируют версии. pip install torch без пина и тег latest дают образ, который через месяц соберётся с другой CUDA, и модель начнёт вести себя иначе.
Кладут датасет в образ. Образ в десятки гигабайт долго тянется на каждый узел, а обновление данных требует пересборки.