Я пытаюсь развернуть функцию Python Azure на портале Azure с помощью конвейера сборки Azure DevOps. По какой-то причине код развертывается на сервере, но я получаю ошибку 404, пытаясь достичь конечной точки. Я получаю сообщение об ошибке 1 functions found (Custom) 0 functions loaded
, а также сообщение об ошибке ModuleNotFoundError: No module named 'requests'
на сервере. Я занимался этим уже несколько часов, но безуспешно. У меня есть следующие сведения об ошибке, которую я получаю (см. ниже). Мне интересно, может ли кто-нибудь помочь мне устранить неполадки и посмотреть, смогу ли я правильно развернуть этот конвейер DevOps. Пожалуйста, дайте мне знать, спасибо!
function_app.py:
import logging
import azure.functions as func
from src.api.controllers.etl_controller import ETLController
from src.helpers.configuration_helper import fetch_configurations
# Define your function
app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)
# Define your routes
@app.route(route = "run", methods=["POST"])
def run(req: func.HttpRequest) -> func.HttpResponse:
# Fetch updated configurations
fetch_configurations()
# Process the request
logging.info(f'Processing request: {req.method} {req.url}')
controller = ETLController()
return controller.run_elphi_etl(req)
функция.json:
{
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": ["post"]
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
хост.json:
{
"version": "2.0",
"functionTimeout": "00:30:00",
"logging": {
"logLevel": {
"default": "Debug"
},
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[4.*, 5.0.0)"
}
}
требования.txt:
asgiref==3.8.1
asn1crypto==1.5.1
azure-appconfiguration==1.6.0
azure-core==1.30.2
azure-core-tracing-opentelemetry==1.0.0b11
azure-functions==1.20.0
azure-identity==1.17.1
azure-keyvault-secrets==4.8.0
azure-monitor-opentelemetry==1.6.0
azure-monitor-opentelemetry-exporter==1.0.0b27
certifi==2024.7.4
cffi==1.16.0
cfgv==3.4.0
charset-normalizer==3.3.2
colorama==0.4.6
coverage==7.5.4
cryptography==42.0.8
debugpy==1.8.2
Deprecated==1.2.14
distlib==0.3.8
filelock==3.15.4
fixedint==0.1.6
flatten-json==0.1.14
identify==2.6.0
idna==3.7
importlib_metadata==8.0.0
iniconfig==2.0.0
isodate==0.6.1
msal==1.30.0
msal-extensions==1.2.0
msrest==0.7.1
nodeenv==1.9.1
oauthlib==3.2.2
opentelemetry-api==1.26.0
opentelemetry-instrumentation==0.47b0
opentelemetry-instrumentation-asgi==0.47b0
opentelemetry-instrumentation-dbapi==0.47b0
opentelemetry-instrumentation-django==0.47b0
opentelemetry-instrumentation-fastapi==0.47b0
opentelemetry-instrumentation-flask==0.47b0
opentelemetry-instrumentation-psycopg2==0.47b0
opentelemetry-instrumentation-requests==0.47b0
opentelemetry-instrumentation-urllib==0.47b0
opentelemetry-instrumentation-urllib3==0.47b0
opentelemetry-instrumentation-wsgi==0.47b0
opentelemetry-resource-detector-azure==0.1.5
opentelemetry-sdk==1.26.0
opentelemetry-semantic-conventions==0.47b0
opentelemetry-util-http==0.47b0
packaging==24.1
platformdirs==4.2.2
pluggy==1.5.0
portalocker==2.10.1
pre-commit==3.7.1
psutil==5.9.8
pycparser==2.22
PyJWT==2.8.0
pyOpenSSL==24.2.1
pytest==8.2.2
pytest-cov==5.0.0
python-dotenv==1.0.1
pytz==2024.1
pywin32==306; sys_platform == 'win32'
PyYAML==6.0.1
requests==2.32.3
requests-oauthlib==2.0.0
six==1.16.0
snowflake-connector-python==3.11.0
sortedcontainers==2.4.0
tomlkit==0.13.0
typing_extensions==4.12.2
urllib3==2.2.2
virtualenv==20.26.3
wrapt==1.16.0
zipp==3.19.2
azure-pipelines-dev.yaml:
trigger:
branches:
include:
- develop
pool:
vmImage: "ubuntu-latest"
variables:
PYTHON_VERSION: "3.11.8"
FUNCTIONAPP_NAME: "fn-elphi-etl-dev"
SERVICE_CONNECTION: "Elphi-ETL-Dev"
RESOURCE_GROUP: "fn-elphi-etl-dev"
PACKAGE_PATH: "$(Build.ArtifactStagingDirectory)/fn_elphi_etl.zip"
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: "$(PYTHON_VERSION)"
addToPath: true
displayName: "Install Python $(PYTHON_VERSION)"
- script: |
python -m pip install --upgrade pip
displayName: "Upgrade pip"
- script: |
python -m pip install -r requirements.txt
displayName: "Install dependencies"
- script: |
python -m pytest -v --cov=src --cov-report=term --cov-report=html --cov-report=xml:coverage.xml --junitxml=test-results.xml
displayName: "Run tests with coverage"
- task: PublishTestResults@2
inputs:
testResultsFormat: "JUnit"
testResultsFiles: "test-results.xml"
failTaskOnFailedTests: true
testRunTitle: "Pytest Results"
displayName: "Publish Pytest Results"
- script: |
mkdir -p $(Build.ArtifactStagingDirectory)/src
shopt -s dotglob
cp -r * $(Build.ArtifactStagingDirectory)/src/
ls -l $(Build.ArtifactStagingDirectory)/src
displayName: "Copy sources and all directories to artifact staging directory and list contents"
- task: ArchiveFiles@2
inputs:
rootFolderOrFile: "$(Build.ArtifactStagingDirectory)/src"
includeRootFolder: false
archiveType: "zip"
archiveFile: "$(PACKAGE_PATH)"
replaceExistingArchive: true
displayName: "Archive files"
- task: PublishPipelineArtifact@1
inputs:
targetPath: "$(Build.ArtifactStagingDirectory)/src"
artifact: "$(FUNCTIONAPP_NAME)"
displayName: "Publish Python project as artifact"
- task: PublishCodeCoverageResults@2
inputs:
summaryFileLocation: "$(Build.SourcesDirectory)/coverage.xml"
displayName: "Publish code coverage results"
- task: AzureFunctionApp@1
inputs:
azureSubscription: "$(SERVICE_CONNECTION)"
appType: "functionAppLinux"
appName: "$(FUNCTIONAPP_NAME)"
package: "$(PACKAGE_PATH)"
runtimeStack: "python|3.11"
startUpCommand: "func start"
displayName: "Deploy Azure Function App"
Логи сервера:
2024-07-26T17:36:54.860 [Information] Starting JobHost
2024-07-26T17:36:54.861 [Information] Starting Host (HostId=fn-elphi-etl-dev, InstanceId=f791376b-5871-4ad4-ab78-47b08af12162, Version=4.34.2.2, ProcessId=26, AppDomainId=1, InDebugMode=True, InDiagnosticMode=False, FunctionsExtensionVersion=~4)
2024-07-26T17:36:54.863 [Information] Loading functions metadata
2024-07-26T17:36:54.869 [Information] Reading functions metadata (Custom)
2024-07-26T17:36:54.871 [Information] 1 functions found (Custom)
2024-07-26T17:36:54.873 [Information] 0 functions loaded
2024-07-26T17:36:54.875 [Debug] FUNCTIONS_WORKER_RUNTIME value: 'python'
2024-07-26T17:36:54.876 [Debug] Adding Function descriptor provider for language python.
2024-07-26T17:36:54.876 [Debug] Creating function descriptors.
2024-07-26T17:36:54.877 [Debug] Function descriptors created.
2024-07-26T17:36:54.878 [Debug] Placeholder mode is enabled: False
2024-07-26T17:36:54.878 [Debug] RpcFunctionInvocationDispatcher received no functions
2024-07-26T17:36:54.878 [Information] Generating 0 job function(s)
2024-07-26T17:36:54.885 [Warning] No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
2024-07-26T17:36:54.888 [Information] Initializing function HTTP routes
2024-07-26T21:00:17.863 [Debug] Hosting starting
2024-07-26T21:00:17.950 [Information] Traceback (most recent call last):
2024-07-26T21:00:17.950 [Information] File "/azure-functions-host/workers/python/3.11/LINUX/X64/azure_functions_worker/utils/wrappers.py", line 44, in call
2024-07-26T21:00:17.950 [Information] return func(*args, **kwargs)
2024-07-26T21:00:17.950 [Information] ^^^^^^^^^^^^^^^^^^^^^
2024-07-26T21:00:17.950 [Information] File "/azure-functions-host/workers/python/3.11/LINUX/X64/azure_functions_worker/loader.py", line 238, in index_function_app
2024-07-26T21:00:17.950 [Information] imported_module = importlib.import_module(module_name)
2024-07-26T21:00:17.950 [Information] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-07-26T21:00:17.950 [Information] File "/usr/local/lib/python3.11/importlib/__init__.py", line 126, in import_module
2024-07-26T21:00:17.950 [Information] return _bootstrap._gcd_import(name[level:], package, level)
2024-07-26T21:00:17.950 [Information] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-07-26T21:00:17.950 [Information] File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
2024-07-26T21:00:17.950 [Information] File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
2024-07-26T21:00:17.950 [Information] File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
2024-07-26T21:00:17.950 [Information] File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
2024-07-26T21:00:17.950 [Information] File "<frozen importlib._bootstrap_external>", line 940, in exec_module
2024-07-26T21:00:17.950 [Information] File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
2024-07-26T21:00:17.950 [Information] File "/home/site/wwwroot/function_app.py", line 4, in <module>
2024-07-26T21:00:17.950 [Information] from src.api.controllers.etl_controller import ETLController
2024-07-26T21:00:17.950 [Information] File "/home/site/wwwroot/src/api/controllers/etl_controller.py", line 6, in <module>
2024-07-26T21:00:17.950 [Information] from src.api.services.etl_service import ETLService
2024-07-26T21:00:17.950 [Information] File "/home/site/wwwroot/src/api/services/etl_service.py", line 4, in <module>
2024-07-26T21:00:17.950 [Information] from src.api.services.elphi_service import ElphiService
2024-07-26T21:00:17.950 [Information] File "/home/site/wwwroot/src/api/services/elphi_service.py", line 3, in <module>
2024-07-26T21:00:17.950 [Information] from src.clients.elphi_client import ElphiClient
2024-07-26T21:00:17.950 [Information] File "/home/site/wwwroot/src/clients/elphi_client.py", line 3, in <module>
2024-07-26T21:00:17.950 [Information] import requests
2024-07-26T21:00:17.950 [Error] ModuleNotFoundError: No module named 'requests'
А вот файловая структура на сервере после развертывания:
Кроме того, если я запускаю func azure functionapp publish fn-elphi-etl-dev --build remote
на своем локальном компьютере, он работает правильно, и вместо этого я получаю следующую структуру папок:
Это функция Python V2? Если да, то у модели V2 нет function.json
. и привязки определены внутри файла function_app.py. Обратитесь к блогу .
Судя по вашим снимкам экрана, когда вы развертываете приложение-функцию на локальном компьютере, оно содержит папку .python_packages
. Требуемые пакеты (включая пакет запроса) будут сохранены в этой папке.
Но когда вы развертываете приложение-функцию через Azure Pipelines, оно не содержит .python_packages
. В этом случае пакеты не могут быть найдены при запуске функции Azure.
Чтобы решить эту проблему, вы можете добавить аргумент --target
в команду pip install, чтобы принудительно сохранить пакеты в правильной папке и убедиться, что эта папка может быть включена в zip-пакет:
Например:
python -m pip install --target = "./.python_packages/lib/site-packages" -r requirements.txt
Задача конвейера:
- script: |
python -m pip install --target = "./.python_packages/lib/site-packages" -r requirements.txt
displayName: "Install dependencies"
Для получения более подробной информации вы можете обратиться к этому документу: Примеры конвейеров сборки YAML
@AdamSteinberger Рад знать, что это может сработать для вас.
У меня тоже есть еще тонна журналов, но я думаю, что недостаточно символов, чтобы опубликовать все...