一、创建权限

创建 Lambda 函数,并对此策略授予了 Lambda 对 Amazon S3 存储桶的读取和写入权限,并允许其写入 Amazon CloudWatch Logs。

创建策略为:LambdaS3Policy

{
    "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:::*/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::*/*"
        }
    ]
}

创建执行角色并附加权限策略(控制台)
  1. 打开(IAM)控制台的角色页面。

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

  3. 可信实体类型中选择 AWS 服务,在使用案例中选择 Lambda

  4. 选择下一步

  5. 执行以下操作添加您在上一步中创建的权限策略:

    1. 在策略搜索框中,输入 LambdaS3Policy

    2. 在搜索结果中,选中 LambdaS3Policy 的复选框。

    3. 选择下一步

  6. 角色详细信息下的角色名称中输入 LambdaS3Role

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

二、创建函数部署包

函数会生成同一个Bucket下不同路径的缩略图,并且会会创建相应的路径结构:

原来Bucket结构:resource/img/1.png

生成的目标Bucket结构:images+原来Bucket结构

import boto3  
import os  
import uuid  
from urllib.parse import unquote_plus  
from PIL import 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'])  
          
        # 分割key,找到文件名前的目录部分  
        dir_path, filename = os.path.split(key)  
          
        # 构造新的key,添加'images'前缀并保持目录结构  
        new_dir_path = 'images/{}'.format(dir_path) if dir_path else 'images/'  
        new_key = os.path.join(new_dir_path, filename)  
          
        # 创建临时文件路径  
        tmp_filename = '{}-{}'.format(uuid.uuid4(), filename)  
        download_path = '/tmp/{}'.format(tmp_filename)  
        upload_path = '/tmp/resized-{}'.format(tmp_filename)  
          
        # 下载图像,调整大小,并上传  
        s3_client.download_file(bucket, key, download_path)  
        resize_image(download_path, upload_path)  
        s3_client.upload_file(upload_path, bucket, new_key)

在创建 lambda_function.py 文件的同一目录中,创建一个名为 package 的新目录并安装 Pillow(PIL)库和 AWS SDK for Python (Boto3)。虽然 Lambda Python 运行时系统包含 Boto3 SDK 的一个版本,但建议您将所有函数的依赖项添加到部署包中,即使这些依赖项已经包含在了运行时系统中。有关更多信息,请参阅 Python 中的运行时系统依赖项

mkdir package
pip install \
--platform manylinux2014_x86_64 \
--target=package \
--implementation cp \
--python-version 3.9 \
--only-binary=:all: --upgrade \
pillow boto3

Pillow 库包含 C/C++ 代码。通过使用 --platform manylinux_2014_x86_64--only-binary=:all: 选项,pip 将下载并安装包含与 Amazon Linux 2 操作系统兼容的预编译二进制文件的 Pillow 版本。这可以确保无论本地构建计算机的操作系统和架构如何,部署包都能在 Lambda 执行环境中正常发挥作用。

创建包含应用程序代码和 Pillow 以及 Boto3 库的 zip 文件。在 Linux 或 MacOS 中,从命令行界面运行以下命令。

cd package
zip -r ../lambda_function.zip .
cd ..
zip lambda_function.zip lambda_function.py

三、创建函数

要使用控制台创建 Lambda 函数,首先要创建包含一些“Hello world”代码的基本函数。然后,通过上传在上一步中创建的 .zip 或 JAR 文件,将此代码替换为自己的函数代码。

  1. 打开 Lamba 控制台的函数页面

  2. 确保您在创建 Amazon S3 存储桶所在的同一 AWS 区域 内操作。您可以使用屏幕顶部的下拉列表更改区域。

    显示了 Lambda 控制台中的区域下拉菜单的图像

  3. 选择 Create function (创建函数)

  4. 选择从头开始创作

  5. 基本信息中,执行以下操作:

    1. 对于 Function name(函数名称),请输入 CreateThumbnail

    2. 运行时系统中,根据您为函数选择的语言选取 Node.js 18.xPython 3.9

    3. 对于架构,选择 x86_64

  6. 更改默认执行角色选项卡中,执行以下操作:

    1. 展开选项卡,然后选择使用现有角色

    2. 选择您之前创建的 LambdaS3Role

  7. 选择创建函数

上传函数代码(控制台)
  1. 代码源窗格中,选择上传自

  2. 选择 .zip 文件

  3. 选择上传

  4. 在文件选择器中,选择 .zip 文件,然后选择打开

  5. 选择保存

四、配置 Amazon S3 来调用函数

重要
此程序将 Amazon S3 存储桶配置为每次在此存储桶中创建对象时调用您的函数。请确保仅在源存储桶上配置。如果您的 Lambda 函数在调用此函数的同一个存储桶中创建对象,则可以在循环中持续调用您的函数。这可能会导致您的 AWS 账户 产生额外费用。
配置 Amazon S3 触发器(控制台)
  1. 打开 Lambda 控制台的函数页面,然后选择函数 (CreateThumbnail)。

  2. 选择 Add trigger

  3. 选择 S3

  4. 存储桶下,选择自己的源存储桶。

  5. 事件类型下,选择所有对象创建事件

  6. 递归调用下,选中复选框以确认知晓不建议使用相同的 Amazon S3 存储桶用于输入和输出。您可以阅读 Serverless Land 中的 Recursive patterns that cause run-away Lambda functions,进一步了解 Lambda 中的递归调用模式。

  7. 选择 添加

    在您使用 Lambda 控制台创建触发器时,Lambda 会自动创建基于资源的策略,授予您选择的服务调用函数的权限。

五、使用虚拟事件测试 Lambda 函数

使用虚拟事件测试 Lambda 函数(控制台)
  1. 打开 Lambda 控制台的函数页面,然后选择函数 (CreateThumbnail)。

  2. 选择测试选项卡。

  3. 要创建测试事件,在测试事件窗格中,执行以下操作:

    1. 测试事件操作下,选择创建新事件

    2. 对于事件名称,输入 myTestEvent

    3. 模板中,选择 S3 Put

    4. 将以下参数的值替换为您自己的值。

      • 对于 awsRegion,将 us-east-1 替换为在其中创建 Amazon S3 存储桶的 AWS 区域。

      • 对于 name,将 DOC-EXAMPLE-BUCKET 替换为您自己的 Amazon S3 源存储桶的名称。

      • 对于 key,将 test%2Fkey 替换为您在步骤 将测试图片上传到源存储桶 中上传到源存储桶的测试对象的文件名。

{
  "Records": [
    {
      "eventVersion": "2.0",
      "eventSource": "aws:s3",
      "awsRegion": "us-east-1",
      "eventTime": "1970-01-01T00:00:00.000Z",
      "eventName": "ObjectCreated:Put",
      "userIdentity": {
        "principalId": "EXAMPLE"
      },
      "requestParameters": {
        "sourceIPAddress": "127.0.0.1"
      },
      "responseElements": {
        "x-amz-request-id": "EXAMPLE123456789",
        "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
      },
      "s3": {
        "s3SchemaVersion": "1.0",
        "configurationId": "testConfigRule",
        "bucket": {
          "name": "DOC-EXAMPLE-BUCKET",
          "ownerIdentity": {
            "principalId": "EXAMPLE"
          },
          "arn": "arn:aws:s3:::DOC-EXAMPLE-BUCKET"
        },
        "object": {
          "key": "test%2Fkey",
          "size": 1024,
          "eTag": "0123456789abcdef0123456789abcdef",
          "sequencer": "0A1B2C3D4E5F678901"
        }
      }
    }
  ]
}