Como trabalhar com camadas para funções do Lambda em Python - AWS Lambda

Como trabalhar com camadas para funções do Lambda em Python

Uma camada do Lambda é um arquivo .zip que contém código ou dados complementares. As camadas geralmente contêm dependências de biblioteca, um runtime personalizado ou arquivos de configuração. A criação de uma camada envolve três etapas gerais:

  1. Empacotar o conteúdo da sua camada. Isso significa criar um arquivo .zip contendo as dependências que você deseja usar em suas funções.

  2. Criar a camada no Lambda.

  3. Adicionar a camada às suas funções.

Este tópico contém etapas e orientações sobre como empacotar e criar adequadamente uma camada do Lambda em Python com dependências externas de bibliotecas.

Pré-requisitos

Para seguir as etapas desta seção, você deve ter o seguinte:

Neste tópico, mencionamos a aplicação de amostra layer-python no repositório awsdocs no GitHub. Essa aplicação contém scripts que baixam as dependências e geram as camadas. A aplicação também contém funções correspondentes que usam dependências das camadas. Após criar uma camada, você pode implantar e invocar a função correspondente para verificar se tudo funciona corretamente. Como você usa o runtime do Python 3.11 para as funções, as camadas também devem ser compatíveis com o Python 3.11.

Na aplicação de amostra layer-python, há dois exemplos:

  • O primeiro exemplo envolve empacotar a biblioteca requests em uma camada do Lambda. O diretório layer/ contém os scripts para gerar a camada. O diretório function/ contém uma amostra de função para ajudar a testar se a camada funciona. A maior parte deste tutorial explica como criar e empacotar essa camada.

  • O segundo exemplo envolve empacotar a biblioteca numpy em uma camada do Lambda. O diretório layer-numpy/ contém os scripts para gerar a camada. O diretório function-numpy/ contém uma amostra de função para ajudar a testar se a camada funciona. Para obter um exemplo de como criar e empacotar essa camada, consulte Como trabalhar com distribuições wheel manylinux.

Compatibilidade da camada em Python com o Amazon Linux

A primeira etapa para criar uma camada é agrupar todo o conteúdo da camada em um arquivo .zip. Devido às funções do Lambda serem executadas no Amazon Linux, seu conteúdo da camada deve ser capaz de compilar e criar em um ambiente Linux.

Em Python, a maioria dos pacotes está disponível como wheels (arquivos .whl), além da distribuição de origem. Cada wheel é um tipo de distribuição compilada compatível com uma combinação específica de versões do Python, sistemas operacionais e conjuntos de instruções de máquina.

As wheels são úteis para garantir que sua camada seja compatível com o Amazon Linux. Ao baixar suas dependências, baixe a wheel universal, se possível. (Por padrão, o pip instala a wheel universal, se houver uma disponível.) A wheel universal contém any como uma etiqueta de plataforma, indicando que é compatível com todas as plataformas, inclusive Amazon Linux.

No exemplo a seguir, você empacota a biblioteca requests em uma camada do Lambda. A biblioteca requests é um exemplo de pacote que está disponível como uma wheel universal.

Nem todos os pacotes do Python são distribuídos como wheels universais. Por exemplo, numpy tem várias distribuições de wheels, cada uma compatível com um conjunto diferente de plataformas. Para esses pacotes, baixe a distribuição manylinux a fim de garantir a compatibilidade com o Amazon Linux. Para obter instruções detalhadas sobre como empacotar essas camadas, consulte Como trabalhar com distribuições wheel manylinux.

Em casos raros, talvez um pacote do Python não esteja disponível como wheel. Se existir apenas a distribuição de origem (sdist), recomendamos instalar e empacotar suas dependências em um ambiente Docker com base na imagem de contêiner básica do Amazon Linux 2023. Também recomendamos essa abordagem se você quiser incluir suas próprias bibliotecas personalizadas escritas em outras linguagens, como C/C++. Essa abordagem imita o ambiente de execução do Lambda no Docker e garante a compatibilidade do Amazon Linux para suas dependências de pacotes que não sejam do Python.

Caminhos de camada para runtimes em Python

Quando você adiciona uma camada a uma função, o Lambda carrega o conteúdo da camada no diretório /opt desse ambiente de execução. Para cada runtime do Lambda, a variável PATH já inclui caminhos de pasta específica no diretório /opt. Para garantir que a variável PATH colete o conteúdo da camada, o arquivo .zip da camada deve ter suas dependências nos seguintes caminhos de pasta:

  • python

  • python/lib/python3.x/site-packages

Por exemplo, o arquivo .zip de camada resultante que você cria neste tutorial tem a seguinte estrutura de diretórios:

layer_content.zip └ python └ lib └ python3.11 └ site-packages └ requests └ <other_dependencies> (i.e. dependencies of the requests package) └ ...

A biblioteca requests está localizada corretamente no diretório python/lib/python3.11/site-packages. Isso garante que o Lambda possa localizar a biblioteca durante as invocações da função.

Empacotar o conteúdo de camada

Neste exemplo, você empacota a biblioteca requests Python em um arquivo .zip de camada. Conclua as etapas a seguir para instalar e empacotar o conteúdo de camada.

Para instalar e empacotar seu conteúdo de camada
  1. Clone o repositório aws-lambda-developer-guide do GitHub, que contém a amostra de código de que você precisa no diretório sample-apps/layer-python.

    git clone https://github.com/awsdocs/aws-lambda-developer-guide.git
  2. Acesse o diretório layer do exemplo de aplicação layer-python. Esse diretório contém os scripts que você usa para criar e empacotar a camada corretamente.

    cd aws-lambda-developer-guide/sample-apps/layer-python/layer
  3. Examine os arquivos requirements.txt Esse arquivo define as dependências que você deseja incluir na camada, ou seja, a biblioteca requests. Você pode atualizar esse arquivo para incluir quaisquer dependências que quiser incluir em sua própria camada.

    exemplo requirements.txt
    requests==2.31.0
  4. Verifique se você tem permissões para executar os dois scripts.

    chmod 744 1-install.sh && chmod 744 2-package.sh
  5. Execute o script 1-install.sh usando o comando a seguir:

    ./1-install.sh

    Esse script usa venv para criar um ambiente virtual em Python chamado create_layer. Em seguida, ele instala todas as dependências necessárias no diretório create_layer/lib/python3.11/site-packages.

    exemplo 1-install.sh
    python3.11 -m venv create_layer source create_layer/bin/activate pip install -r requirements.txt
  6. Execute o script 2-package.sh usando o comando a seguir:

    ./2-package.sh

    Esse script copia o conteúdo do diretório create_layer/lib em um novo diretório chamado python. Em seguida, ele compacta o conteúdo do diretório python em um arquivo chamado layer_content.zip. Esse é o arquivo .zip da sua camada. É possível descompactar o arquivo e verificar se ele contém a estrutura de arquivo correta, conforme apresentado na seção Caminhos de camada para runtimes em Python.

    exemplo 2-package.sh
    mkdir python cp -r create_layer/lib python/ zip -r layer_content.zip python

Como criar a camada

Nesta seção, você pega o arquivo layer_content.zip gerado na seção anterior e o carrega como uma camada do Lambda. É possível fazer upload de uma camada usando o AWS Management Console ou a API do Lambda por meio da AWS Command Line Interface (AWS CLI). Ao carregar seu arquivo .zip de camada, no seguinte comando PublishLayerVersion da AWS CLI, especifique python3.11 como o runtime compatível e arm64 como a arquitetura compatível.

aws lambda publish-layer-version --layer-name python-requests-layer \ --zip-file fileb://layer_content.zip \ --compatible-runtimes python3.11 \ --compatible-architectures "arm64"

Na resposta, anote o LayerVersionArn, que será algo como arn:aws:lambda:us-east-1:123456789012:layer:python-requests-layer:1. Você precisará desse nome do recurso da Amazon (ARN) na próxima etapa deste tutorial, ao adicionar a camada à função.

Como adicionar a camada à sua função

Nesta seção, você implanta uma amostra de função do Lambda que usa a biblioteca requests em seu código de função e, em seguida, você anexa a camada. Para implantar a função, você precisará de um Definir permissões de uma função do Lambda com um perfil de execução. Se ainda não tiver um perfil de execução, siga as etapas na seção recolhível. Caso contrário, pule para a próxima seção para implantar a função.

Para criar uma função de execução
  1. Abra a página Roles (Funções) no console do IAM.

  2. Selecione Create role (Criar função).

  3. Crie uma função com as propriedades a seguir.

    • Entidade confiávelLambda.

    • Permissions (Permissões): AWSLambdaBasicExecutionRole.

    • Role name (Nome da função): lambda-role.

    A política AWSLambdaBasicExecutionRole tem as permissões necessárias para a função gravar logs no CloudWatch Logs.

Para implantar a função do Lambda
  1. Navegue até o diretório function/. Se você estiver no diretório layer/, execute o seguinte comando:

    cd ../function
  2. Revise o código de função. A função importa a biblioteca requests, faz uma solicitação HTTP GET simples e retorna o código e o corpo do status.

    import requests def lambda_handler(event, context): print(f"Version of requests library: {requests.__version__}") request = requests.get('https://api.github.com/') return { 'statusCode': request.status_code, 'body': request.text }
  3. Crie um arquivo .zip de pacote de implantação usando o seguinte comando:

    zip my_deployment_package.zip lambda_function.py
  4. Implantar a função. No seguinte comando da AWS CLI, substitua o parâmetro --role pelo ARN do seu perfil de execução:

    aws lambda create-function --function-name python_function_with_layer \ --runtime python3.11 \ --architectures "arm64" \ --handler lambda_function.lambda_handler \ --role arn:aws:iam::123456789012:role/lambda-role \ --zip-file fileb://my_deployment_package.zip

Nessa fase, é possível, opcionalmente, tentar invocar sua função antes de anexar a camada. Se tentar fazer isso, você deverá receber um erro de importação porque sua função não pode fazer referência ao pacote requests. Para invocar sua função, use o seguinte comando da AWS CLI:

aws lambda invoke --function-name python_function_with_layer \ --cli-binary-format raw-in-base64-out \ --payload '{ "key": "value" }' response.json

Você deve ver uma saída semelhante a:

{ "StatusCode": 200, "FunctionError": "Unhandled", "ExecutedVersion": "$LATEST" }

Para ver o erro específico, abra o arquivo response.json de saída. Você deverá ver um ImportModuleError com a seguinte mensagem de erro:

"errorMessage": "Unable to import module 'lambda_function': No module named 'requests'"

Em seguida, anexe a camada à sua função. No seguinte comando da AWS CLI, substitua o parâmetro --layers pelo ARN da versão de camada que você anotou anteriormente:

aws lambda update-function-configuration --function-name python_function_with_layer \ --cli-binary-format raw-in-base64-out \ --layers "arn:aws:lambda:us-east-1:123456789012:layer:python-requests-layer:1"

Por fim, tente invocar sua função usando o seguinte comando da AWS CLI:

aws lambda invoke --function-name python_function_with_layer \ --cli-binary-format raw-in-base64-out \ --payload '{ "key": "value" }' response.json

Você deve ver uma saída semelhante a:

{ "StatusCode": 200, "ExecutedVersion": "$LATEST" }

O arquivo response.json de saída contém detalhes sobre a resposta.

Agora você pode excluir os recursos criados para este tutorial, a menos que queira mantê-los. Excluindo os recursos da AWS que você não está mais usando, você evita cobranças desnecessárias em sua Conta da AWS.

Para excluir a camada do Lambda
  1. Abra a página Camadas do console do Lambda.

  2. Selecione a camada que você criou.

  3. Escolha Excluir, depois escolha Excluir novamente.

Como excluir a função do Lambda
  1. Abra a página Functions (Funções) no console do Lambda.

  2. Selecione a função que você criou.

  3. Escolha Ações, Excluir.

  4. Digite delete no campo de entrada de texto e escolha Delete (Excluir).

Como trabalhar com distribuições wheel manylinux

Às vezes, um pacote que você deseja incluir como dependência não terá uma wheel universal (mais especificamente, não terá any como tag de plataforma). Nesse caso, em vez disso baixe a wheel compatível com manylinux. Isso garantirá que suas bibliotecas de camadas sejam compatíveis com o Amazon Linux.

O numpy é um pacote que não tem uma wheel universal. Se quiser incluir o pacote numpy em sua camada, você poderá executar as etapas do exemplo a seguir para instalar e empacotar sua camada corretamente.

Para instalar e empacotar seu conteúdo de camada
  1. Clone o repositório aws-lambda-developer-guide do GitHub, que contém a amostra de código de que você precisa no diretório sample-apps/layer-python.

    git clone https://github.com/awsdocs/aws-lambda-developer-guide.git
  2. Acesse o diretório layer-numpy do exemplo de aplicação layer-python. Esse diretório contém os scripts que você usa para criar e empacotar a camada corretamente.

    cd aws-lambda-developer-guide/sample-apps/layer-python/layer-numpy
  3. Examine os arquivos requirements.txt Esse arquivo define as dependências que você deseja incluir na sua camada, ou seja, a biblioteca numpy. Aqui, você especifica o URL da distribuição de wheel manylinux compatível com Python 3.11, Amazon Linux e o conjunto de instruções x86_64:

    exemplo requirements.txt
    https://files.pythonhosted.org/packages/3a/d0/edc009c27b406c4f9cbc79274d6e46d634d139075492ad055e3d68445925/numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
  4. Verifique se você tem permissões para executar os dois scripts.

    chmod 744 1-install.sh && chmod 744 2-package.sh
  5. Execute o script 1-install.sh usando o comando a seguir:

    ./1-install.sh

    Esse script usa venv para criar um ambiente virtual em Python chamado create_layer. Em seguida, ele instala todas as dependências necessárias no diretório create_layer/lib/python3.11/site-packages. Nesse caso, o comando pip é diferente, pois você precisa especificar a tag --platform como manylinux2014_x86_64. Isso instrui o pip a instalar a wheel manylinux correta, mesmo que sua máquina local use macOS ou Windows.

    exemplo 1-install.sh
    python3.11 -m venv create_layer source create_layer/bin/activate pip install -r requirements.txt --platform=manylinux2014_x86_64 --only-binary=:all: --target ./create_layer/lib/python3.11/site-packages
  6. Execute o script 2-package.sh usando o comando a seguir:

    ./2-package.sh

    Esse script copia o conteúdo do diretório create_layer/lib em um novo diretório chamado python. Em seguida, ele compacta o conteúdo do diretório python em um arquivo chamado layer_content.zip. Esse é o arquivo .zip da sua camada. É possível descompactar o arquivo e verificar se ele contém a estrutura de arquivo correta, conforme apresentado na seção Caminhos de camada para runtimes em Python.

    exemplo 2-package.sh
    mkdir python cp -r create_layer/lib python/ zip -r layer_content.zip python

Para carregar essa camada no Lambda, use o seguinte comando PublishLayerVersion da AWS CLI:

aws lambda publish-layer-version --layer-name python-numpy-layer \ --zip-file fileb://layer_content.zip \ --compatible-runtimes python3.11 \ --compatible-architectures "x86_64"

Na resposta, anote o LayerVersionArn, que será algo como arn:aws:lambda:us-east-1:123456789012:layer:python-numpy-layer:1. Para verificar se sua camada funciona conforme o esperado, implante a função do Lambda no diretório function-numpy.

Para implantar a função do Lambda
  1. Navegue até o diretório function-numpy/. Se você estiver no diretório layer-numpy/, execute o seguinte comando:

    cd ../function-numpy
  2. Revise o código de função. A função importa a biblioteca numpy, cria uma matriz numpy simples e retorna o código e o corpo de um status fictício.

    import json import numpy as np def lambda_handler(event, context): x = np.arange(15, dtype=np.int64).reshape(3, 5) print(x) return { 'statusCode': 200, 'body': json.dumps('Hello from Lambda!') }
  3. Crie um arquivo .zip de pacote de implantação usando o seguinte comando:

    zip my_deployment_package.zip lambda_function.py
  4. Implantar a função. No seguinte comando da AWS CLI, substitua o parâmetro --role pelo ARN do seu perfil de execução:

    aws lambda create-function --function-name python_function_with_numpy \ --runtime python3.11 \ --handler lambda_function.lambda_handler \ --role arn:aws:iam::123456789012:role/lambda-role \ --zip-file fileb://my_deployment_package.zip

Como opção, é possível tentar invocar sua função antes de anexar a camada. Se tentar fazer isso, você deverá receber um erro de importação porque sua função não pode fazer referência ao pacote numpy. Para invocar sua função, use o seguinte comando da AWS CLI:

aws lambda invoke --function-name python_function_with_numpy \ --cli-binary-format raw-in-base64-out \ --payload '{ "key": "value" }' response.json

Você deve ver uma saída semelhante a:

{ "StatusCode": 200, "FunctionError": "Unhandled", "ExecutedVersion": "$LATEST" }

Para ver o erro específico, abra o arquivo response.json de saída. Você deverá ver um ImportModuleError com a seguinte mensagem de erro:

"errorMessage": "Unable to import module 'lambda_function': No module named 'numpy'"

Em seguida, anexe a camada à sua função. No seguinte comando da AWS CLI, substitua o parâmetro --layers pelo ARN da versão da sua camada:

aws lambda update-function-configuration --function-name python_function_with_numpy \ --cli-binary-format raw-in-base64-out \ --layers "arn:aws:lambda:us-east-1:123456789012:layer:python-requests-layer:1"

Por fim, tente invocar sua função usando o seguinte comando da AWS CLI:

aws lambda invoke --function-name python_function_with_numpy \ --cli-binary-format raw-in-base64-out \ --payload '{ "key": "value" }' response.json

Você deve ver uma saída semelhante a:

{ "StatusCode": 200, "ExecutedVersion": "$LATEST" }

Você pode examinar os logs da função para verificar se o código imprime a matriz numpy na saída padrão.