Share via


依存関係またはサードパーティ製ライブラリを Azure Functions に取り込む

この記事では、サードパーティの依存関係を関数アプリに取り込む方法について説明します。 サードパーティの依存関係の例としては、JSON ファイル、バイナリ ファイル、機械学習モデルがあります。

この記事では、次のことについて説明します。

  • Functions Code プロジェクトを使用して依存関係を取り込む
  • Azure Fileshare をマウントして依存関係を取り込む

プロジェクト ディレクトリから依存関係を取り込む

依存関係を取り込む最も簡単な方法の 1 つは、ファイル/成果物を Functions プロジェクトディレクトリ構造の関数アプリ コードと一緒に置く方法です。 Python 関数プロジェクトのディレクトリ サンプルの例を次に示します。

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

Functions アプリ プロジェクト ディレクトリ内のフォルダーに依存関係を配置すると、dependencies フォルダーがコードと共にデプロイされます。 その結果、関数コードは、ファイル システム 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)

Note

Linux 環境で ffmpeg バイナリに Execute 権限を提供するために chmod を使用する必要がある場合があります

依存関係を取り込む最も簡単な方法の 1 つは、ファイル/成果物を Functions プロジェクトディレクトリ構造の関数アプリ コードと一緒に置く方法です。 Java 関数プロジェクトのディレクトリ サンプルの例を次に示します。

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

特に Java の場合は、リソースをコピーするときに、ビルド/ターゲット フォルダーに成果物を具体的に含める必要があります。 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>
...

Functions アプリ プロジェクト ディレクトリ内のフォルダーに依存関係を配置すると、dependencies フォルダーがコードと共にデプロイされます。 その結果、関数コードは、ファイル システム 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();

    }

Note

このコード スニペットを Azure で動作させるには、「/home/site/wwwroot」の値を使用して 「BASE_PATH」のカスタムアプリケーション設定を指定する必要があります。

ファイル共有をマウントして依存関係を取り込む

Linux で関数アプリを実行する場合は、サードパーティの依存関係を取り込む別の方法があります。 Functions を使用すると、Azure Files でホストされているファイル共有をマウントできます。 アプリケーション コードから依存関係または成果物を分離する場合は、この方法を検討してください。

まず、Azure ストレージ アカウントを作成する必要があります。 アカウントでは、Azure files でファイル共有を作成する必要もあります。 これらのリソースを作成するには、こちらのガイドに従ってください

ストレージアカウントとファイル共有を作成した後、次の例に示すように、 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 Pre-existing share
mount-path コンテナー内で共有にアクセスできるパス。 値は /dir-name 形式である必要があり、/home で始めることはできません

ファイル共有の構成を変更または削除するその他のコマンドについては、こちらを参照してください

依存関係を Azure Files にアップロードする

依存関係を Azure Files にアップロードするには、Azure portal を使用することもオプションの 1 つです。 ポータルを使用して依存関係をアップロードする手順については、この ガイド を参照してください。 依存関係を Azure Files にアップロードするその他のオプションには、Azure CLIPowerShell の使用もあります。

コード内の依存関係へのアクセス

ファイル共有に依存関係がアップロードされると、コードから依存関係にアクセスできます。 マウントされた共有は、/path/to/mount など指定された 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"
  }
}

次のステップ