教程:使用 Amazon S3 触发器创建缩略图 - Amazon Lambda
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

教程:使用 Amazon S3 触发器创建缩略图

在本教程中,您将创建 Lambda 函数,然后为 Amazon Simple Storage Service (Amazon S3) 配置触发器。Amazon S3 会为上载到 S3 存储桶的每个镜像文件调用 CreateThumbnail 函数。该函数从 S3 源存储桶读取图像对象并在目标 S3 存储桶中创建要保存的缩略图。

注意

本教程需要适度的 Amazon、Lambda、Docker 操作和 Amazon Serverless Application Model(Amazon SAM)知识水平。我们建议您先尝试 教程:使用 Amazon S3 触发器调用 Lambda 函数

在本教程中,您将使用 Amazon Command Line Interface (Amazon CLI) 创建以下 Amazon 资源:

Lambda 资源
  • Lambda 函数。您可以选择 Node.js 或 Python 作为函数代码。

  • 函数的 .zip 文件存档部署包。

  • 授予 Amazon S3 调用函数的权限的访问策略。

Amazon Identity and Access Management (IAM) 资源
  • 拥有关联权限策略的执行角色,用于授予函数所需的权限。

Amazon S3 资源
  • 具有调用函数的通知配置的源 S3 存储桶。

  • 函数在其中保存已调整大小的图像的目标 S3 存储桶。

先决条件

第 1 步 创建 S3 存储桶并上传示例对象

按照以下步骤创建 S3 存储桶并上传对象。

  1. 打开 Amazon S3 控制台

  2. 创建两个 S3 存储桶。目标存储桶必须命名为 source-resized,其中 source 是源存储桶的名称。例如,名为 sourcebucket 的源存储桶和名为 sourcebucket-resized 的目标存储桶。

    注意

    确保在计划用于 Lambda 函数的相同 Amazon Web Services 区域 中创建存储桶。

  3. 在源存储桶中,上传 .jpg 或 .png 对象,例如 HappyFace.jpg

    在测试 Lambda 函数之前,必须创建此示例对象。在步骤 6 中手动测试函数时,将示例事件数据传递给指定源存储桶名称和图像文件名称的函数。

第 2 步 创建 IAM policy

创建定义 Lambda 函数权限的 IAM policy。该函数必须具有以下权限:

  • 从源 S3 存储桶获取对象。

  • 将已调整大小的对象放入目标 S3 存储桶。

  • 将日志写入 Amazon CloudWatch Logs

创建 IAM policy
  1. 在 IAM 控制台中打开 Policies(策略)页面

  2. 选择 Create policy(创建策略)。

  3. 选择 JSON 选项卡,然后粘贴以下策略。请务必将 sourcebucket 替换为之前创建的源存储桶的名称。

    { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:PutLogEvents", "logs:CreateLogGroup", "logs:CreateLogStream" ], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": [ "s3:GetObject" ], "Resource": "arn:aws:s3:::sourcebucket/*" }, { "Effect": "Allow", "Action": [ "s3:PutObject" ], "Resource": "arn:aws:s3:::sourcebucket-resized/*" } ] }
  4. 请选择下一步:标签

  5. 选择 Next: Review(下一步:审核)。

  6. Review policy(查看策略)下,为 Name(名称)输入 AWSLambdaS3Policy

  7. 选择 Create policy(创建策略)。

第 3 步 创建执行角色

创建执行角色,向您的 Lambda 函数授予访问Amazon资源的权限。

创建执行角色
  1. 在 IAM 控制台中,打开“Roles (角色)”页面

  2. 选择 Create role(创建角色)。

  3. 创建具有以下属性的角色:

    • Trusted entity(可信任的实体)– Lambda

    • Permission policy(权限策略)– AWSLambdaS3Policy

    • Role name(角色名称)– lambda-s3-role

第 4 步 创建部署程序包

部署程序包是包含 Lambda 函数代码及其依赖项的 .zip 文件归档

Node.js
  1. 在 Linux 环境中打开命令行终端或 shell。确保本地环境中的 Node.js 版本与函数的 Node.js 版本相匹配。

  2. 创建名为 lambda-s3 的目录。

    mkdir lambda-s3
  3. 将函数代码保存为 index.js

    // dependencies const AWS = require('aws-sdk'); const util = require('util'); const sharp = require('sharp'); // get reference to S3 client const s3 = new AWS.S3(); exports.handler = async (event, context, callback) => { // Read options from the event parameter. console.log("Reading options from event:\n", util.inspect(event, {depth: 5})); const srcBucket = event.Records[0].s3.bucket.name; // Object key may have spaces or unicode non-ASCII characters. const srcKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " ")); const dstBucket = srcBucket + "-resized"; const dstKey = "resized-" + srcKey; // Infer the image type from the file suffix. const typeMatch = srcKey.match(/\.([^.]*)$/); if (!typeMatch) { console.log("Could not determine the image type."); return; } // Check that the image type is supported const imageType = typeMatch[1].toLowerCase(); if (imageType != "jpg" && imageType != "png") { console.log(`Unsupported image type: ${imageType}`); return; } // Download the image from the S3 source bucket. try { const params = { Bucket: srcBucket, Key: srcKey }; var origimage = await s3.getObject(params).promise(); } catch (error) { console.log(error); return; } // set thumbnail width. Resize will set the height automatically to maintain aspect ratio. const width = 200; // Use the sharp module to resize the image and save in a buffer. try { var buffer = await sharp(origimage.Body).resize(width).toBuffer(); } catch (error) { console.log(error); return; } // Upload the thumbnail image to the destination bucket try { const destparams = { Bucket: dstBucket, Key: dstKey, Body: buffer, ContentType: "image" }; const putResult = await s3.putObject(destparams).promise(); } catch (error) { console.log(error); return; } console.log('Successfully resized ' + srcBucket + '/' + srcKey + ' and uploaded to ' + dstBucket + '/' + dstKey); };
  4. lambda-s3 目录中,创建一个 node_modules 目录。

    mkdir node_modules cd node_modules
  5. node_modules 目录中,使用 npm 安装 sharp 库。

    npm install sharp

    完成此步骤后,您将拥有以下目录结构:

    lambda-s3 |- index.js |- /node_modules/... └ /node_modules/sharp
  6. 返回 lambda-s3 目录。

    cd lambda-s3
  7. 创建包含函数代码及其依赖项的部署包。为 zip 命令设置 -r (递归)选项以压缩子文件夹。

    zip -r function.zip .
Python

本教程的 Python 部署包使用 Pillow (PIL) 库。不能使用 Amazon CLI 上传包含 C 或 C++ 库的部署程序包,例如 Pillow。相反,应将 Amazon Serverless Application Model (Amazon SAM) CLI sam build 命令与 --use-container 选项结合使用,以此创建部署程序包。使用带有此选项的 Amazon SAM CLI 创建具有类似 Lambda 环境(可与 Lambda 兼容)的 Docker 容器。

要使用 Amazon SAM 创建部署程序包
  1. 打开命令提示符并创建 lambda-s3 项目目录。

    mkdir lambda-s3
  2. 导航到 lambda-s3 项目目录。

    cd lambda-s3
  3. 复制以下 Python 示例代码的内容,并且使用名为 lambda_function.py 的新文件将其保存:

    import boto3 import os import sys import uuid from urllib.parse import unquote_plus from PIL import Image import PIL.Image s3_client = boto3.client('s3') def resize_image(image_path, resized_path): with Image.open(image_path) as image: image.thumbnail(tuple(x / 2 for x in image.size)) image.save(resized_path) def lambda_handler(event, context): for record in event['Records']: bucket = record['s3']['bucket']['name'] key = unquote_plus(record['s3']['object']['key']) tmpkey = key.replace('/', '') download_path = '/tmp/{}{}'.format(uuid.uuid4(), tmpkey) upload_path = '/tmp/resized-{}'.format(tmpkey) s3_client.download_file(bucket, key, download_path) resize_image(download_path, upload_path) s3_client.upload_file(upload_path, '{}-resized'.format(bucket), 'resized-{}'.format(key))
  4. 在新的 package 目录中安装 Pillow 库。

    pip install --target ./package pillow
  5. lambda-s3 目录中,创建名为 template.yaml 的新文件。这是 Amazon SAM 模板。

    AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Resources: CreateThumbnail: Type: AWS::Serverless::Function Properties: Handler: lambda_function.lambda_handler Runtime: python3.9 Timeout: 10 Policies: AWSLambdaExecute Events: CreateThumbnailEvent: Type: S3 Properties: Bucket: !Ref SrcBucket Events: s3:ObjectCreated:* SrcBucket: Type: AWS::S3::Bucket
  6. 创建名为 requirements.txt 的文件并添加以下内容。这是指定您的依赖项的清单文件。如果您安装不同版本的 Pillow,请更改版本号。

    Pillow == 9.2.0
  7. 构建部署程序包。--use-container 标志是必填项。此标志在行为类似于 Lambda 环境的 Docker 容器中本地编译您的函数,因此在您部署它们时,它们的格式正确。

    sam build --use-container

步骤 5:创建 Lambda 函数

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

对于 role 参数,请将 123456789012 替换为您的 Amazon 账户 ID

create-function 命令将函数处理程序指定为 index.handler。此处理程序名称将函数名称表示为 handler,存储处理程序代码的文件名为 index.js。有关更多信息,请参阅 Node.js 中的 Amazon Lambda 函数处理程序。该命令指定了 nodejs16.x 的运行时。有关更多信息,请参阅Lambda 运行时

Python

运行以下 Amazon SAM CLI 命令部署部署包并创建 Lambda 函数。按照屏幕上的提示操作。要接受交互式体验中提供的原定设置选项,请通过 Enter 进行响应。

sam deploy --guided

函数配置包含 10 秒的超时值。根据上传的对象的大小,可能需要使用下面的 Amazon CLI 命令增大超时值:

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

步骤 6:测试 Lambda 函数

使用示例 Amazon S3 事件数据手动调用 Lambda 函数。

测试 Lambda 函数
  1. 在之前创建的项目目录中,在名为 inputFile.txt 的文件中保存如下 Amazon S3 示例事件数据。请务必替换以下值:

    • us-west-2 – 在其中创建 Amazon S3 存储桶和 Lambda 函数的 Amazon Web Services 区域。

    • sourcebucket – 在步骤 1 中创建的 Amazon S3 源存储桶。

    • HappyFace.jpg – 您上传到源存储桶的 .jpg 或 .png 图像的对象密钥。

    { "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. 使用以下 invoke 命令调用函数。请注意,该命令会请求异步执行 (--invocation-type Event)。或者,您可以通过将 RequestResponse 指定为 invocation-type 参数值来同步调用函数。

    aws lambda invoke --function-name CreateThumbnail \ --cli-binary-format raw-in-base64-out \ --invocation-type Event \ --payload file://inputFile.txt outputfile.txt
    • 如果使用 cli-binary-format 版本 2,则 Amazon CLI 选项是必需的。要将其设为默认设置,请运行 aws configure set cli-binary-format raw-in-base64-out。有关更多信息,请参阅Amazon CLI 支持的全局命令行选项

    • 如果您收到错误 “解析参数 '--payload' 时出错:无法加载参数文件://inputFile.txt”,请确保您位于保存 inputFile.txt 的目录中。

  3. 验证目标 S3 存储桶中已创建缩略图。

第 7 步 配置 Amazon S3 以发布事件

完成配置,以使 Amazon S3 能够向 Lambda 发布对象创建事件并调用 Lambda 函数。在此步骤中,您将执行以下操作:

  • 向函数访问策略添加权限以允许 Amazon S3 调用该函数。

  • 向源 S3 存储桶添加通知配置。在通知配置中,您需要提供以下内容:

    • 需要 Amazon S3 发布事件的事件类型。在本教程中,指定 s3:ObjectCreated:* 事件类型,以便 Amazon S3 在创建对象时发布事件。

    • 要调用的函数。

向函数策略添加权限
  1. 运行下面的 add-permission 命令以向 Amazon S3 服务主体(s3.amazonaws.com)授予执行 lambda:InvokeFunction 操作的权限。请注意,向 Amazon S3 授予权限,使其只能在满足以下条件时调用该函数:

    • 在特定的 S3 存储桶上检测到对象创建事件。

    • 该 S3 存储桶由您的 Amazon 账户拥有。如果删除一个存储桶,则另一个 Amazon 账户可能会创建具有相同 Amazon 资源名称(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. 通过运行 get-policy 命令验证函数的访问策略。

    aws lambda get-policy --function-name CreateThumbnail

要使 Amazon S3 将对象创建的事件发布到 Lambda,请在源 S3 存储桶上添加通知配置。

重要

此程序将 S3 存储桶配置为每次在该存储桶中创建对象时调用您的函数。请确保仅在源存储桶上配置此选项。不要让您的函数在源存储桶中创建对象,否则您的函数可能会导致在循环中被连续调用

配置通知
  1. 打开 Amazon S3 控制台

  2. 选择源 S3 存储桶的名称。

  3. 选择 Properties(属性)选项卡。

  4. Event notifications(事件通知)下,选择 Create event notification(创建事件通知)以配置采用以下设置的通知:

    • 事件名称lambda-trigger

    • Event types(事件类型)– All object create events

    • 目的地Lambda function

    • Lambda 函数CreateThumbnail

有关事件配置的更多信息,请参阅 Amazon Simple Storage Service 用户指南中的使用 Amazon S3 控制台启用和配置事件通知

第 8 步 使用 Amazon S3 触发器测试

按如下所示测试设置:

  1. 使用 Amazon S3 控制台将 .jpg 或 .png 对象上载到源 S3 存储桶。

  2. 使用 CreateThumbnail Lambda 函数验证每个图像对象都已在目标 S3 存储桶中创建了缩略图。

  3. CloudWatch 控制台中查看日志。

第 9 步 清除资源

除非您想要保留为本教程创建的资源,否则可立即将其删除。通过删除您不再使用的 Amazon 资源,可防止您的 Amazon 账户产生不必要的费用。

删除 Lambda 函数
  1. 打开 Lamba 控制台的 Functions(函数)页面

  2. 选择您创建的函数。

  3. 依次选择 Actions(操作)和 Delete(删除)。

  4. 在文本输入字段中键入 delete,然后选择 Delete(删除)。

删除您创建的策略
  1. 打开 IAM 控制台的 Policies(策略)页面

  2. 选择您创建的策略 (AWSLambdaS3Policy)。

  3. 选择 Policy actions(策略操作)、Delete(删除)。

  4. 选择 Delete(删除)。

删除执行角色
  1. 打开 IAM 控制台的 Roles(角色)页面。

  2. 选择您创建的执行角色。

  3. 选择 Delete (删除)

  4. 在文本输入字段中输入角色名称,然后选择 Delete(删除)。

删除 S3 存储桶
  1. 打开 Amazon S3 控制台

  2. 选择您创建的存储桶。

  3. 选择 Delete (删除)

  4. 在文本输入字段中输入存储桶的名称。

  5. 选择删除存储桶