2025, Dec 23 00:03

Почему Python‑функции в Azure Functions на Linux Consumption не индексируются и как это исправить

Почему Linux Consumption Azure Functions не видны Python‑функции: исправляем упаковку zip, WEBSITE_RUN_FROM_PACKAGE=1, host.json в корне и настройку хранилища

В Azure Functions на тарифном плане Linux Consumption ваши Python‑эндпоинты могут незаметно игнорироваться, если пакет приложения собран с неправильной структурой или ключевые параметры не согласованы с моделью развертывания. Типичный признак — Function App запускается, но в портале и среде не появляется ни одной функции. Хорошая новость: обычно дело в упаковке и настройках, а не в логике обработчика.

Кратко о проблеме

Приложение было настроено на запуск из пакета в Azure Storage по SAS‑ссылке, однако список функций оставался пустым. Параметр выглядел так:

WEBSITE_RUN_FROM_PACKAGE = https://testfunc007.blob.core.windows.net/test123/HttpTrigger1.zip?sp=r&st=2025-05-28T02:39:29Z&se=2025-09-05T10:39:29Z&spr=https&sv=2024-11-04&sr=b&sig=zFH1y9KVNlibedwFVySop%2BbCnsSduX5UNrbwnVn7i8M%3D

Ожидаемая Python‑функция не появлялась во время индексации. Сам код — это простой HTTP‑триггер на модели программирования Python.

Пример кода, который должен был обнаружиться

Ниже — минимальный HTTP‑маршрут. При правильной упаковке и корректных настройках этот эндпоинт обнаруживается и вызывается.

import azure.functions as azf
import logging as log
fa = azf.FunctionApp(http_auth_level=azf.AuthLevel.ANONYMOUS)
@fa.route(route="http_trigger")
def ping(req: azf.HttpRequest) -> azf.HttpResponse:
    log.info("Hello Rithwik")
    return azf.HttpResponse("Rithwik", status_code=200)

Почему функция не отображалась

Индексация зависит от корректной структуры пакета и ряда параметров приложения. Если корень архива не соответствует тому, что ожидает Python‑воркер, Function App стартует, но не находит ни одного эндпоинта. Важен и способ развертывания: использование прямой SAS‑ссылки на пакет без согласования настроек Function App под план Consumption приводит к тому же результату — “функции не найдены”.

Здесь индексация воркером явно включена:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "AzureWebJobsFeatureFlags": "EnableWorkerIndexing"
  }
}

Если архив собран неверно, индексация завершается, но ничего не возвращает — будто приложение просто проигнорировало ваш Python‑код. В обсуждении также всплыла путаница с ресурсами хранилища: не смешивайте имя файловой общей папки (file share) и имя контейнера BLOB — это разные сущности, и в настройках они указываются по‑разному. Одна эта путаница способна сорвать упаковку и развертывание.

Что в итоге помогло

Сработали две вещи: правильная укладка проекта в корне архива и корректные параметры для плана Consumption. Рабочий архив имел следующую структуру на верхнем уровне zip:

<root>/
├── .vscode/
├── .venv/
├── .funcignore
├── .gitignore
├── function_app.py
├── host.json
├── local.settings.json
├── requirements.txt
└── __pycache__/

Перед развертыванием был добавлен такой параметр приложения:

"WEBSITE_RUN_FROM_PACKAGE": "1"

Для плана Consumption потребовалась также следующая настройка:

WEBSITE_CONTENTAZUREFILECONNECTIONSTRING

После публикации zip‑архива функции появились. Позже значение параметра run‑from‑package в портале изменилось, но важно, что обнаружение заработало сразу после корректировки пакета и настроек.

Развертывание выполнялось без VS Code, через CLI:

az functionapp deployment source config-zip -g "resgrpname" -n "funcanme" --src "test.zip"

Файл функции остался таким же, как выше; для полноты приведён тот же обработчик, который воркер успешно обнаружил после исправления структуры и настроек:

import azure.functions as azf
import logging as log
fa = azf.FunctionApp(http_auth_level=azf.AuthLevel.ANONYMOUS)
@fa.route(route="http_trigger")
def ping(req: azf.HttpRequest) -> azf.HttpResponse:
    log.info("Hello Rithwik")
    return azf.HttpResponse("Rithwik", status_code=200)

Почему это важно

В бессерверной среде обнаружение функций так же важно, как и сам код. Если рантайм не может их проиндексировать, вы будете отлаживать проблему “пропавшей функции”, не связанную с вашим обработчиком. Правильная структура zip‑архива и настройки, соответствующие типу плана, экономят часы проб и ошибок и помогают избежать вводящих в заблуждение проблем с конфигурацией хранилища.

Практические рекомендации

Держите host.json и точку входа Python в корне архива, не во вложенных папках. Включайте run‑from‑package простым значением “1” до загрузки zip и добавляйте обязательную для Consumption настройку хранилища, чтобы платформа смогла отработать. При развертывании через CLI используйте config‑zip с корректно собранным архивом. И, наконец, различайте имена файловых шар и контейнеров: указание не того ресурса в параметрах напрямую ведёт к “пропавшим функциям”.

Вывод

Если ваш Python Function App на Linux Consumption запускается, но не показывает функций, начните с упаковки и настроек. Чистая структура проекта в корне, WEBSITE_RUN_FROM_PACKAGE со значением 1 до развертывания и обязательный параметр хранилища для Consumption — этого оказалось достаточно, чтобы эндпоинты появились. С этими условиями даже минимальный HTTP‑триггер индексируется и становится доступным сразу после zip‑деплоя.