你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

将依赖项或第三方库引入 Azure Functions

本文介绍如何将第三方依赖项引入函数应用。 第三方依赖项示例为 json 文件、二进制文件和机器学习模型。

在本文中,学习如何:

  • 通过 Functions Code 项目引入依赖项
  • 通过装载 Azure Fileshare 引入依赖项

从项目目录引入依赖项

引入依赖项的最简单方法之一是将文件/项目与函数应用代码一起放入函数项目目录结构。 以下示例是 Python 函数项目中的目录示例:

<project_root>/
 | - my_first_function/
 | | - __init__.py
 | | - function.json
 | | - example.py
 | - dependencies/
 | | - dependency1
 | - .funcignore
 | - host.json
 | - local.settings.json

通过将依赖项放入函数应用项目目录中的文件夹,依赖项文件夹将与代码一起部署。 因此,函数代码可以通过文件系统 API 访问云中的依赖项。

访问代码中的依赖项

以下举例说明了如何访问和执行放入 <project_root>/ffmpeg_lib 目录中的 ffmpeg 依赖项。

import logging

import azure.functions as func
import subprocess

FFMPEG_RELATIVE_PATH = "../ffmpeg_lib/ffmpeg"

def main(req: func.HttpRequest,
         context: func.Context) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    command = req.params.get('command')
    # If no command specified, set the command to help
    if not command:
        command = "-h"

    # context.function_directory returns the current directory in which functions is executed 
    ffmpeg_path = "/".join([str(context.function_directory), FFMPEG_RELATIVE_PATH])

    try:
        byte_output  = subprocess.check_output([ffmpeg_path, command])
        return func.HttpResponse(byte_output.decode('UTF-8').rstrip(),status_code=200)
    except Exception as e:
        return func.HttpResponse("Unexpected exception happened when executing ffmpeg. Error message:" + str(e),status_code=200)

注意

可能需使用 chmod 为 Linux 环境中的 ffmpeg 二进制文件提供 Execute 权限

引入依赖项的最简单方法之一是将文件/项目与函数应用代码一起放入函数项目目录结构。 以下示例是 Java 函数项目中的目录示例:

<project_root>/
 | - src/
 | | - main/java/com/function
 | | | - Function.java
 | | - test/java/com/function
 | - artifacts/
 | | - dependency1
 | - host.json
 | - local.settings.json
 | - pom.xml

特别是对于 Java,需在复制资源时专门将项目添加到 build/target 文件夹。 以下示例介绍如何在 Maven 中执行此操作:

...
<execution>
    <id>copy-resources</id>
    <phase>package</phase>
    <goals>
        <goal>copy-resources</goal>
    </goals>
    <configuration>
        <overwrite>true</overwrite>
        <outputDirectory>${stagingDirectory}</outputDirectory>
        <resources>
            <resource>
                <directory>${project.basedir}</directory>
                <includes>
                    <include>host.json</include>
                    <include>local.settings.json</include>
                    <include>artifacts/**</include>
                </includes>
            </resource>
        </resources>
    </configuration>
</execution>
...

通过将依赖项放入函数应用项目目录中的文件夹,依赖项文件夹将与代码一起部署。 因此,函数代码可以通过文件系统 API 访问云中的依赖项。

访问代码中的依赖项

以下举例说明了如何访问和执行放入 <project_root>/ffmpeg_lib 目录中的 ffmpeg 依赖项。

public class Function {
    final static String BASE_PATH = "BASE_PATH";
    final static String FFMPEG_PATH = "/artifacts/ffmpeg/ffmpeg.exe";
    final static String HELP_FLAG = "-h";
    final static String COMMAND_QUERY = "command";

    @FunctionName("HttpExample")
    public HttpResponseMessage run(
            @HttpTrigger(
                name = "req",
                methods = {HttpMethod.GET, HttpMethod.POST},
                authLevel = AuthorizationLevel.ANONYMOUS)
                HttpRequestMessage<Optional<String>> request,
            final ExecutionContext context) throws IOException{
        context.getLogger().info("Java HTTP trigger processed a request.");

        // Parse query parameter
        String flags = request.getQueryParameters().get(COMMAND_QUERY);

        if (flags == null || flags.isBlank()) {
            flags = HELP_FLAG;
        }

        Runtime rt = Runtime.getRuntime();
        String[] commands = { System.getenv(BASE_PATH) + FFMPEG_PATH, flags};
        Process proc = rt.exec(commands);

        BufferedReader stdInput = new BufferedReader(new 
        InputStreamReader(proc.getInputStream()));

        String out = stdInput.lines().collect(Collectors.joining("\n"));
        if(out.isEmpty()) {
            BufferedReader stdError = new BufferedReader(new 
                InputStreamReader(proc.getErrorStream()));
            out = stdError.lines().collect(Collectors.joining("\n"));
        }
        return request.createResponseBuilder(HttpStatus.OK).body(out).build();

    }

注意

若要使这段代码在 Azure 中正常运行,需指定自定义应用程序设置“BASE_PATH”,并将值设置为“/home/site/wwwroot”

通过装载文件共享引入依赖项

在 Linux 上运行函数应用时,还可以通过另一种方式引入第三方依赖项。 Functions 允许装载 Azure 文件存储中托管的文件共享。 要将依赖项或项目与应用程序代码分离时,请考虑使用该方法。

首先,需创建 Azure 存储帐户。 在帐户中,还需在 Azure 文件中创建文件共享。 若要创建这些资源,请遵循此指南

创建存储帐户和文件共享后,使用 az webapp config storage-account add 命令将文件共享附加到函数应用,如下例所示。

az webapp config storage-account add \
  --name < Function-App-Name > \
  --resource-group < Resource-Group > \
  --subscription < Subscription-Id > \
  --custom-id < Unique-Custom-Id > \
  --storage-type AzureFiles \
  --account-name < Storage-Account-Name > \
  --share-name < File-Share-Name >  \
  --access-key < Storage-Account-AccessKey > \
  --mount-path </path/to/mount>
标志
custom-id 任何唯一字符串
storage-type 目前仅支持 AzureFiles
share-name 现存共享
mount-path 容器内可访问共享的路径。 值必须为 /dir-name 格式,并且不能以 /home 开头

可在此处查找更多用于修改/删除文件共享配置的命令

将依赖项上传到 Azure 文件存储

可以选择通过 Azure 门户将依赖项上传到 Azure 文件存储。 有关通过门户上传依赖项的说明,请参阅此指南。 还可以选择通过 Azure CLIPowerShell 将依赖项上传到 Azure 文件存储。

访问代码中的依赖项

在文件共享中上传依赖项后,可以通过代码访问依赖项。 指定的 mount-path(例如 )提供了装载的共享。 可以使用文件系统 API 访问目标目录。

以下示例显示了可访问 ffmpeg 库的 HTTP 触发器代码,该代码存储在装载的文件共享中。

import logging

import azure.functions as func
import subprocess 

FILE_SHARE_MOUNT_PATH = os.environ['FILE_SHARE_MOUNT_PATH']
FFMPEG = "ffmpeg"

def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    command = req.params.get('command')
    # If no command specified, set the command to help
    if not command:
        command = "-h"

    try:
        byte_output  = subprocess.check_output(["/".join(FILE_SHARE_MOUNT_PATH, FFMPEG), command])
        return func.HttpResponse(byte_output.decode('UTF-8').rstrip(),status_code=200)
    except Exception as e:
        return func.HttpResponse("Unexpected exception happened when executing ffmpeg. Error message:" + str(e),status_code=200)

将此代码部署到 Azure 中的函数应用时,需创建应用设置,并将键名设置为 FILE_SHARE_MOUNT_PATH,将值设置为装载的文件共享路径(本例中为 /azure-files-share)。 若要进行本地调试,需在 FILE_SHARE_MOUNT_PATH 中填充在本地计算机中存储依赖项的文件路径。 以下举例说明了如何使用 local.settings.json 设置 FILE_SHARE_MOUNT_PATH

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "python",
    "FILE_SHARE_MOUNT_PATH" : "PATH_TO_LOCAL_FFMPEG_DIR"
  }
}

后续步骤