Share via


Portare le dipendenze o la libreria di terze parti in Funzioni di Azure

Questo articolo illustra come inserire dipendenze di terze parti nelle app per le funzioni. Esempi di dipendenze di terze parti sono file JSON, file binari e modelli di Machine Learning.

In questo articolo vengono illustrate le operazioni seguenti:

  • Inserire dipendenze tramite il progetto codice di Funzioni
  • Inserire le dipendenze tramite il montaggio della condivisione file di Azure

Inserire dipendenze dalla directory del progetto

Uno dei modi più semplici per inserire le dipendenze consiste nell'inserire i file/artefatti insieme al codice dell'app per le funzioni nella struttura di directory del progetto Funzioni. Di seguito è riportato un esempio di esempi di directory in un progetto di funzioni Python:

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

Inserendo le dipendenze in una cartella all'interno della directory del progetto dell'app per le funzioni, la cartella dependencies verrà distribuita insieme al codice. Di conseguenza, il codice della funzione può accedere alle dipendenze nel cloud tramite l'API del file system.

Accesso alle dipendenze nel codice

Ecco un esempio per accedere ed eseguire ffmpeg le dipendenze inserite nella <project_root>/ffmpeg_lib directory.

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)

Nota

Potrebbe essere necessario usare chmod per fornire Execute diritti al file binario ffmpeg in un ambiente Linux

Uno dei modi più semplici per inserire le dipendenze consiste nell'inserire i file/artefatti insieme al codice dell'app per le funzioni nella struttura di directory del progetto di funzioni. Ecco un esempio di esempi di directory in un progetto di funzioni Java:

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

Per Java in particolare, è necessario includere in modo specifico gli artefatti nella cartella di compilazione/destinazione durante la copia delle risorse. Ecco un esempio su come eseguire questa operazione in 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>
...

Inserendo le dipendenze in una cartella all'interno della directory del progetto dell'app per le funzioni, la cartella dependencies verrà distribuita insieme al codice. Di conseguenza, il codice della funzione può accedere alle dipendenze nel cloud tramite l'API del file system.

Accesso alle dipendenze nel codice

Ecco un esempio per accedere ed eseguire ffmpeg le dipendenze inserite nella <project_root>/ffmpeg_lib directory.

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();

    }

Nota

Per ottenere il funzionamento di questo frammento di codice in Azure, è necessario specificare un'impostazione dell'applicazione personalizzata "BASE_PATH" con il valore "/home/site/wwwroot"

Portare le dipendenze montando una condivisione file

Quando si esegue l'app per le funzioni in Linux, esiste un altro modo per introdurre dipendenze di terze parti. Funzioni consente di montare una condivisione file ospitata in File di Azure. Prendere in considerazione questo approccio quando si vogliono separare le dipendenze o gli artefatti dal codice dell'applicazione.

Prima di tutto, è necessario creare un account di archiviazione di Azure. Nell'account è anche necessario creare una condivisione file in file di Azure. Per creare queste risorse, seguire questa guida

Dopo aver creato l'account di archiviazione e la condivisione file, usare il comando az webapp config storage-account add per collegare la condivisione file all'app per le funzioni, come illustrato nell'esempio seguente.

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>
Flag valore
custom-id Qualsiasi stringa univoca
tipo di archiviazione Attualmente è supportato solo AzureFiles
share-name Condivisione preesistente
mount-path Percorso in cui la condivisione sarà accessibile all'interno del contenitore. Il valore deve essere del formato /dir-name e non può iniziare con /home

Altri comandi per modificare/eliminare la configurazione della condivisione file sono disponibili qui

Caricamento delle dipendenze in File di Azure

Un'opzione per caricare la dipendenza in File di Azure è tramite portale di Azure. Per istruzioni sul caricamento delle dipendenze tramite il portale, vedere questa guida . Altre opzioni per caricare le dipendenze in File di Azure sono tramite l'interfaccia della riga di comando di Azure e PowerShell.

Accesso alle dipendenze nel codice

Dopo aver caricato le dipendenze nella condivisione file, è possibile accedere alle dipendenze dal codice. La condivisione montata è disponibile nel percorso di montaggio specificato, ad esempio /path/to/mount. È possibile accedere alla directory di destinazione usando le API del file system.

Nell'esempio seguente viene illustrato il codice trigger HTTP che accede alla ffmpeg libreria, archiviata in una condivisione file montata.

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)

Quando si distribuisce questo codice in un'app per le funzioni in Azure, è necessario creare un'impostazione dell'app con un nome di chiave e FILE_SHARE_MOUNT_PATH il valore del percorso della condivisione file montata, che per questo esempio è /azure-files-share. Per eseguire il debug locale, è necessario popolare con il FILE_SHARE_MOUNT_PATH percorso del file in cui sono archiviate le dipendenze nel computer locale. Ecco un esempio da impostare FILE_SHARE_MOUNT_PATH usando local.settings.json:

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

Passaggi successivi