Стадия жизненного цикла модуляExperimental

У модуля есть требования для установки

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

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

Потому что платформа выбирает лучше, чем это может сделать манифест. Заказ называет класс и модель; ускоритель, его долю, размещение и оценки процессора, памяти и тома модели считают по настоящему железу кластера и возвращают в status.resolved.

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

Почему у заказа нет поля для среды исполнения?

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

Заказ, который всё же несёт блок среды исполнения, клиент со строгой проверкой полей отвергнет, а клиент без неё молча срежет.

Как узнать, какой договор API получил мой заказ?

Прочитайте status.model.endpointType. Он отвечает Chat, Embeddings или Rerank.

Это ваше единственное окно в этот выбор, и так задумано: договор выбирается из modelPolicy.allowedEndpointTypes класса, а прав на чтение классов пользователю namespace не дано.

Почему моя модель представлений обслужена как беседа?

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

Платформа берёт первый элемент перечня класса, суженного тем, что об умениях модели говорит источник. Из каталога ai-models, который такие сведения несёт, модель представлений получает договор представлений. По голой ссылке Hugging Face, которая не несёт ничего, стоит весь перечень и побеждает первый элемент, а во встроенном классе default-llm первый элемент — Chat.

Лечится классом, чей перечень называет один договор. Попросите администратора или посмотрите Примеры — там есть класс только для представлений.

Могу ли я прочитать класс, которым пользуется мой заказ?

Нет. Права на чтение классов пользователю namespace намеренно не даны. То, что класс решил о вашем заказе, возвращается в состояние самого заказа: status.model.endpointType для договора и status.constraints для границ числа копий и класса важности.

Заказ говорит ClassNotFound или ClassNotReady. Что делать?

Класса, который называет заказ, нет, либо он есть и не готов. Прочтите имя в своём же заказе — spec.inferenceServiceClassName — и сверьте с классами, которые поставил администратор. Этой причины следует ждать сразу после обновления, переименовавшего поставляемый класс: заказ, называющий прежнее имя, продолжает его называть, и никто не перепишет его за вас.

ClassNotReady вам не исправить: класс есть, и что-то в нём не сходится. Это к администратору.

Заказ говорит NamespaceNotAllowed. Что делать?

Класс не принимает заказы из вашего пространства имён. Перечень допуска живёт на классе, в admissionPolicy.allowedNamespaces, и расширить его может только администратор. Другой класс может вас принять.

Заказ говорит ModelNotFound или ModelNotReady. Что делать?

Ссылка на модель не разрешается, или модель есть, но не готова. Это ваше: проверьте идентификатор хранилища для источника Hugging Face либо имя объекта и kind для источника ai-models.

kind выбирает между Model в namespace и ClusterModel уровня кластера, а поле namespace внутри ref допустимо только для Model — другое сочетание сервер API отвергает при записи.

Заказ говорит InvalidModelSource. Что делать?

Ссылка на модель не той формы, какой требует источник. Это ваше, и быстрее всего смотреть spec.model: источнику Hugging Face нужен идентификатор хранилища, источнику ai-models — имя объекта и kind.

Заказ говорит AuthSecretNotFound. Что делать?

Заказ забирает модель, которой нужны учётные данные, а названной тайны в вашем пространстве имён нет. Заведите Secret или поправьте имя в spec.model.authSecretRef.

Заказ говорит EndpointTypePolicyConflict. Что делать?

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

Заказ говорит FormatNotAllowed или ParameterCountNotAllowed. Что делать?

Модель запрещена политикой класса: её формат не назван в allowedFormats либо число параметров превышает maxParameterCount. Другая модель или другой класс.

Заказ говорит CatalogDisabled. Что делать?

Связь с каталогом выключена в настройках модуля (catalog.mode: None), а заказ называет модель каталога. Либо назовите прямой источник Hugging Face, либо попросите изменить настройку. См. Конфигурацию.

Заказ говорит CatalogLookupFailed или CatalogKindNotServed. Что делать?

Каталог спросили о вашей модели, и он ответил бесполезно. CatalogLookupFailed означает, что не удался сам запрос — обычно это временно, и следующий проход спросит снова. CatalogKindNotServed означает, что каталог не обслуживает тот kind, который названа ваша ссылка, и это не временно: поправьте kind либо назовите прямой источник Hugging Face.

Заказ говорит NoCapacity, NoAcceleratorWithEnoughMemory или NoCompatiblePlacement. Что делать?

В большинстве случаев в кластере сейчас нет места: либо ничего не свободно, либо ни у одного ускорителя не хватает памяти под эту модель ни при какой доле, которую разрешает класс. Для этих двух ожидание — осмысленный ответ: вместимость величина подвижная, и план пересчитывается. status.resolved считает пересчёты в replanCount.

У NoCompatiblePlacement есть вторая причина, которую ожидание не лечит: профиль памяти оборудования, на которое сел бы заказ, неполон, и доля не вычисляется вовсе. Различить их даёт сообщение. Это уже сторона платформы, и нужен администратор.

Заказ говорит PlannerRequestFailed или PlanningPreemptionFailed. Что делать?

Платформа не смогла довести планирование вашего заказа до конца. Ни то, ни другое вам не исправить, и ни то, ни другое не окончательно: первое означает, что планировщик не ответил, второе — что освободить ёмкость под ваш заказ не вышло. Оба повторяются. Если что-то из них держится долго — это к администратору.

Заказ говорит LaunchPlanNotAPlacement. Что делать?

Сохранённая настройка пуска вашего заказа описывает не размещение: одно из её полей превратило бы заявку на устройство или учёт ёмкости в то, чего никто не просил. Сообщение называет поле и значение — доля вне 1..100, ускоритель без класса устройства, объём памяти, которого класс не несёт.

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

Заказ говорит PriorityClassNotFound. Что делать?

Класса приоритета, который называет класс вашего заказа, в кластере нет. Своего приоритета заказ не называет, поэтому исправляет это администратор.

Заказ говорит QuantizationMismatch или NoCompatibleRuntimeAvailable. Что делать?

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

Чем ResourceClaimExhausted отличается от PlacementUndecidable?

Это самое полезное различие на странице, потому что причины выглядят похоже, а требуют противоположного.

  • ResourceClaimExhausted — поиск был. Перебраны все классы устройств, которые заказу разрешено было пробовать, и ни один его не держит. Предмет здесь — вместимость: искать место или ждать, когда появится;
  • PlacementUndecidable — поиск не начинался. Пробовать было нечего, потому что класс нельзя рассудить вовсе. Предмет здесь — класс: его выражению отбора нужен взгляд администратора, а ожидание не ответ.

Если видите вторую — не ждите, что она пройдёт сама. Не пройдёт.

Заказ говорит ResourceClaimPending. Это ошибка?

Нет. Рабочая нагрузка ждёт, когда её заявка на ресурс будет удовлетворена. Это шаг, а не отказ.

Заказ говорит WorkloadNotReady или WorkloadError. Что делать?

Это две половины рабочей нагрузки заказа, и ответы у них разные. WorkloadNotReady означает, что объекты созданы, а копии ещё не поднялись: тянется образ, скачивается модель, ждётся узел. Это проходит само.

WorkloadError означает, что объекты не удалось применить либо нагрузку отвергает кластер, и само это не проходит. Сообщение называет, что именно не вышло. Один случай стоит знать: нагрузка, чей том заказ перерос, отвергается навсегда, потому что том нельзя переразмерить — заказ несёт об этом событие SettledRegionTooSmall, а порядок действий описан в замечаниях о выпуске.

Заказ говорит WorkloadStartupFailed. Что делать?

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

Отличие от WorkloadNotReady — в том, чего ждать. Там копии ещё поднимаются, и это проходит само. Здесь узел уже сказал, что запуск не удался, и следующая попытка кончится тем же: нужна правка — образа, настроек заказа или его окружения.

Сообщение несёт и то, что напечатал сам контейнер перед смертью: несколько строк его вывода, где описана ошибка. Имя состояния CrashLoopBackOff говорит, что контейнер падал, а строки вывода — отчего именно: не хватило видеопамяти, не нашёлся файл весов, не сошлась настройка. Если строк нет, вывода получить не удалось — контейнер мог не стартовать вовсе, например когда не тянется образ.

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

Отказ снимается сам, как только под поднялся: правка заказа для выхода не требуется, если её и не требовалось. Нагрузка при отказе остаётся на месте, поэтому подъём пода модуль увидит.

Заказ в состоянии Degraded, но точка доступа отвечает. Что не так?

Ровно то, что сказано: API инференса работает, а рост числа копий заблокирован. Причина обычно ScaleUpBlocked — вытеснение исчерпало вместимость, нужную автоматике роста, чтобы вырастить заказ.

Ваша точка доступа продолжает обслуживать. Чего у вас нет — так это запаса.

Условие Planned говорит LaunchPlanInForce. Заказ сломан?

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

Почему пересчёт вообще может не удаться у работающего заказа: речь о вместимости помимо места, которое заказ уже держит. Само это место планировщик видит: драйвер снимает занятое устройство с публикации, но заказ передаёт удерживаемое отдельно, и пересчёт учитывает его как доступное себе.

Что делать: обычно ничего. Если вам нужен рост, ищите свободную вместимость на классе устройств заказа — причины NoCapacity и NoAcceleratorWithEnoughMemory в message называют, чего не хватило. Отказ о нехватке памяти называет требуемый объём и наибольший найденный, так что «модель велика для парка» и «в парке сейчас нет крупного устройства» различимы по одному сообщению.

Заказ готов, но вторая копия не появляется. На заказе событие GrowthClaimUnplaced

Заказу не хватает места для роста, и это всё. Копия, которую просит автоматика роста, не получила устройства; копии, без которых заказ не обслуживается, устройства держат, поэтому заказ остаётся готовым и остаётся на своём классе устройств.

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

Что делать: искать свободную вместимость на классе устройств заказа. Как только раздел освободится, планировщик кластера поставит ждущую копию сам — ничего перепланировать не нужно. Текст события называет, что именно сказала заявка.

Заказ говорит ServiceUnhealthy. Чем это отличается от HealthCheckFailed?

И то и другое — опрос состояния, в двух разных точках жизни заказа:

  • HealthCheckFailed при состоянии Pending — заказ ни разу не был готов. Он ещё поднимается, и опрос пока не удался;
  • ServiceUnhealthy при состоянии Failed — заказ был готов, а потом API перестал отвечать, и достаточно долго, чтобы отказ не был случайным.

Что значит каждое состояние?

Состояние Смысл
Pending согласование ещё не завершилось успешно
Ready заказ обслуживает свой API инференса
Degraded API инференса работает, но рост числа копий заблокирован
Failed согласование остановилось на устойчивой ошибке

Когда что-то не так, читайте условия, а не состояние: состояние говорит, что что-то не так, условия — что именно.

Где смотреть при разборе?

kubectl get inferenceservice <имя> -n <namespace> \
  -o jsonpath='{range .status.conditions[*]}{.type}{"="}{.status}{" "}{.reason}{"\n"}{end}'

Пять условий отвечают по порядку — ClassResolved, ModelResolved, Planned, WorkloadReady, Ready, — поэтому смотреть надо на первое, которое не True. Шестое, ScalingHealthy, про рост, а не про готовность, и True у него означает благополучие.

Почему у моего заказа только одна копия?

Потому что его класс не называет scalingPolicy. Класс без этого блока даёт своим заказам одну копию и никакой автоматики роста — это решение о вместимости, которое модуль за администратора не принимает.

status.constraints показывает границы, действующие для вашего заказа.

Что происходит с объектами при удалении заказа?

Всё, чем заказ владеет, уходит вместе с ним: рабочая нагрузка, служба, объекты публикации и Secret с токеном доступа. Все они несут ownerReferences на заказ.

Ваш собственный Secret с токеном Hugging Face заказу не принадлежит и остаётся на месте.

Нужен ли модулю установленный ai-models?

Нет. Заказы, называющие прямой источник Hugging Face, работают без него. Для кластера, где каталог не установлен, задайте в настройках модуля catalog.mode: None, и клиенты каталога вместе с их правами создаваться не будут.

Что убрать перед отключением модуля?

Сначала удалите каждый InferenceService во всех namespace, затем объекты InferenceServiceClass, на которые эти namespace ссылались. Отключение останавливает контроллер и планировщик ресурсов, а вместе с ними — каждую рабочую нагрузку заказа; отключение без уборки оставляет объекты заказов в кластере, и согласовывать их будет некому.