AWS Lambda
Guia do desenvolvedor

Tutorial: usar o AWS Lambda com o Amazon S3

Suponha que você deseja criar uma miniatura para cada arquivo de imagem que é obtida por upload em um bucket. Você pode criar uma função do Lambda (CreateThumbnail) que o Amazon S3 pode invocar quando os objetos são criados. Em seguida, a função do Lambda pode ler o objeto de imagem do bucket de origem e criar um bucket de destino da imagem em miniatura.

Ao concluir este tutorial, você terá os seguintes recursos do Amazon S3, do Lambda e do IAM na sua conta:

Recursos da Lambda

  • Uma função do Lambda.

  • Uma política de acesso associada à sua função do Lambda que concede a permissão do Amazon S3 para invocar a função do Lambda.

Recursos da IAM

  • Uma função de execução que concede permissões de que sua função do Lambda precisa por meio da política de permissões associada a essa função.

Recursos da Amazon S3

  • Um bucket de origem com uma configuração de notificação que invoca a função do Lambda.

  • Um bucket de destino em que a função salva imagens redimensionadas.

Pré-requisitos

Este tutorial pressupõe que você tenha algum conhecimento das operações básicas do Lambda e do console do Lambda. Caso ainda não tenha feito isso, siga as instruções em Conceitos básicos do AWS Lambda para criar sua primeira função do Lambda.

Para seguir os procedimentos neste manual, você precisa de um terminal de linha de comando ou de um shell para executar os comandos. Nas listagens, os comandos são mostrados precedidos por um símbolo de prompt ($) e pelo nome do diretório atual, quando apropriado:

~/lambda-project$ this is a command this is output

Para comandos longos, um caractere de escape (\) é usado para dividir um comando em várias linhas.

No Linux e no macOS, use seu gerenciador preferido de pacotes e de shell. No Windows 10, você pode instalar o Subsistema Windows para Linux para obter uma versão do Ubuntu integrada com o Windows e o Bash.

Instalar o NPM para gerenciar as dependências da função.

O tutorial usa comandos da CLI da AWS para criar e chamar a função do Lambda. Instale a CLI da AWS e configure-a usando com suas credenciais da AWS

Criar a função de execução

Crie a função de execução que dá à sua função permissão para acessar recursos do AWS.

Para criar uma função de execução

  1. Abra a página Roles no console do IAM.

  2. Selecione Create role.

  3. Crie uma função com as seguintes propriedades.

    • Trusted entity (Entidade confiável)AWS Lambda.

    • Permissions (Permissões)AWSLambdaExecute.

    • Nome da funçãolambda-s3-role.

A política AWSLambdaExecute tem as permissões de que a função precisa para gerenciar objetos no Amazon S3 e gravar logs no CloudWatch Logs.

Criar buckets e fazer upload de um objeto de exemplo

Siga as etapas para criar buckets e fazer upload de um objeto.

  1. Abra o console do Amazon S3.

  2. Crie dois buckets. O nome do bucket de destino deve ser source seguido por resized, em que source é o nome do bucket que você deseja usar como a origem. Por exemplo, mybucket e mybucketresized.

  3. No bucket de origem, faça upload de um objeto.jpg, HappyFace.jpg.

    Quando você invoca a função do Lambda manualmente antes de se conectar ao Amazon S3, você passa os dados do evento de exemplo para a função que especifica o bucket de origem e HappyFace.jpg como o objeto recém-criado, portanto, você precisa criar esse objeto de exemplo primeiro.

Criar a função

O código de amostra a seguir recebe uma entrada de evento Amazon S3 e processa a mensagem que ela contém. Ele redimensiona uma imagem no bucket de origem e salva a saída no bucket de destino.

nota

Para o código de amostra em outras linguagens, consulte Código de função do Amazon S3 de amostra.

exemplo index.js

// dependencies var async = require('async'); var AWS = require('aws-sdk'); var gm = require('gm') .subClass({ imageMagick: true }); // Enable ImageMagick integration. var util = require('util'); // constants var MAX_WIDTH = 100; var MAX_HEIGHT = 100; // get reference to S3 client var s3 = new AWS.S3(); exports.handler = function(event, context, callback) { // Read options from the event. console.log("Reading options from event:\n", util.inspect(event, {depth: 5})); var srcBucket = event.Records[0].s3.bucket.name; // Object key may have spaces or unicode non-ASCII characters. var srcKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " ")); var dstBucket = srcBucket + "resized"; var dstKey = "resized-" + srcKey; // Sanity check: validate that source and destination are different buckets. if (srcBucket == dstBucket) { callback("Source and destination buckets are the same."); return; } // Infer the image type. var typeMatch = srcKey.match(/\.([^.]*)$/); if (!typeMatch) { callback("Could not determine the image type."); return; } var imageType = typeMatch[1].toLowerCase(); if (imageType != "jpg" && imageType != "png") { callback(`Unsupported image type: ${imageType}`); return; } // Download the image from S3, transform, and upload to a different S3 bucket. async.waterfall([ function download(next) { // Download the image from S3 into a buffer. s3.getObject({ Bucket: srcBucket, Key: srcKey }, next); }, function transform(response, next) { gm(response.Body).size(function(err, size) { // Infer the scaling factor to avoid stretching the image unnaturally. var scalingFactor = Math.min( MAX_WIDTH / size.width, MAX_HEIGHT / size.height ); var width = scalingFactor * size.width; var height = scalingFactor * size.height; // Transform the image buffer in memory. this.resize(width, height) .toBuffer(imageType, function(err, buffer) { if (err) { next(err); } else { next(null, response.ContentType, buffer); } }); }); }, function upload(contentType, data, next) { // Stream the transformed image to a different S3 bucket. s3.putObject({ Bucket: dstBucket, Key: dstKey, Body: data, ContentType: contentType }, next); } ], function (err) { if (err) { console.error( 'Unable to resize ' + srcBucket + '/' + srcKey + ' and upload to ' + dstBucket + '/' + dstKey + ' due to an error: ' + err ); } else { console.log( 'Successfully resized ' + srcBucket + '/' + srcKey + ' and uploaded to ' + dstBucket + '/' + dstKey ); } callback(null, "message"); } ); };

Analise o código anterior e observe o seguinte:

  • A função conhece o nome do bucket de origem e o nome da chave do objeto dos dados do evento que recebe como parâmetros. Se o objeto for um .jpg, o código criará e salvará uma miniatura no bucket de destino.

  • O código pressupõe que o bucket de destino existe e seu nome é uma concatenação do nome do bucket de origem seguido pela string resized. Por exemplo, se o bucket de origem identificado nos dados do evento for examplebucket, o código pressuporá que você tem um bucket de destino examplebucketresized.

  • Para a miniatura que cria, o código deriva seu nome de chave como a concatenação da string resized- seguida pelo nome da chave do objeto de origem. Por exemplo, se a chave do objeto de origem for sample.jpg, o código criará um objeto em miniatura que terá a chave resized-sample.jpg.

O pacote de implantação é um arquivo .zip que contém o código de sua função de Lambda e as dependências.

Como criar um pacote de implantação

  1. Salve o código da função como index.js em uma pasta chamada lambda-s3.

  2. Instale as bibliotecas GraphicsMagick e Async com o NPM.

    lambda-s3$ npm install async gm

    Depois de concluir esta etapa, você terá a seguinte estrutura de pastas:

    lambda-s3 |- index.js |- /node_modules/gm └ /node_modules/async
  3. Crie um pacote de implantação com o código da função e as dependências.

    lambda-s3$ zip -r function.zip .

Para criar a função

  • Crie uma função do Lambda com o comando create-function.

    $ aws lambda create-function --function-name CreateThumbnail \ --zip-file fileb://function.zip --handler index.handler --runtime nodejs12.x \ --timeout 10 --memory-size 1024 \ --role arn:aws:iam::123456789012:role/lambda-s3-role

O comando anterior especifica um valor de tempo limite de 10 segundos como a configuração da função. Dependendo do tamanho dos objetos obtidos por upload, pode ser necessário aumentar o valor do tempo limite usando o seguinte comando da AWS CLI.

$ aws lambda update-function-configuration --function-name CreateThumbnail --timeout 30

Testar a função do Lambda

Nessa etapa, você invoca a função do Lambda manualmente usando dados do evento de exemplo do Amazon S3.

Para testar a função do Lambda

  1. Salve os seguintes dados dos eventos de exemplo do Amazon S3 em um arquivo e salve-o como inputFile.txt. Você precisa atualizar o JSON fornecendo o nome do sourcebucket e uma chave do objeto .jpg.

    { "Records":[ { "eventVersion":"2.0", "eventSource":"aws:s3", "awsRegion":"us-west-2", "eventTime":"1970-01-01T00:00:00.000Z", "eventName":"ObjectCreated:Put", "userIdentity":{ "principalId":"AIDAJDPLRKLG7UEXAMPLE" }, "requestParameters":{ "sourceIPAddress":"127.0.0.1" }, "responseElements":{ "x-amz-request-id":"C3D13FE58DE4C810", "x-amz-id-2":"FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD" }, "s3":{ "s3SchemaVersion":"1.0", "configurationId":"testConfigRule", "bucket":{ "name":"sourcebucket", "ownerIdentity":{ "principalId":"A3NL1KOZZKExample" }, "arn":"arn:aws:s3:::sourcebucket" }, "object":{ "key":"HappyFace.jpg", "size":1024, "eTag":"d41d8cd98f00b204e9800998ecf8427e", "versionId":"096fKKXTRTtl3on89fVO.nfljtsv6qko" } } } ] }
  2. Execute o comando invoke da CLI do Lambda para invocar a função. Observe que o comando solicita execução assíncrona. Opcionalmente, você pode invocá-la de forma síncrona especificando RequestResponse como o valor do parâmetro invocation-type.

    $ aws lambda invoke --function-name CreateThumbnail --invocation-type Event \ --payload file://inputfile.txt outputfile.txt
  3. Verifique se a miniatura foi criada no bucket de destino.

Configurar o Amazon S3 para publicar eventos

Nessa etapa, você adiciona o restante da configuração para que o Amazon S3 possa publicar eventos criados por objetos no AWS Lambda e invocar sua função do Lambda. Nesta etapa, faça o seguinte:

  • Adicione permissões à política de acesso da função do Lambda para permitir que o Amazon S3 invoque a função.

  • Adicione a configuração de notificação ao bucket de origem. Na configuração de notificação, você fornece o seguinte:

    • Tipo de evento para o qual você deseja que o Amazon S3 publique eventos. Para este tutorial, você especifica o tipo de evento s3:ObjectCreated:* para que o Amazon S3 publique eventos quando forem criados objetos.

    • Função Lambda para invocar.

Como adicionar permissões à política de função

  1. Execute o comando add-permission da CLI do Amazon S3 para conceder à entidade de serviço do Lambda (s3.amazonaws.com) as principais permissões para executar a ação lambda:InvokeFunction. Observe que a permissão será concedida ao Amazon S3 para invocar a função somente se as seguintes condições forem atendidas:

    • Um evento criado por objeto é detectado em um bucket específico.

    • O bucket é de propriedade da sua conta. Se você excluir um bucket, será possível que outra conta crie um bucket com o mesmo ARN.

    $ aws lambda add-permission --function-name CreateThumbnail --principal s3.amazonaws.com \ --statement-id s3invoke --action "lambda:InvokeFunction" \ --source-arn arn:aws:s3:::sourcebucket \ --source-account account-id
  2. Verifique a política de acesso da função executando o comando AWS CLI get-policy.

    $ aws lambda get-policy --function-name CreateThumbnail

Adicione a configuração de notificação no bucket de origem para solicitar que o Amazon S3 publique os eventos criados pelo objeto no Lambda.

Importante

Este procedimento configura o bucket para chamar a função sempre que um objeto é criado nele. Certifique-se de configurar essa opção somente no bucket de origem e não criar objetos no bucket de origem a partir da função disparada. Caso contrário, a função pode fazer com que ela seja invocada continuamente em um loop.

Como configurar notificações

  1. Abra o console do Amazon S3.

  2. Escolha o bucket de origem.

  3. Escolha Propriedades.

  4. Em Events (Eventos), configure uma notificação com as configurações a seguir.

    • Name (Nome)lambda-trigger.

    • Events (Eventos)ObjectCreate (All).

    • Send to (Enviar para)Lambda function.

    • LambdaCreateThumbnail.

Para obter mais informações sobre configuração de eventos, consulte Habilitação de notificações de evento no Guia do usuário do console do Amazon Simple Storage Service.

Testar a configuração

Agora você pode testar a configuração da seguinte forma:

  1. Fazer upload dos objetos .jpg ou .png no bucket de origem usando o console do Amazon S3.

  2. Verificar se a miniatura foi criada no bucket de destino usando a função CreateThumbnail.

  3. Visualize logs no console do CloudWatch.