Стадия жизненного цикла модуля: Experimental
У модуля есть требования для установки
Руководство предназначено для пользователя пространства имён и оператора приложения.
Оно показывает, как создать модель, импортировать модель из внешнего каталога
и подключить модель в фазе Ready к рабочей нагрузке Kubernetes без ручной
настройки учётных данных реестра, initContainer и Secret.
Модуль не запускает среду инференса. Он готовит файлы модели в поддерживаемом формате и монтирует их в Pod, а приложение само читает эти файлы.
Быстрый старт
- Создайте
ModelилиClusterModelс одним источником:url,uploadилиcatalog. - Дождитесь
status.phase=Ready. - Добавьте
ai.deckhouse.io/modelилиai.deckhouse.io/clustermodelв верхнийmetadataрабочей нагрузки. - Проверьте, что Pod рабочей нагрузки стартовал и видит модель в
/data/modelcache/models/<model-name>.
Model или ClusterModel
| Ресурс | Область | Когда использовать |
|---|---|---|
Model |
пространство имён | Модель принадлежит одному пространству имён. |
ClusterModel |
кластер | Модель курируется администратором и доступна нескольким пространствам имён. |
Model может использовать Secret из своего пространства имён для приватного
репозитория Hugging Face. ClusterModel не ссылается на Secret из пространства
имён.
Что происходит после создания модели
После создания Model или ClusterModel модуль подготавливает локальную
копию модели, которой дальше пользуются рабочие нагрузки.
Этапы:
- Контроллер читает
spec.sourceи определяет, откуда получить данные. - Рабочий процесс получает данные из Hugging Face, Ollama, загрузочной сессии или внешнего каталога.
- Рабочий процесс проверяет формат, контрольную сумму и метаданные.
- Контроллер записывает
status.artifact.digest,status.artifact.sizeBytes,status.resolved.*и условия. status.phaseстановитсяReady, после чего модель можно подключать к рабочей нагрузке.
Внутренний путь в DMCR, тег и служебная контрольная сумма остаются внутренними
данными контроллера. Пользователь работает с именем Model или
ClusterModel.
status.phase: Ready означает, что данные модели проверены, локальная копия
сохранена в DMCR, а выбранный способ доставки может подготовить монтирование
для Pod.
Модель из Hugging Face
apiVersion: ai.deckhouse.io/v1alpha1
kind: Model
metadata:
name: bge-m3
namespace: ai-demo
spec:
source:
url: https://huggingface.co/BAAI/bge-m3Для приватного репозитория создайте Secret в том же пространстве имён.
Поддерживаются ключи token, HF_TOKEN, HUGGING_FACE_HUB_TOKEN.
apiVersion: v1
kind: Secret
metadata:
name: hf-private-token
namespace: ai-demo
type: Opaque
stringData:
token: hf_xxx
---
apiVersion: ai.deckhouse.io/v1alpha1
kind: Model
metadata:
name: private-llm
namespace: ai-demo
spec:
source:
url: https://huggingface.co/acme/private-llm
authSecretRef:
name: hf-private-tokenПроверка подготовки:
d8 k -n ai-demo get model bge-m3
d8 k -n ai-demo describe model bge-m3Модель из Ollama
apiVersion: ai.deckhouse.io/v1alpha1
kind: ClusterModel
metadata:
name: qwen-gguf
spec:
source:
url: https://ollama.com/library/qwen3.6:latestURL должен иметь вид https://ollama.com/library/<name>[:tag]. Контроллер
читает манифест, конфигурацию и слои реестра, выбирает один слой GGUF,
проверяет контрольную сумму и заголовок GGUF, затем сохраняет модель как
обычный OCI-артефакт каталога.
Ошибки формы URL попадают в status.phase=Failed с причиной
UnsupportedSource. Ошибки реестра, тега, манифеста, описателя или данных GGUF
попадают в status.phase=Failed с причиной PublicationFailed. Точный текст
ошибки смотрите в status.conditions.
Загрузка файла
Загрузка используется для локального файла или архива:
- прямой файл:
GGUF-модель, обычно файл*.gguf; - архивы:
tar,tar.gz,tgz,zip,tar.zst,tar.zstd,tzst; - содержимое архива:
GGUF,SafetensorsилиDiffusers.
Для Safetensors в архиве должен быть корневой config.json и один или
несколько файлов *.safetensors. Для Diffusers должен быть корневой
model_index.json и файлы весов *.safetensors или *.bin. Для GGUF
достаточно файла *.gguf.
apiVersion: ai.deckhouse.io/v1alpha1
kind: Model
metadata:
name: uploaded-model
namespace: ai-demo
spec:
source:
upload: {}После создания ресурс переходит в WaitForUpload. Имя Secret с URL загрузки и
токеном доступно в status.upload.secretName:
d8 k -n ai-demo get model uploaded-model -o jsonpath='{.status.upload.secretName}{"\n"}'Для загрузки нужен доступ get к этому Secret. Контроллер создаёт Role
ai-model-upload-reader-<model-name>, которая читает только один Secret.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: uploaded-model-uploader
namespace: ai-demo
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ai-model-upload-reader-uploaded-model
subjects:
- kind: ServiceAccount
name: model-uploader
namespace: ai-demoЗагрузите файл:
UPLOAD_SECRET=$(d8 k -n ai-demo get model uploaded-model -o jsonpath='{.status.upload.secretName}')
UPLOAD_URL=$(d8 k -n ai-demo get secret "$UPLOAD_SECRET" -o jsonpath='{.data.url}' | base64 -d)
UPLOAD_TOKEN=$(d8 k -n ai-demo get secret "$UPLOAD_SECRET" -o jsonpath='{.data.token}' | base64 -d)
curl -fS --progress-bar \
-H "Authorization: Bearer ${UPLOAD_TOKEN}" \
-T ./model.gguf \
"$UPLOAD_URL" | catДля архива передайте имя файла явно. По расширению контроллер определяет тип архива:
curl -fS --progress-bar \
-H "Authorization: Bearer ${UPLOAD_TOKEN}" \
-T ./model-bundle.zip \
"$UPLOAD_URL?filename=model-bundle.zip" | catИмпорт из внешнего каталога
Внешний каталог настраивает администратор. Пользователь выбирает модель по имени каталога, без контрольной суммы и OCI-ссылки:
apiVersion: ai.deckhouse.io/v1alpha1
kind: Model
metadata:
name: qwen3-8b
namespace: ai-demo
spec:
source:
catalog:
sourceName: dmz
name: qwen3-8bЕсли в кластере ровно один ModelCatalogSource в фазе Ready,
sourceName можно не указывать:
spec:
source:
catalog:
name: qwen3-8bКонтроллер фиксирует ревизию внешнего каталога и удалённую контрольную сумму в
status.source.catalog, копирует артефакт в локальный DMCR и
только затем переводит объект в Ready. Доставка в рабочую нагрузку всегда
использует локальную копию.
Если у внешнего каталога временно сломался токен, сертификат или готовность,
объект может перейти в Failed с причиной CatalogAuthFailed,
CatalogTLSInvalid или CatalogSourceNotReady. Эти состояния
восстанавливаются: после исправления Secret, сертификата, RBAC или состояния
источника контроллер повторяет импорт той же ревизии каталога и той же
удалённой контрольной суммы.
Статусы
| Фаза | Значение |
|---|---|
Pending |
Контроллер ожидает предварительную проверку или ещё не начал подготовку. |
WaitForUpload |
Создана сессия загрузки, нужно передать файл. |
Publishing |
Идёт подготовка модели: получение, проверка и сохранение локальной копии. |
Ready |
Данные модели проверены, локальная копия сохранена, метаданные рассчитаны. |
Failed |
Подготовка завершилась ошибкой. Причина указана в status.conditions. |
Deleting |
Выполняется очистка. |
Полезные поля:
status.artifact.digest— контрольная сумма подготовленного артефакта;status.artifact.sizeBytes— размер артефакта;status.resolved.format—Safetensors,GGUFилиDiffusers;status.resolved.family— семейство модели;status.resolved.supportedEndpointTypes— поддерживаемые типы конечных точек;status.resolved.supportedFeatures— возможности модели.
Для импорта из внешнего каталога полезны также:
status.source.catalog.sourceName— выбранныйModelCatalogSource;status.source.catalog.catalogRevision— ревизия каталога, по которой была выбрана модель;status.source.catalog.remoteDigest— контрольная сумма внешнего артефакта, который контроллер импортирует локально.
Типовые причины для импорта из внешнего каталога:
CatalogAuthFailed— не прошли учётные данные или RBAC внешнего каталога;CatalogTLSInvalid— сертификат внешнего каталога отсутствует или невалиден;CatalogSourceNotReady— внешний каталог ещё не готов;ManifestInvalid— импортированный артефакт не прошёл проверку;InsufficientStorage— в локальном DMCR не хватает места.
Подключение модели к рабочей нагрузке
Добавьте аннотацию в верхний metadata рабочей нагрузки. Это основной источник
выбора модели.
apiVersion: apps/v1
kind: Deployment
metadata:
name: embedder
namespace: ai-demo
annotations:
ai.deckhouse.io/model: bge-m3
spec:
selector:
matchLabels:
app: embedder
template:
metadata:
labels:
app: embedder
spec:
containers:
- name: app
image: registry.example.com/embedder:latestДля кластерной модели:
metadata:
annotations:
ai.deckhouse.io/clustermodel: gemma-smallДля нескольких моделей:
metadata:
annotations:
ai.deckhouse.io/model: bge-m3,bge-reranker
ai.deckhouse.io/clustermodel: gemma-smallКонтроллер сам добавляет выбранный способ доставки. В контейнере доступны:
AI_MODELS_MODELS_DIR=/data/modelcache/models;AI_MODELS_MODELS— JSON со списком моделей;- путь каждой модели:
/data/modelcache/models/<model-name>.
Имена моделей в одной рабочей нагрузке должны быть уникальными.
Удаление
d8 k -n ai-demo delete model bge-m3
d8 k delete clustermodel gemma-smallПосле удаления контроллер выполняет очистку через finalizer. Пока очистка
идёт, объект может оставаться в фазе Deleting.