Share via


Traslado de dependencias o bibliotecas de terceros a Azure Functions

En este artículo, aprenderá a trasladar dependencias de terceros a las aplicaciones de funciones. Algunos ejemplos de dependencias de terceros son los archivos JSON, los archivos binarios y los modelos de aprendizaje automático.

En este artículo aprenderá a:

  • Trasladar dependencias mediante un proyecto de código de Functions
  • Trasladar dependencias mediante el montaje de un recurso compartido de archivos de Azure

Trasladar dependencias desde el directorio del proyecto

Una de las formas más sencillas de trasladar dependencias es colocar los archivos o artefactos junto con el código de la aplicación de funciones en la estructura de directorios del proyecto de Functions. Este es uno de los ejemplos de directorio de un proyecto de funciones de Python:

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

Al colocar las dependencias en una carpeta dentro del directorio del proyecto de la aplicación de funciones, la carpeta de dependencias se implementará junto con el código. Como resultado, el código de función puede acceder a las dependencias en la nube mediante la API del sistema de archivos.

Acceso a las dependencias del código

En este ejemplo se accede y se ejecuta la dependencia ffmpeg que se encuentra en el directorio <project_root>/ffmpeg_lib.

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

Puede que tenga que usar chmod para proporcionar derechos Execute al binario ffmpeg en un entorno Linux.

Una de las formas más sencillas de trasladar dependencias es colocar los archivos o artefactos junto con el código de la aplicación de funciones en la estructura de directorios del proyecto de Functions. Este es uno de los ejemplos de directorio de un proyecto de funciones de Java:

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

En el caso concreto de Java, debe incluir específicamente los artefactos en la carpeta de creación o destino al copiar recursos. Este es un ejemplo de cómo se hace en 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>
...

Al colocar las dependencias en una carpeta dentro del directorio del proyecto de la aplicación de funciones, la carpeta de dependencias se implementará junto con el código. Como resultado, el código de función puede acceder a las dependencias en la nube mediante la API del sistema de archivos.

Acceso a las dependencias del código

En este ejemplo se accede y se ejecuta la dependencia ffmpeg que se encuentra en el directorio <project_root>/ffmpeg_lib.

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

Para que este fragmento de código funcione en Azure, debe especificar una configuración de la aplicación personalizada de "BASE_PATH" con el valor "/home/site/wwwroot".

Traslado de dependencias mediante el montaje de un recurso compartido de archivos

Cuando ejecuta la aplicación de funciones en Linux, hay otra manera de trasladar las dependencias de terceros. Functions le permite montar un recurso compartido de archivos hospedado en Azure Files. Tenga en cuenta este enfoque si desea desacoplar dependencias o artefactos desde el código de la aplicación.

En primer lugar, tiene que crear una cuenta de Azure Storage. En la cuenta, también debe crear un recurso compartido de archivos en Azure Files. Para crear estos recursos, siga esta guía.

Después de crear la cuenta de almacenamiento y el recurso compartido de archivos, use el comando az webapp config storage-account add para adjuntar el recurso compartido de archivos a la aplicación de funciones, como se muestra en el ejemplo siguiente.

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>
Marca Value
custom-id Cualquier cadena única
storage-type Actualmente solo se admite Azure Files
share-name Recurso compartido ya existente
mount-path Ruta de acceso en la que se podrá acceder al recurso compartido dentro del contenedor. El valor debe tener el formato /dir-name y no puede empezar por /home.

Aquí puede encontrar más comandos para modificar o eliminar la configuración del recurso compartido de archivos.

Carga de las dependencias en Azure Files

Una opción para cargar la dependencia en Azure Files es mediante Azure Portal. Consulte esta guía para obtener instrucciones para cargar dependencias mediante el portal. Otras opciones para cargar las dependencias en Azure Files son mediante la CLI de Azure y PowerShell.

Acceso a las dependencias del código

Después de cargar las dependencias en el recurso compartido de archivos, puede acceder a estas desde el código. El recurso compartido montado está disponible en la ruta de acceso de montaje especificada como, por ejemplo, /path/to/mount. Puede acceder al directorio de destino mediante las API del sistema de archivos.

En el ejemplo siguiente se muestra un código de desencadenador HTTP que accede a la biblioteca ffmpeg, que está almacenada en un recurso compartido de archivos montado.

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)

Al implementar este código en una aplicación de funciones de Azure, debe crear una configuración de la aplicación con un nombre de clave FILE_SHARE_MOUNT_PATH y un valor de la ruta de acceso del recurso compartido de archivos montado que, para este ejemplo es /azure-files-share. Para realizar la depuración local, debe rellenar FILE_SHARE_MOUNT_PATH con la ruta de acceso del archivo donde se almacenan las dependencias en la máquina local. Este es un ejemplo para establecer FILE_SHARE_MOUNT_PATH mediante local.settings.json:

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

Pasos siguientes