Compartilhar via


Trazer dependências ou biblioteca de terceiros para o Azure Functions

Neste artigo, você aprenderá a trazer dependências de terceiros para os aplicativos de funções. Exemplos de dependências de terceiros são arquivos json, arquivos binários e modelos de machine learning.

Neste artigo, você aprenderá como:

  • Trazer dependências por meio do projeto de código do Functions
  • Trazer dependências por meio da montagem do Azure Fileshare

Trazer dependências do diretório do projeto

Uma das maneiras mais simples de trazer dependências é colocar os arquivos/artefatos junto com o código do aplicativo de funções na estrutura de diretório do projeto do Functions. Este é um exemplo das amostras de diretório em um projeto de funções do Python:

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

Ao colocar as dependências em uma pasta dentro do diretório do projeto do aplicativo de funções, a pasta de dependências será implantada junto com o código. Como resultado, o código da função pode acessar as dependências na nuvem por meio da API do sistema de arquivos.

Acessar as dependências no código

Aqui está um exemplo de como acessar e executar a dependência ffmpeg que é colocada no diretório <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)

Observação

Talvez seja necessário usar chmod para fornecer direitos de Execute ao binário ffmpeg em um ambiente do Linux

Uma das maneiras mais simples de trazer dependências é colocar os arquivos/artefatos junto com o código do aplicativo de funções na estrutura de diretório do projeto de funções. Este é um exemplo das amostras de diretório em um projeto de funções do Java:

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

Especificamente para Java, você precisa incluir os artefatos na pasta compilação/destino ao copiar os recursos. Veja um exemplo de como fazer isso no 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>
...

Ao colocar as dependências em uma pasta dentro do diretório do projeto do aplicativo de funções, a pasta de dependências será implantada junto com o código. Como resultado, o código da função pode acessar as dependências na nuvem por meio da API do sistema de arquivos.

Acessar as dependências no código

Aqui está um exemplo de como acessar e executar a dependência ffmpeg que é colocada no diretório <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();

    }

Observação

Para que esse trecho de código funcione no Azure, você precisa especificar uma configuração de aplicativo personalizada de "BASE_PATH" com o valor de "/home/site/wwwroot"

Trazer dependências montando um compartilhamento de arquivos

Ao executar seu aplicativo de funções no Linux, há outra maneira de trazer dependências de terceiros. O Functions permite montar um compartilhamento de arquivos hospedado no Arquivos do Azure. Considere essa abordagem quando quiser desassociar dependências ou artefatos do código do aplicativo.

Primeiro, você precisa criar uma conta de Armazenamento do Azure. Na conta, você também precisa criar o compartilhamento de arquivos nos arquivos do Azure. Para criar esses recursos, siga este guia

Depois de criar a conta de armazenamento e o compartilhamento de arquivos, use o comando az webapp config storage-account add para anexar o compartilhamento de arquivos ao aplicativo de funções, conforme mostrado no exemplo a seguir.

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>
Sinalizador Valor
custom-id Qualquer cadeia de caracteres exclusiva
storage-type Somente AzureFiles tem suporte no momento
share-name Compartilhamento preexistente
mount-path Caminho no qual o compartilhamento estará acessível dentro do contêiner. O valor deve estar no formato /dir-name e não pode começar com /home

Mais comandos para modificar/excluir a configuração de compartilhamento de arquivos podem ser encontrados aqui

Carregar as dependências no Arquivos do Azure

Uma opção para carregar sua dependência no Arquivos do Azure é por meio do portal do Azure. Consulte este guia para ver instruções de como carregar dependências usando o portal. Outras opções para carregar suas dependências no Arquivos do Azure são por meio da CLI do Azure e do PowerShell.

Acessar as dependências no código

Depois que suas dependências são carregadas no compartilhamento de arquivos, você pode acessar as dependências do código. O compartilhamento montado está disponível no mount-path especificado, como /path/to/mount. Você pode acessar o diretório de destino usando APIs do sistema de arquivos.

O exemplo a seguir mostra o código de gatilho HTTP que acessa a biblioteca ffmpeg, que é armazenada em um compartilhamento de arquivos 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)

Ao implantar esse código em um aplicativo de funções no Azure, você precisa criar uma configuração de aplicativo com um nome de chave de FILE_SHARE_MOUNT_PATH e o valor do caminho do compartilhamento de arquivos montado, que neste exemplo é /azure-files-share. Para fazer a depuração local, você precisa preencher o FILE_SHARE_MOUNT_PATH com o caminho do arquivo em que suas dependências são armazenadas no computador local. Este é um exemplo para definir 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"
  }
}

Próximas etapas