Стадия жизненного цикла модуля: Experimental
У модуля есть требования для установки

Какие режимы доставки поддерживаются?

Два режима:

  • SharedPVC — режим по умолчанию для кластеров с RWX-хранилищем;
  • NodeCache — кэш на узле поверх SDS и CSI-монтирования.

SharedPVC создаёт RWX PVC в пространстве имён рабочей нагрузки и Job для подготовки каждой запрошенной модели. NodeCache хранит модели в общем кэше узла и монтирует их только на чтение через CSI.

Модуль работает только с LLM?

Нет. Модуль хранит и доставляет файлы моделей в поддерживаемых форматах, например Safetensors, GGUF и Diffusers. Это могут быть LLM, модели эмбеддингов или другие модели, если их формат поддержан контроллером.

Модуль не запускает среду инференса и не решает, как именно приложение будет использовать модель. Он готовит проверенные файлы и монтирует их в Pod.

Чем раздача каталога отличается от доставки?

Доставка подключает модель к рабочей нагрузке внутри кластера.

Раздача каталога работает между кластерами или сетевыми зонами. Раздающий кластер отдаёт ClusterModel в фазе Ready, а потребляющий кластер сначала импортирует локальную копию и только потом доставляет её в рабочую нагрузку. Поэтому раздача каталога не является третьим значением delivery.type; она включается через distribution.mode=PublicCatalog.

Что именно происходит после создания Model?

Контроллер читает spec.source, получает данные модели, проверяет формат и контрольную сумму, сохраняет локальную копию в DMCR и обновляет status.

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

Для чего нужен ModelPack?

ModelPack — внутренняя упаковка исходных файлов модели в OCI-артефакт DMCR. Он нужен для проверки, возобновления после сбоя, очистки и повторной доставки. Это не конвертация весов модели: исходный формат файлов не меняется. Пользователь не выбирает ModelPack, контрольную сумму или путь в реестре.

Для больших моделей из объектного источника подготовка идёт по частям: контроллер читает источник диапазонами, записывает завершённые части в DMCR и может продолжить после рестарта с последнего зафиксированного слоя.

Сжатие включается автоматически там, где оно уменьшает размер хранения: данные части сжимаются zstd, а если сжатый вариант больше исходного, сохраняется исходная часть. Для архивных слоёв поддерживаются gzip и zstd. Мониторинг сравнивает логический размер и фактический размер хранения, чтобы показать реальную экономию.

Почему в S3 bucket тысячи объектов?

Это нормально для подготовленных моделей. Модуль хранит не один файл на модель, а OCI-артефакт ModelPack: манифест, конфигурацию, слои, ссылки реестра, промежуточные данные подготовки и служебные маркеры для возобновления и очистки. В интерфейсе хранилища можно увидеть группы вроде docker/registry/..., raw/... и _ai_models/direct-upload/...; это внутренняя структура, а не пользовательский API.

Количество объектов не равно количеству моделей. Удаление Model или ClusterModel ставит запрос на очистку, но физическое освобождение места происходит позже, после сборки мусора. Не удаляйте объекты вручную: сначала проверьте дашборд хранилища, запросы очистки и логи контейнера dmcr-garbage-collection.

Как увидеть прогресс подготовки модели?

Для SharedPVC используйте панели очереди подготовки и скорости передачи на обзорном дашборде. Контроллер публикует ожидаемый размер для каждой Job, а DMCR считает прочитанные байты OCI-слоёв по разрешению, выданному этой Job.

Для NodeCache используйте панели скорости подготовки кэша и занятого места. Служебный процесс кэша отдаёт ожидаемый и загруженный размер по узлу и артефакту, пока заполняет локальный кэш узла.

Как импортировать из внешнего каталога?

Создайте кластерный ModelCatalogSource для внешнего каталога. Затем создайте локальный Model или ClusterModel с spec.source.catalog.name. spec.source.catalog.sourceName нужен только если доступно больше одного внешнего каталога.

Восстановится ли импорт после проблем с токеном или сертификатом?

Да, если ошибка на стороне источника. CatalogAuthFailed, CatalogTLSInvalid и CatalogSourceNotReady повторяются после того, как ModelCatalogSource снова перейдёт в фазу Ready. Контроллер сохраняет выбранную ревизию каталога и удалённую контрольную сумму, поэтому восстановление не переключит модель на другую версию незаметно.

ManifestInvalid, InsufficientStorage и нарушенный контракт каталога не повторяются автоматически. Сначала исправьте артефакт, лимит хранилища или спецификацию каталога.

Где взять токен для ModelCatalogSource?

На раздающем кластере администратор создаёт ServiceAccount для потребляющего кластера и привязывает его к ClusterRole d8:ai-models:distribution:reader. Затем администратор выпускает токен командой d8 k -n d8-ai-models create token <service-account> и передаёт администратору потребляющего кластера только значение токена по защищённому внешнему каналу. На потребляющем кластере этот токен кладётся в Secret в d8-system, а его имя указывается в ModelCatalogSource.spec.credentialsSecretName.

Модуль не ротирует этот токен сам: он не имеет доверенного доступа сразу к раздающему и потребляющему кластерам. Ротация выполняется выпуском нового токена на раздающем кластере и обновлением Secret на потребляющем кластере. Контроллер перечитает ModelCatalogSource после обновления Secret.

Отзыв доступа выполняется удалением RoleBinding или ServiceAccount на раздающем кластере.

Как подключить частный центр сертификации внешнего каталога?

Создайте Secret с ключом ca.crt в d8-system и укажите его имя в ModelCatalogSource.spec.caSecretName. Проверка TLS работает по принципу закрытого отказа: при неверном или отсутствующем сертификате источник получает условие с причиной CatalogTLSInvalid, CASecretMissing или InvalidCABundle.

Нужен ли SDS для работы?

Для подготовки Model и ClusterModel SDS не нужен. SDS нужен только для delivery.type=NodeCache. Режим SharedPVC требует StorageClass, который может создавать PVC с ReadWriteMany.

Как выбрать StorageClass для SharedPVC?

Задайте delivery.sharedPVCStorageClassName:

delivery:
  type: SharedPVC
  sharedPVCStorageClassName: rwx-storage-class

Пустое значение берёт global.modules.storageClass, затем global.defaultClusterStorageClass, затем default StorageClass Kubernetes. Если в кластере несколько default StorageClass, задайте значение явно в настройках модуля или в глобальных настройках Deckhouse.

Как задать размер node-cache?

delivery:
  type: NodeCache
  nodeCacheSize: 200Gi

Это размер кэша на каждом узле. То же значение используется для управляемого локального хранилища и PVC служебного процесса кэша.

Почему node-cache не стартует?

Проверьте выбранные ноды и BlockDevice:

d8 k get nodes --show-labels | grep ai.deckhouse.io/model-cache
d8 k get blockdevices.storage.deckhouse.io -o wide
d8 k describe blockdevice <block-device-name>

Диск должен быть свободным, без старых сигнатур LVM/FS, с состоянием consumable=true и меткой, которая совпадает с delivery.nodeCacheBlockDeviceSelector.

Где находится URL загрузки?

status.upload.secretName указывает на Secret в пространстве имён модели. В Secret есть ключи:

  • url — URL загрузки без токена в пути;
  • token — токен.

Для чтения Secret используйте Role ai-model-upload-reader-<model-name>, которую создал контроллер.

Что означает ошибка InsufficientStorage?

Значит artifacts.capacityLimit меньше уже занятого или зарезервированного места плюс размера новой модели. Для загрузки клиент должен передавать размер данных: обычный curl -T делает это через Content-Length.

Как работает Ollama URL?

Контроллер принимает URL вида https://ollama.com/library/<name>[:tag], читает манифест, конфигурацию и слои реестра, выбирает слой GGUF и проверяет контрольную сумму. HTML-страница Ollama и локальный демон Ollama не участвуют в подготовке модели.

Почему рабочая нагрузка не стартует до готовности модели?

Контроллер временно запрещает планирование Pod через Kubernetes scheduling gate и снимает это ограничение только после успешного разрешения модели и готовности выбранного способа доставки. Это защищает приложение от старта с пустой директорией модели.

Как избежать лишних изменений в GitOps?

В Git храните исходную рабочую нагрузку с аннотацией на верхнем metadata. Служебные тома, монтирования, переменные окружения и рассчитанные аннотации появляются в живом объекте после согласования контроллером.

Где смотреть диагностику?

d8 k -n d8-ai-models get pods -o wide
d8 k get models.ai.deckhouse.io -A
d8 k get clustermodels.ai.deckhouse.io
d8 k -n <namespace> describe model <name>

В Grafana используйте дашборды из группы модуля: обзор, объект каталога, подготовка, доставка и хранилище.