You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从单仓部署Python Azure Function应用并配置入口及依赖?

问题描述

我拥有一个包含Flask API及多个Azure Function应用的单仓(mono-repo),现尝试通过Azure DevOps流水线将其中一个Function应用部署至Azure。

Python代码结构如下:

./backend
./backend/domain/             - 包含领域逻辑的.py文件
./backend/entrypoints/api     - 包含Flask应用文件
./backend/entrypoints/my-func - 我的新Function应用目录
./backend/...                 - 其他被导入的层级文件夹

已配置AzureFunctionApp@2任务将项目压缩包推送至存储账户,但在Azure门户中看不到已注册的函数,流水线任务代码如下:

- task: ArchiveFiles@2
  displayName: Package Function Apps
  inputs:
    rootFolderOrFile: $(Build.SourcesDirectory)
    archiveType: 'zip'
    archiveFile: '$(Build.ArtifactStagingDirectory)/nightly-import-$(Build.BuildId).zip'
    verbose: true

- task: AzureFunctionApp@2
  displayName: Deploy Nightly Importer
  inputs:
    azureSubscription: ${{parameters.azureServiceConnection}}
    appType: functionAppLinux
    appName: nightly-import-${{parameters.environmentMoniker}}-uks-01
    package: '$(Pipeline.Workspace)/FuncAppsPackage/nightly-import-$(Build.BuildId).zip'
    deploymentMethod: auto
    verbose: true

需要解决:如何从单仓中发布Function应用,确保包含所有依赖(包括venv中的pip包及Function应用文件夹外的backend/domain等内部Python模块),并告知Azure应用入口点?


解决方案

1. 调整归档范围与目录结构

当前归档整个源码目录会导致Azure Function无法识别正确的Function根目录,需要先整理文件结构再归档:

  • 将目标Function的目录作为根目录,同时把整个backend目录复制到该根目录下,确保内部模块能被正常导入
  • 通过CopyFiles任务先完成文件整理,再执行归档

修改流水线任务如下:

# 复制共享的backend模块到临时Function目录
- task: CopyFiles@2
  displayName: Copy Shared Backend Modules
  inputs:
    SourceFolder: $(Build.SourcesDirectory)/backend
    TargetFolder: $(Build.ArtifactStagingDirectory)/my-func/backend
    CleanTargetFolder: true

# 复制Function应用自身的文件到临时根目录
- task: CopyFiles@2
  displayName: Copy Function App Files
  inputs:
    SourceFolder: $(Build.SourcesDirectory)/backend/entrypoints/my-func
    TargetFolder: $(Build.ArtifactStagingDirectory)/my-func
    CleanTargetFolder: false

# 归档整理好的Function目录
- task: ArchiveFiles@2
  displayName: Package Function App
  inputs:
    rootFolderOrFile: $(Build.ArtifactStagingDirectory)/my-func
    archiveType: 'zip'
    archiveFile: '$(Build.ArtifactStagingDirectory)/nightly-import-$(Build.BuildId).zip'
    verbose: true

2. 安装依赖到归档目录

Linux环境的Azure Function需要把依赖包放在指定路径,推荐通过requirements.txt安装到临时Function目录:

# 指定与Azure Function匹配的Python版本
- task: UsePythonVersion@0
  inputs:
    versionSpec: '3.10'
    addToPath: true

# 安装依赖到Function目录的指定路径
- script: |
    python -m pip install --upgrade pip
    pip install -r $(Build.SourcesDirectory)/backend/entrypoints/my-func/requirements.txt -t $(Build.ArtifactStagingDirectory)/my-func/.python_packages/lib/site-packages
  displayName: Install Function Dependencies

注意:内部模块(如backend/domain)不需要在requirements.txt中声明,只要目录结构正确就能被Python识别导入。

3. 配置Function入口点

确保Azure Function能识别触发器位置:

  • 检查Function目录下的function.json,确认scriptFile路径正确,示例:
{
  "scriptFile": "__init__.py",
  "bindings": [
    // 你的触发器配置
  ]
}
  • 如果使用function_app.py作为入口文件,需要在Azure门户的应用设置中添加以下配置:
    • FUNCTIONS_WORKER_RUNTIME_VERSION = 3.10(匹配Python版本)
    • FUNCTIONS_EXTENSION_VERSION = ~4
    • AzureWebJobsScriptRoot = __app__

4. 修正部署任务配置

明确指定部署方式和运行时栈,避免自动检测的不确定性:

# 先下载之前归档的工件(如果有发布步骤的话)
- task: DownloadBuildArtifacts@0
  inputs:
    buildType: 'current'
    downloadType: 'single'
    artifactName: 'FuncAppsPackage'
    downloadPath: '$(Pipeline.Workspace)'

# 部署到Azure Function
- task: AzureFunctionApp@2
  displayName: Deploy Nightly Importer
  inputs:
    azureSubscription: ${{parameters.azureServiceConnection}}
    appType: functionAppLinux
    appName: nightly-import-${{parameters.environmentMoniker}}-uks-01
    package: '$(Pipeline.Workspace)/FuncAppsPackage/nightly-import-$(Build.BuildId).zip'
    deploymentMethod: 'zipDeploy'
    runtimeStack: 'PYTHON|3.10'
    verbose: true

5. 验证内部模块导入

在Function代码中使用正确的导入路径,示例:

from backend.domain import your_domain_logic

因为我们已经将backend目录放在Function根目录下,Python会自动识别这个模块。


内容的提问来源于stack exchange,提问作者Greg B

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 22:21:07