使用 S3、Libvips 和 Ruby 的 AWS Lambda 微服务研讨会

2025-06-04

使用 S3、Libvips 和 Ruby 的 AWS Lambda 微服务研讨会

有兴趣使用 Ruby 从头学习 AWS 和 Lambda 吗?本次研讨会利用 Docker 和AWS SAM Cookiecutter 模板,提供快速且配置简单的课程。您将学习以下内容,并学习如何编写一个响应 S3 事件以调整源镜像大小的 Lambda。

研讨会步骤

想快速学习,稍后再阅读?在每个部分中,找到以⚡️⏩⚡️符号开头的代码框,输入或应用它们,即可轻松完成整个工作坊。不过,请务必抽出时间跟进并稍后阅读笔记。以下是今天工作坊的步骤。

  1. 使用 SAM Init 的新项目
  2. 设置和部署
  3. 将 Lambda 连接到 S3
  4. 图像处理和 Lambda 层
  5. 调整器代码和权限
  6. 后续步骤和资源

准备

🚢 安装 Docker

AWS SAM 使用 Docker 来模拟 Ruby Lambda 运行时环境。我们还使用 Docker 来避免同时安装 AWS CLI 和 SAM CLI。由于两者都使用 Python,安装起来可能会比较麻烦。不用担心,Docker 也能帮您解决这个问题。如果您还没有安装Docker,请立即安装。它能正常工作吗?

$ docker --version
Docker version 19.03.8, build afacb8b
Enter fullscreen mode Exit fullscreen mode

⛅️ AWS 账户

毕竟,从现在开始,我们就在云端了——所以你需要一个 AWS 账户。创建账户非常简单。之后,你需要使用账户的AWS_ACCESS_KEY_ID和 来配置程序访问权限。如果你还没有这些权限,可以在AWS 管理控制台AWS_SECRET_ACCESS_KEY中执行以下操作来创建它们

  • 点击工具栏中的“服务”。
  • 在查找服务字段中输入“IAM”,然后选择。
  • 单击左侧导航中的“用户”,选择您的用户名。
  • 单击“安全凭证”选项卡。
  • 单击“创建访问密钥”按钮。
  • 将您的密钥 ID 和秘密复制到安全的地方。

从这里开始,您需要配置 CLI 程序访问。使用 AWS CLI Docker 容器可以轻松完成此操作。

$ docker run \
  --interactive \
  --tty \
  --rm \
  --volume "${HOME}/.aws:/root/.aws" \
  "amazon/aws-cli" \
  configure
Enter fullscreen mode Exit fullscreen mode

出现提示时,请粘贴上述步骤中生成的密钥 ID 和密钥。我建议使用us-east-1默认区域和json输出格式。为了aws简化所有 CLI 命令,我建议使用以下别名。

alias aws='docker run --rm -it --tty -v "${HOME}/.aws:/root/.aws" -v "${PWD}:/aws" "amazon/aws-cli"'
Enter fullscreen mode Exit fullscreen mode

或者,您可以通过 Homebrew 安装 AWS CLI 和 SAM。

$ brew install awscli
$ brew tap aws/tap
$ brew install aws-sam-cli
Enter fullscreen mode Exit fullscreen mode

假设您已运行configure并设置了别名。它能正常工作吗?此命令应该会列出您 AWS 账户中的所有 S3 存储桶。

$ aws s3 ls
Enter fullscreen mode Exit fullscreen mode

🚀 CI/CD

这部分是可选的。但是,如果您已经git安装并使用 GitHub,那么提交我们的工作不仅有趣,还能确保代码探索的安全。如果您两者都没有,也没关系,您可以放心地跳过这些步骤。

但是,如果您有 GitHub 帐户,我们的入门项目包含一个GitHub Action Workflow,可以帮助您以完全自动化的方式实践持续集成和持续交付 (CI/CD)。稍后会详细介绍。

步骤 1:使用 SAM Init 新建项目

自从Serverless框架首次出现以来,大多数开发者都对其非常熟悉。可以将其视为每个云提供商“无服务器”产品的 ActiveRecord 适配器。它是一个由社区插件支持的高阶抽象。

为了简化其 Lambda 产品的开发周期,AWS 开发了一款名为 🐿 SAM 的工具,它是无服务器应用程序模型 (Serverless Application Model)的缩写。SAM 包含用于表达函数的 YAML 语法名称,以及用于运行、构建和部署该函数的命令行工具。

❓为什么要使用 SAM 而不是无服务器?这两个工具都是开源的。但是,如果您是无服务器新手并且正在使用 AWS,我建议您使用 SAM。学习太多抽象层可能会令人沮丧。所以,在升级之前(如果有需要的话),请坚持使用 SAM 并学习它。

SAM初始化

要启动一个新的 SAM 项目,我们将使用一个 Docker 容器来运行,sam init该容器利用这个自定义 Ink Cookiecutter 项目模板为您启动一个新的项目文件夹。

⚡️⏩⚡️

$ docker run \
  --interactive \
  --volume "${PWD}:/var/task:delegated" \
  lambci/lambda:build-ruby2.7 \
  sam init --location "gh:customink/cookiecutter-ruby"
Enter fullscreen mode Exit fullscreen mode

它会提示您输入项目名称,并询问您的 Lambda 是否需要 HTTP API。请使用“image_service”作为此名称。此外,我们不希望此 Lambda 产生 HTTP 事件,因此在第二个问题中输入“2” 。

  • 项目名称 [my_awesome_lambda]: image_service
  • 选择 http_api 1 - 是 2 - 否:2️⃣

现在切换到你新创建的项目目录。所有其他命令都假定你位于此工作目录中。

⚡️⏩⚡️

$ cd image_service
Enter fullscreen mode Exit fullscreen mode

🚀 CI/CD

假设您正在使用 git,并且在处理此项目时创建了一个 GitHub 仓库,请创建您的第一个提交并推送。请记住,首先在 GitHub 上创建一个新的仓库。

⚡️⏩⚡️

$ git init && git add .
$ git commit -m "Initial commit"
$ git remote add origin git@github.com:YOURUSERNAME/image_service.git
$ git push -u origin master
Enter fullscreen mode Exit fullscreen mode

❗️YOURUSERNAME用你自己的 GitHub 用户名替换。

发生了什么?

您的新 SAM 项目文件夹包含您新 Ruby Lambda 所需的一切。请花些时间浏览其内容。特别是template.yaml描述您的 Lambda 函数的 SAM 文件。该文件指定了一个用于lib/image_service.rb接收事件的处理程序方法。从更高层次来看,以下是新项目中生成的内容。

  • Dockerfile使用和来进行 Docker 设置docker-compose
  • 一个具有 lib 目录、捆绑器和测试的工作 Ruby 项目。
  • SAM 完全集成到所有设置和测试脚本中。

在整个研讨会期间,您将有机会熟悉所有这些内容。

第 2 步:设置和部署

在当前状态下,Lambda 唯一会做的事情就是记录触发它的事件。与其等待重大版本发布,不如趁着首次部署熟悉流程的好时机。首先,我们需要设置项目的依赖项并运行测试。这些命令类似于标准脚本,用于执行一次性引导或可重复的设置。例如,如果您在 Gemfile 中更改了依赖项。

⚡️⏩⚡️

$ ./bin/bootstrap
$ ./bin/setup
$ ./bin/test
Enter fullscreen mode Exit fullscreen mode

如果您的测试运行良好,您应该会看到类似这样的输出。

# Running:
.
Finished in 0.000992s, 1008.4712 runs/s, 1008.4712 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
Enter fullscreen mode Exit fullscreen mode

您的第一次部署

⚡️⏩⚡️

$ STAGE_ENV=production ./bin/deploy
Enter fullscreen mode Exit fullscreen mode

这将使用 AWS SAM 的构建、打包和部署 CLI 命令。假设一切顺利,您应该会看到 SAM 的 CloudFormation 部署任务的输出以类似以下内容结尾。请花点时间查看完整输出。

CloudFormation outputs from deployed stack
---------------------------------------------------------------------------------------------
Outputs
---------------------------------------------------------------------------------------------
Key                 ImageServiceLambdaArn
Description         Lambda Function Arn
Value               arn:aws:lambda:us-east-1:012345678912:function:image-service-production
---------------------------------------------------------------------------------------------

Successfully created/updated stack - image-service-production in us-east-1
Enter fullscreen mode Exit fullscreen mode

💥有问题吗?你确定运行了bin/bootstrap脚本吗?它应该会创建一个 S3 存储桶来存储你打包的工件。请检查.bucket-name你的 AWS 账户中是否存在该文件以及该存储桶。

调用您的 Lambda

即使没有任何事件处理程序,我们仍然可以调用并测试您的 Lambda 是否已成功部署。登录AWS 管理控制台

  • 点击工具栏中的“服务”。
  • 在查找服务字段中输入“CloudFormation”,然后选择。

在此页面中,您将看到新部署的镜像服务 Lambda 被列为“堆栈”。堆栈是项目的 AWS 资源集合。

您的 CloudFormation Ruby 堆栈

点击您的堆栈,然后点击“资源选项卡”。您的 Lambda 项目只有两个资源:Lambda 本身以及它所执行的 IAM 角色。

  • 点击“物理 ID”列下的“image-service-productions”Lambda 资源。这将带您进入 AWS 控制台中的 Lambda。
  • 点击右上角的“测试”按钮。
  • 使用“Hello World”事件模板。
  • 将其命名为“HelloWorld”。
  • 单击“创建”按钮。
  • 现在单击“测试”按钮来调用您的 Lambda

测试您的图像服务 Lambda

🎉 恭喜!

您的新 Lambda 已运行。从我们刚刚执行的测试调用中,您可以看到返回值:一个包含状态码的 Ruby 哈希、一个标头数组以及一个响应正文。在本例中,Lambda 只是以 JSON 字符串的形式返回了它收到的相同事件。这就是您项目中的处理程序方法。

def handler(event:, context:)
  puts event
  { statusCode: 200,
    headers: [{'Content-Type' => 'application/json'}],
    body: JSON.dump(event) }
end
Enter fullscreen mode Exit fullscreen mode

CloudWatch 日志

那么,Ruby 处理程序中的调用怎么办puts?标准输出又写到哪里了?日志记录到文件又怎么样?除了有限的存储空间外/tmp,Lambda 无法写入文件系统。所有标准输出(日志)都会被 CloudWatch 捕获并写入日志组。该服务完全托管。查看我们测试调用的日志。

  • 点击工具栏中的“服务”。
  • 在查找服务字段中输入“CloudWatch”,然后选择。
  • 单击左侧菜单中的“日志组”。
  • 找到名为“/aws/lambda/image-service-production”的日志组并选择它。

从这里开始,CloudWatch 将日志按日期整理成流。点击其中一个即可查看测试调用的日志。

START RequestId: 0d6c34b2-42f0-439f-9f65-c35050e8da3e Version: $LATEST
{"key1"=>"value1", "key2"=>"value2", "key3"=>"value3"}
END RequestId: 0d6c34b2-42f0-439f-9f65-c35050e8da3e
REPORT RequestId: 0d6c34b2-42f0-439f-9f65-c35050e8da3e  Duration: 2.93 ms Billed Duration: 100 ms Memory Size: 512 MB Max Memory Used: 49 MB  Init Duration: 255.06 ms
Enter fullscreen mode Exit fullscreen mode

❗️当出现问题时,深入研究 CloudWatch 日志是您应该首先查看发生了什么的地方之一。

🚀 CI/CD

由于 SAM 已捆绑并打包了我们的 Lambda,因此Gemfile.lock我们的项目中新增了一个功能,确保我们的 gem 已锁定。我们可以在继续下一步之前提交此更改。

⚡️⏩⚡️

$ git add .
$ git commit -m "Add Gemfile.lock"
$ git push
Enter fullscreen mode Exit fullscreen mode

步骤 3:将 Lambda 连接到 S3

现在该熟悉一下 AWS SAM 项目中的文件了。它们的组织方式通常与 Ruby Gem 类似。有一个lib目录,其中包含与您的项目名称匹配的文件和文件夹。Ruby 文件是同名目录中所有必需文件的入口点。此外,还包含Gemfile任何其他 Gem 依赖项的入口。

但是在部署过程中,我们如何在 AWS 中创建资源?此外,Lambda 如何知道在哪里调用你的 Ruby 代码?

模板.yaml

这是CloudFormation的 SAM 规范,用于指导如何构建项目所需的一切。您可以将其视为简化 AWS Lambda 开发的语法糖。

❗️需要记住的是,SAM 规范是 CloudFormation 的子集。任何有效的 CloudFormation 都可以在此模板中使用。

部署脚本运行时,SAM 会检查您的模板文件,找到您的代码,将其打包成一个压缩文件,上传到 S3 存储桶,然后使用新打包的 template.yaml 文件指示 CloudFormation 为您构建所需的 AWS 资源。请花些时间检查您的template.yaml文件。请注意以下几点:

  • Resources部分包含您需要在 AWS 中为此项目创建的所有内容。
  • 您的函数的资源Runtime属性已设置为 Ruby 2.7。它还具有内存和超时设置。
  • 函数部分Handler是 SAM 了解代码所在位置的方式。它会查找lib/image_service.rb包含调用方法的文件handler
  • CloudFormation 实际上是一种半动态语言。它通过称为伪参数的概念支持运行时反射,以及称为内部函数的行为。

❓SAM 把我的代码上传到哪个存储桶了?好问题!在上传过程中bin/bootstrap,我们为您创建了一个随机存储桶名称。该名称存储在一个.bucket-name文件中。

添加您的 S3 资源

上面有很多信息,SAM/CloudFormation 确实有很多功能。但让我们慢慢开始,创建 Lambda 的 S3 存储桶,以便它可以监听事件并最终调整图像大小。将以下内容添加ImageServiceS3Buckettemplate.yaml文件中的Resources部分下。由于缩进很重要,我们已显示了相对于 的位置ImageServiceLambda。不过顺序并不重要。

⚡️⏩⚡️

Resources:
  ImageServiceLambda:
    # ...
  ImageServiceS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub image-service-SOMEUNIQNAME-${StageEnv}
Enter fullscreen mode Exit fullscreen mode

❗️S3 bucket 名称是全局的。因此请将SOMEUNIQNAME上面的内容替换为您自己的唯一名称。

触发 Lambda 事件

还记得我们的 Lambda 之前没有关联任何事件,需要我们手动触发测试吗?现在我们已经声明了 S3 存储桶资源,可以指示 SAM/CloudFormation 从任何S3 通知触发我们的 Lambda 。我们将选择任何ObjectCreated事件。SAM 允许我们提供Events属性,而这正是我们要添加属性的地方。请参阅下面的示例,了解如何在本ImageServiceLambda Properties节下添加属性。

⚡️⏩⚡️

ImageServiceLambda:
  Type: AWS::Serverless::Function
  Properties:
    # ...
    Events:
      ImageServiceS3BucketEvent:
        Type: S3
        Properties:
          Bucket: !Ref ImageServiceS3Bucket
          Events: s3:ObjectCreated:*
Enter fullscreen mode Exit fullscreen mode

ImageServiceS3BucketEvent被称为逻辑ID。它由我们定义,可以是任何我们想要的值,就像ImageServiceS3Bucket上面一样。

我们的 S3 事件确实需要两样东西:存储桶的名称以及我们想要触发 Lambda 的事件。其!Ref语法是我之前提到的内部函数之一。在本例中,我们赋予它上一步模板中存储桶资源的逻辑 ID。之所以能够成功,是因为 S3 存储桶的 Ref 返回值就是其名称。

部署更新的堆栈

又到了部署的时间了。部署时,请仔细观察 SAM 的输出。它展示了 CloudFormation 如何检测堆栈的变更,注意到新增资源以及哪些资源需要修改。它愉快地整理了所有这些,甚至确定了事件需要按什么顺序发生才能获得所需的结果。简直太神奇了!✨

⚡️⏩⚡️

$ STAGE_ENV=production ./bin/deploy
Enter fullscreen mode Exit fullscreen mode

测试 S3 上传触发器 Lambda

现在,我们的存储桶已通过堆栈部署创建完成,接下来我们来上传一个镜像,看看它是否能触发 Lambda 函数。这里有一个有趣的文件,名为RubyForGood.png,我们可以通过 AWS 控制台上传它。

Ruby For Good S3 测试镜像

  • 点击工具栏中的“服务”。
  • 在查找服务字段中输入“S3”,然后选择。
  • 单击名为 的 S3 存储桶image-service-SOMEUNIQNAME-production。 其中SOMEUNIQNAME是您之前选择的名称。
  • 将此文件拖放到浏览器窗口即可启动上传对话框。
  • 单击“下一步”3次,使用权限等的默认值。最后单击“上传”开始上传。

之后,您应该会看到文件已上传到 S3 存储桶。但是我们的 Lambda 是否收到了该事件?使用上一章中的CloudWatch 步骤,导航到您的日志组,查看您的 Lambda 是否收到了该事件并记录了它。您应该看到类似这样的内容。

{
  "Records": [
    {
      "eventVersion": "2.1",
      "eventSource": "aws:s3",
      "awsRegion": "us-east-1",
      "eventTime": "2020-04-26T23:40:00.273Z",
      "eventName": "ObjectCreated:Put",
      "userIdentity": {
        "principalId": "AWS:AIDAJIS4TINW4H5GRI3LG"
      },
      "requestParameters": {
        "sourceIPAddress": "72.228.219.152"
      },
      "responseElements": {
        "x-amz-request-id": "B1C967507AE19561",
        "x-amz-id-2": "CwSljyyyFADdm1Cyf06BsYkfWfoojX5CX7ezcT1Y9uWSF/L4mWGjz01cnPpGg+W+fiWEiCj2oQjTkELtfJFny5DlbB80UXkz"
      },
      "s3": {
        "s3SchemaVersion": "1.0",
        "configurationId": "8fe91e68-1782-47d8-93a1-470f89531673",
        "bucket": {
          "name": "image-service-SOMEUNIQNAME-production",
          "ownerIdentity": {
            "principalId": "A4ILFJ7OF8X06"
          },
          "arn": "arn:aws:s3:::image-service-SOMEUNIQNAME-production"
        },
        "object": {
          "key": "RubyForGood.png",
          "size": 659624,
          "eTag": "a2028b43a11dd778720371ceaf53dde5",
          "sequencer": "005EA59B740BD1E80F"
        }
      }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

事实上,这个事件对我们最终的测试套件可能很有用。我建议把它添加到你的项目中test/events/s3-put.json。稍后我们可以用它来进行一些最终的测试驱动开发。

🚀 CI/CD

这似乎是拯救我们工作成果的另一个好时机。

⚡️⏩⚡️

$ git add .
$ git commit -m "Connecting Lambda to S3"
$ git push
Enter fullscreen mode Exit fullscreen mode

步骤4:图像处理和Lambda层

为了调整图像大小,我们需要选择一个 Ruby 库来帮我们完成这项工作。值得庆幸的是,Rails ActiveStorage提供了一个很棒的库,名为ImageProcessing,它可以利用 ImageMagick 或 Libvips 来调整图像大小。

将其添加到您的Gemfile

⚡️⏩⚡️

gem 'image_processing'
Enter fullscreen mode Exit fullscreen mode

添加 Libvips

谈到 Lambda 时,我们通常称之为“无服务器”,但实际上,从技术角度来看,它确实涉及服务器。具体来说,它们是执行代码的微型虚拟机。您可以将它们视为托管容器,我们称之为“运行时”。如果您查看项目template.yaml文件,您会发现我们函数的资源Runtime属性设置为ruby2.7。顾名思义,这些微型虚拟机仅包含执行所需任务所需的极简软件,例如,安装了 Ruby。这确保了它们体积小巧,并且能够快速执行代码。

通常,带有原生 C 扩展的 Ruby 库需要头文件或共享对象来编译或链接。ImageMagick 和 Libvips 都需要其他共享对象。AWS Lambda 的现代运行时并未预装这些共享对象。您可以使用一种名为Lambda Layers的技术来完成这项工作。Layers 工作原理最简单的解释是,它们会将代码添加到运行时的/opt目录中。我们将使用一个 Lambda 层,将Libvips添加到我们的运行时中,以便 ImageProcessing gem 能够使用它。

在文件的功能部分下添加此公共 Libvips 层资源ARNPropertiestemplate.yaml

⚡️⏩⚡️

ImageServiceLambda:
  Type: AWS::Serverless::Function
  Properties:
    # ...
    Layers:
      - arn:aws:lambda:us-east-1:589405201853:layer:rubyvips892-27:13
Enter fullscreen mode Exit fullscreen mode

❓我可以了解更多关于这个 Libvips 层是如何构建的吗?是的,这里是用于构建该层的ruby​​-vips-lambda项目。此外, Yumda项目对于其他常见的层用例也是一个很好的选择。

权限

还记得我们第一次部署Lambda 并在 AWS 控制台中查看 CloudFormation 堆栈时吗?在“资源”选项卡中有一个 类型AWS::IAM::Role。SAM 自动为我们创建了这个角色。调用时,我们的 Lambda 将使用附加到此角色的任何托管或内联策略执行。如果我们的 Lambda 要读写 S3 存储桶,则需要权限。幸运的是,借助 AWS SAM 框架,使用Policies属性可以非常轻松地完成此操作。

任何有效的 AWS Identity & Access Management语句都可以在本节中以集合的形式表示。每个语句都将附加到您的 Lambda 函数的角色。以下是一个简单的示例,它声明此 Lambda 可以对其拥有的 S3 存储桶执行任何操作。

⚡️⏩⚡️

ImageServiceLambda:
  Type: AWS::Serverless::Function
  Properties:
    # ...
    Policies:
      - Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action:
              - s3:*
            Resource:
              - !Sub arn:aws:s3:::image-service-SOMEUNIQNAME-${StageEnv}
              - !Sub arn:aws:s3:::image-service-SOMEUNIQNAME-${StageEnv}/*
Enter fullscreen mode Exit fullscreen mode

❗️S3 bucket 名称是全局的。因此,请将SOMEUNIQNAME上面的名称替换为您自己的唯一名称。确保它与您在资源中使用的名称匹配ImageServiceS3Bucket

🚀 CI/CD

我们尚未完成读写 S3 bucket 所需的全部代码。所以现在无需提交工作。

步骤 5:Resizer 代码和权限

在本节中,我们将响应“将 Lambda 连接到 S3”部分中的新 S3 事件。以下是我们的代码将执行的步骤:

  • 从我们的 S3 存储桶中读取图像文件。
  • 将图像调整为 200px 宽作为新图像。
  • 将该图像以新名称上传回同一个 S3 存储桶。

Resizer 类

我编写了这个简单的 Ruby 对象(PO​​RO)类来帮我们完成这项工作。请花点时间仔细阅读一下。以下是一些高阶调用:

  • 需要 ImageProcessing gem 的Vips实现。
  • 创建一个Aws::S3::Client要使用的客户端。
  • 使用 S3 键和可选的所需大小进行初始化。
  • 如果图像尚未调整大小,则调整其大小。
  • 利用 S3 元数据避免递归调整大小事件。
  • 所有工作都是使用缓冲区在内存中完成还是写入磁盘?

使用以下代码在项目中lib/image_service名为resizer.rbfile 的目录中创建一个新文件。💥请将常量更改SOMEUNIQNAMEBUCKET与您的实际存储桶名称匹配。💥

⚡️⏩⚡️

require 'aws-sdk-s3'
require 'image_processing/vips'

module ImageService
  class Resizer
    CLIENT = Aws::S3::Client.new region: Env.region
    BUCKET = "image-service-SOMEUNIQNAME-#{Env.stage}"

    attr_reader :key, :size

    def initialize(key, size = 200)
      @key = key
      @size = size
    end

    def resize!
      return if resized?
      resized = ImageProcessing::Vips
        .source(source)
        .resize_to_limit(size, nil)
        .call(save: false)
        .write_to_buffer(File.extname(key))
      put_object resized, new_key
    end

    def source
      if File.extname(key) == '.png'
        Vips::Image.pngload_buffer(get_object)
      else
        Vips::Image.new_from_buffer(get_object, File.extname(key))
      end
    end

    def new_key
      "#{File.basename(key, File.extname(key))}-#{size}#{File.extname(key)}"
    end

    def get_object
      CLIENT.get_object(bucket: BUCKET, key: key).body.read
    end

    def put_object(object, put_key)
      CLIENT.put_object bucket: BUCKET, key: put_key, body: object,
                        metadata: { 'resized' => '1' }
    end

    def resized?
      metadata['resized'] == '1'
    end

    def metadata
      response = CLIENT.head_object bucket: BUCKET, key: key
      response.metadata || {}
    rescue Aws::S3::Errors::NotFound
      {}
    end

  end
end
Enter fullscreen mode Exit fullscreen mode

❓我注意到你确实需要了,aws-sdk-s3但它并没有添加到你的 中Gemfile,这是怎么回事?每个 Lambda 运行时都预装了 SDK 包,以便于执行常见任务。在本例中,Aws::S3 SDK 就是其中之一。

❓我注意到你没有将 anAWS_ACCESS_KEY_ID或 a传递AWS_SECRET_ACCESS_KEY给客户端?这是怎么回事?由于我们的 Lambda 是通过上一步中添加的执行角色调用的,所以我们无需管理密钥或机密。所有客户端 SDK 都会自动使用该角色。欢迎来到未来!

处理程序变更

现在我们有了可以调整 S3 对象大小的 Ruby 对象,我们需要将它连接到 Lambda 的处理函数中。以下代码已更改为:

  • 为我们的新文件添加了要求。
  • 从事件中获取 S3 密钥。
  • 创建一个新的 Resizer 实例。调整文件大小。
  • 返回一些有意义的响应。S3 键。

更新您的image_service.rb文件以使用此代码。

⚡️⏩⚡️

require 'json'
require 'dotenv'
require_relative './image_service/env'
require_relative './image_service/resizer'

def handler(event:, context:)
  key = event['Records'][0].dig('s3','object','key')
  resizer = ImageService::Resizer.new(key, 200)
  resizer.resize!
  { statusCode: 200,
    headers: [{'Content-Type' => 'application/json'}],
    body: JSON.dump({key: key}) }
end
Enter fullscreen mode Exit fullscreen mode

部署更新的堆栈

需要改变的事情有很多,但现在我们已准备好部署并看到我们的努力取得成效。

⚡️⏩⚡️

$ STAGE_ENV=production ./bin/deploy
Enter fullscreen mode Exit fullscreen mode

看看它是如何工作的

就像在将 Lambda 连接到 S3步骤中一样,我们将上传我们的测试图像,RubyForGood.png如右图所示。

  • 点击工具栏中的“服务”。
  • 在查找服务字段中输入“S3”,然后选择。
  • 单击名为 的 S3 存储桶image-service-SOMEUNIQNAME-production。其中 SOMEUNIQNAME 是您之前选择的名称。
  • 删除我们之前上传的文件。

现在将我们的文件拖放RubyForGood.png到 S3 浏览器窗口中,点击三次“下一步”,使用权限等默认值。最后点击“上传”开始上传。上传完成后,点击几次♻️按钮,直到看到新文件出现。

新的 RubyForGood.png 已调整大小

💥 你没看到新文件吗?去检查一下你的 CloudWatch 日志,看看发生了什么。如果你有任何问题或遇到困难,可以通过GitHub Issues寻求帮助,我很乐意为你提供帮助。

🚀 CI/CD

如果一切顺利,现在是提交代码的好时机。

后续步骤和资源

以下是我建议做的一些事情,以继续学习或深入研究 AWS 生态系统。

🚀 自动化 CI/CD - 你是否厌倦了无休止bin/deploy地重复工作?想使用 GitHub Actions 实现自动化流程?本项目包含一个工作流程,助你快速上手。打开项目的 README 文件,了解具体操作步骤。

HTTP Web 服务- 使用 cookie 模板的 HTTP 选项创建一个小型 Web 服务。这将帮助你学习 API 网关HTTP API

使 CloudWatch 日志过期- 设置您的 CloudWatch 日志过期。没错,您需要为它们付费,直到永远。您可以根据需要设置它们的过期时间。

S3 CloudFormation 存储桶- 在此bin/bootstrap过程中,我们为您创建了一个动态存储桶名称,并将其存储在.bucket-name文件中。通常,建议在不同项目中使用相同的 S3 存储桶。

资源

找到下一步行动并知道在哪里寻求帮助可能会很困难。以下是我在使用 SAM 编写 AWS Lambda 代码时参考的一些地方。

AWS 无服务器应用程序模型 (AWS SAM) 规范- 从属性引用到内部函数,涵盖您需要了解的所有内容template.yaml。请记住,无服务器应用程序模型 (SAM) 规范是 CloudFormation 的一个更专注、更简洁的子集,旨在简化 Lambda 开发。

AWS 资源和属性类型参考在模板中传递 AWS 资源时,了解内部函数的返回值会很有帮助Ref。每个资源都不同。有时是名称,有时是 ARN。

文章来源:https://dev.to/aws-heroes/aws-lambda-microservice-workshop-using-s3-libvips-ruby-4o96
PREV
无服务器:赋予前端开发人员超能力的后端技术
NEXT
创建容器镜像的艺术和最佳实践