View a markdown version of this page

使用构建 Rust Lambda 事件函数 Cargo Lambda in AWS SAM - AWS Serverless Application Model

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

使用构建 Rust Lambda 事件函数 Cargo Lambda in AWS SAM

使用 AWS Serverless Application Model 命令行接口 (AWS SAMCLI) 和 Rust AWS Lambda 事件函数。

先决条件

Rust 语言

要安装 Rust,请参阅 Rust 语言网站上的安装 Rust。

Cargo Lambda

AWS SAM CLI 要求安装 Cargo Lambda,是 Cargo 的子命令。有关安装说明,请参阅 Cargo Lambda 文档中的安装。

Docker

构建和测试 Rust Lambda 函数需要 Docker。有关安装说明,请参阅安装 Docker。

配置 AWS SAM 与 Rust Lambda 事件函数一起使用

第 1 步:配置你的 AWS SAM 模板

使用以下内容配置您的 AWS SAM 模板:

  • 二进制 – 可选。指定单个Cargo软件包何时定义多个二进制文件,以确定要为此函数生成哪个二进制文件。当每个函数都是自己的Cargo包时(例如在Cargo工作区中),则不需要此属性。

  • BuildMethod – rust-cargolambda.

  • CodeUri— Cargo.toml 文件路径。

  • 处理程序 – bootstrap.

  • 运行时系统 – provided.al2023.

要了解有关自定义运行时的更多信息,请参阅《AWS Lambda 开发者指南AWS Lambda 》中的自定义运行时。

以下是已配置 AWS SAM 模板的示例:

AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 ... Resources: MyFunction: Type: AWS::Serverless::Function Metadata: BuildMethod: rust-cargolambda BuildProperties: function_a Properties: CodeUri: ./rust_app Handler: bootstrap Runtime: provided.al2023 ...

第 2 步:使用 AWS SAM CLI 使用你的 Rust Lambda 事件函数

在 AWS SAM 模板中使用任意 AWS SAMCLI命令。有关更多信息,请参阅 AWS SAM CLI。

示例

Hello World 示例

在此示例中,我们使用 Rust 作为运行时系统来构建示例 Hello World 应用程序。

首先,我们使用 sam init 初始化新的无服务器应用程序。在交互式流程中,我们选择 Hello World 应用程序并选择 Rust 运行时系统。

$ sam init ... Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location Choice: 1 Choose an AWS Quick Start application template 1 - Hello World Example 2 - Multi-step workflow 3 - Serverless API ... Template: 1 Use the most popular runtime and package type? (Python and zip) [y/N]: ENTER Which runtime would you like to use? 1 - dotnet8 2 - dotnet6 3 - go (provided.al2) ... 18 - python3.11 19 - python3.10 20 - ruby4.0 21 - ruby3.3 22 - ruby3.2 23 - rust (provided.al2) 24 - rust (provided.al2023) Runtime: 24 Based on your selections, the only Package type available is Zip. We will proceed to selecting the Package type as Zip. Based on your selections, the only dependency manager available is cargo. We will proceed copying the template using cargo. Would you like to enable X-Ray tracing on the function(s) in your application? [y/N]: ENTER Would you like to enable monitoring using CloudWatch Application Insights? For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: ENTER Project name [sam-app]: hello-rust ----------------------- Generating application: ----------------------- Name: hello-rust Runtime: rust (provided.al2023) Architectures: x86_64 Dependency Manager: cargo Application Template: hello-world Output Directory: . Configuration file: hello-rust/samconfig.toml Next steps can be found in the README file at hello-rust/README.md Commands you can use next ========================= [*] Create pipeline: cd hello-rust && sam pipeline init --bootstrap [*] Validate SAM template: cd hello-rust && sam validate [*] Test Function in the Cloud: cd hello-rust && sam sync --stack-name {stack-name} --watch

以下是 Hello World 应用程序的结构:

hello-rust
├── README.md
├── events
│   └── event.json
├── rust_app
│   ├── Cargo.toml
│   └── src
│       └── main.rs
├── samconfig.toml
└── template.yaml

在我们的 AWS SAM 模板中,我们的Rust函数定义如下:

AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 ... Resources: HelloWorldFunction: Type: AWS::Serverless::Function Metadata: BuildMethod: rust-cargolambda Properties: CodeUri: ./rust_app Handler: bootstrap Runtime: provided.al2023 Architectures: - x86_64 Events: HelloWorld: Type: Api Properties: Path: /hello Method: get

接下来,运行 sam build 以构建应用程序并准备部署。 AWS SAM CLI 创建一个 .aws-sam 目录并在其中整理构建构件。函数是使用 Cargo Lambda 构建,并以可执行二进制文件的形式存储于 .aws-sam/build/HelloWorldFunction/bootstrap。

注意

如果您计划在 MacOS 中运行 sam local invoke 命令,则需要在调用之前构建不同的函数。要执行此操作,请使用以下命令:

  • SAM_BUILD_MODE=debug sam build

仅在完成本地测试时才需要此命令。在为部署构建时,不建议这样做。

hello-rust$ sam build Starting Build use cache Cache is invalid, running build and copying resources for following functions (HelloWorldFunction) Building codeuri: /Users/.../hello-rust/rust_app runtime: provided.al2023 metadata: {'BuildMethod': 'rust-cargolambda'} architecture: x86_64 functions: HelloWorldFunction Running RustCargoLambdaBuilder:CargoLambdaBuild Running RustCargoLambdaBuilder:RustCopyAndRename Build Succeeded Built Artifacts : .aws-sam/build Built Template : .aws-sam/build/template.yaml Commands you can use next ========================= [*] Validate SAM template: sam validate [*] Invoke Function: sam local invoke [*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch [*] Deploy: sam deploy --guided

接下来,使用 sam deploy --guided 部署应用程序。

hello-rust$ sam deploy --guided Configuring SAM deploy ====================== Looking for config file [samconfig.toml] : Found Reading default arguments : Success Setting default arguments for 'sam deploy' ========================================= Stack Name [hello-rust]: ENTER AWS Region [us-west-2]: ENTER #Shows you resources changes to be deployed and require a 'Y' to initiate deploy Confirm changes before deploy [Y/n]: ENTER #SAM needs permission to be able to create roles to connect to the resources in your template Allow SAM CLI IAM role creation [Y/n]: ENTER #Preserves the state of previously provisioned resources when an operation fails Disable rollback [y/N]: ENTER HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y Save arguments to configuration file [Y/n]: ENTER SAM configuration file [samconfig.toml]: ENTER SAM configuration environment [default]: ENTER Looking for resources needed for deployment: ... Uploading to hello-rust/56ba6585d80577dd82a7eaaee5945c0b 817973 / 817973 (100.00%) Deploying with following values =============================== Stack name : hello-rust Region : us-west-2 Confirm changeset : True Disable rollback : False Deployment s3 bucket : aws-sam-cli-managed-default-samclisam-s3-demo-bucket-1a4x26zbcdkqr Capabilities : ["CAPABILITY_IAM"] Parameter overrides : {} Signing Profiles : {} Initiating deployment ===================== Uploading to hello-rust/a4fc54cb6ab75dd0129e4cdb564b5e89.template 1239 / 1239 (100.00%) Waiting for changeset to be created.. CloudFormation stack changeset --------------------------------------------------------------------------------------------------------- Operation LogicalResourceId ResourceType Replacement --------------------------------------------------------------------------------------------------------- + Add HelloWorldFunctionHelloW AWS::Lambda::Permission N/A orldPermissionProd ... --------------------------------------------------------------------------------------------------------- Changeset created successfully. arn:aws:cloudformation:us-west-2:012345678910:changeSet/samcli-deploy1681427201/f0ef1563-5ab6-4b07-9361-864ca3de6ad6 Previewing CloudFormation changeset before deployment ====================================================== Deploy this changeset? [y/N]: y 2023-04-13 13:07:17 - Waiting for stack create/update to complete CloudFormation events from stack operations (refresh every 5.0 seconds) --------------------------------------------------------------------------------------------------------- ResourceStatus ResourceType LogicalResourceId ResourceStatusReason --------------------------------------------------------------------------------------------------------- CREATE_IN_PROGRESS AWS::IAM::Role HelloWorldFunctionRole - CREATE_IN_PROGRESS AWS::IAM::Role HelloWorldFunctionRole Resource creation ... --------------------------------------------------------------------------------------------------------- CloudFormation outputs from deployed stack --------------------------------------------------------------------------------------------------------- Outputs --------------------------------------------------------------------------------------------------------- Key HelloWorldFunctionIamRole Description Implicit IAM Role created for Hello World function Value arn:aws:iam::012345678910:role/hello-rust-HelloWorldFunctionRole-10II2P13AUDUY Key HelloWorldApi Description API Gateway endpoint URL for Prod stage for Hello World function Value https://ggdxec9le9.execute-api.us-west-2.amazonaws.com/Prod/hello/ Key HelloWorldFunction Description Hello World Lambda Function ARN Value arn:aws:lambda:us-west-2:012345678910:function:hello-rust-HelloWorldFunction- yk4HzGzYeZBj --------------------------------------------------------------------------------------------------------- Successfully created/updated stack - hello-rust in us-west-2

为了进行测试,我们可以使用 API 端点调用 Lambda 函数。

$ curl https://ggdxec9le9.execute-api.us-west-2.amazonaws.com/Prod/hello/ Hello World!%

要在本地测试函数,首先我们要确保函数的 Architectures 属性与本地计算机相匹配。

... Resources: HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Metadata: BuildMethod: rust-cargolambda # More info about Cargo Lambda: https://github.com/cargo-lambda/cargo-lambda Properties: CodeUri: ./rust_app # Points to dir of Cargo.toml Handler: bootstrap # Do not change, as this is the default executable name produced by Cargo Lambda Runtime: provided.al2023 Architectures: - arm64 ...

由于我们在此示例中将基础设施从 x86_64 修改为 arm64,因此我们运行 sam build 以更新构建构件。然后运行 sam local invoke 在本地调用函数。

hello-rust$ sam local invoke Invoking bootstrap (provided.al2023) Local image was not found. Removing rapid images for repo public.ecr.aws/sam/emulation-provided.al2023 Building image..................................................................................................................................... Using local image: public.ecr.aws/lambda/provided:al2023-rapid-arm64. Mounting /Users/.../hello-rust/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated, inside runtime container START RequestId: fbc55e6e-0068-45f9-9f01-8e2276597fc6 Version: $LATEST {"statusCode":200,"body":"Hello World!"}END RequestId: fbc55e6e-0068-45f9-9f01-8e2276597fc6 REPORT RequestId: fbc55e6e-0068-45f9-9f01-8e2276597fc6 Init Duration: 0.68 ms Duration: 130.63 ms Billed Duration: 131 ms Memory Size: 128 MB Max Memory Used: 128 MB

单个 Lambda 事件函数项目

以下是一个包含单个 Rust Lambda 函数的无服务器应用程序的示例。

项目目录结构:

.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── template.yaml

AWS SAM 模板:

AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 ... Resources: MyFunction: Type: AWS::Serverless::Function Metadata: BuildMethod: rust-cargolambda Properties: CodeUri: ./ Handler: bootstrap Runtime: provided.al2023 ...

多个 Lambda 事件函数项目

以下是一个包含多个 Rust Lambda 函数的无服务器应用程序的示例,这些函数按Cargo工作空间进行组织。

我们建议为具有多个 Rust Lambda 函数的应用程序提供Cargo工作空间。每个函数都是自己的包,因此函数可以声明独立的依赖关系,同时通过库包共享公共代码。每个包都会生成一个以该包命名的二进制文件,因此您无需设置 Binary build 属性。

项目目录结构:

.
├── Cargo.lock
├── Cargo.toml
├── function_a
│   ├── Cargo.toml
│   └── src
│       └── main.rs
├── function_b
│   ├── Cargo.toml
│   └── src
│       └── main.rs
└── template.yaml

位于项目根目录的工作区Cargo.toml文件:

[workspace] resolver = "2" members = [ "function_a", "function_b", ] [workspace.dependencies] lambda_runtime = "0.13" serde = { version = "1", features = ["derive"] } tokio = { version = "1", features = ["macros", "rt"] }

Cargo.toml每个函数的文件,例如function_a/Cargo.toml:

[package] name = "function_a" version = "0.1.0" edition = "2021" [dependencies] lambda_runtime = { workspace = true } serde = { workspace = true } tokio = { workspace = true }

AWS SAM 模板。每个函数CodeUri的都指向该函数的包目录:

AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 ... Resources: FunctionA: Type: AWS::Serverless::Function Metadata: BuildMethod: rust-cargolambda Properties: CodeUri: ./function_a Handler: bootstrap Runtime: provided.al2023 FunctionB: Type: AWS::Serverless::Function Metadata: BuildMethod: rust-cargolambda Properties: CodeUri: ./function_b Handler: bootstrap Runtime: provided.al2023
注意

将工作区中的每个函数都 AWS SAMCLI构建到工作区的共享target目录中,因此每个函数只Cargo编译一次共享依赖关系,而不是编译一次。此行为需要 AWS SAMCLI版本 1.165.0 或更高版本。在早期版本中,每个函数都构建在自己的target目录中,并且会为每个函数重新编译完整的依赖树,这会使添加函数时生成速度变慢。

为每个函数包指定一个唯一的二进制名称。Package 名称在工作空间中是唯一的,因此默认的二进制名称已经是唯一的。如果用[[bin]]节覆盖二进制名称,请不要为两个包指定相同的二进制名称。它们编译到共享target目录中的相同路径并互相覆盖。当它检测到这一点时,会 AWS SAMCLI记录一条警告。

或者,一个包可以定义多个二进制文件。在这种情况下,请使用 Binary build 属性为每个函数选择二进制文件:

Resources: FunctionA: Type: AWS::Serverless::Function Metadata: BuildMethod: rust-cargolambda BuildProperties: Binary: function_a Properties: CodeUri: ./ Handler: bootstrap Runtime: provided.al2023

优化 Rust 内置版本 GitHub 行动

Rust 版本是计算密集型的,持续集成运行器一开始就没有编译过的工件。具有多个共享大型依赖关系的函数(例如)的 AWSSDK应用程序可能会将大部分构建时间花在编译相同的依赖项上。以下做法可缩短构建时间GitHub Actions。

对工作 AWS SAMCLI区使用 1.165.0 或更高版本

版本 1.165.0 及更高版本将工作空间的每个成员构建到Cargo工作空间的共享target目录中,因此共享依赖关系每次编译一次,而不是每个函数编译一次。在安装时指定最低版本, AWS SAMCLI这样编译版本就不会静默地回退到较慢的行为。

缓存Cargo注册表和target目录

在两次运行之间缓存Cargo注册表(~/.cargo/registry和~/.cargo/git/db)和工作区target目录,以便恢复未更改的依赖关系,而不是重新编译。为每个编译目标使用单独的缓存。交叉编译发布工件的作业与原生编译的作业arm64产生的工件不同x86_64,因此共享缓存永远不会匹配。

在缓存密钥中包含编译设置

Cargo在指纹codegen-units中包含诸如opt-level和之类的设置,用于决定是否可以重复使用已编译的工件。如果您在不更改缓存密钥的情况下更改工作区Cargo.toml文件的[profile.release]部分,则缓存会恢复,但无论如何都会重新编译每个板条箱。在缓存密钥中加入工作空间Cargo.toml文件的哈希值,这样更改配置文件设置就会启动新的缓存。

提交你的Cargo.lock文件

Lambda 函数是可执行文件,因此请提交您的文件。Cargo.lock这为你提供了可重现的版本和稳定的缓存密钥,只有当你的依赖关系发生变化时,缓存密钥才会改变。

调整发布配置文件以了解构建时间和冷启动

你的函数代码在每次运行时都会被重新编译,因为它比依赖关系更频繁地更改。默认版本配置文件针对运行时吞吐量进行了优化,而许多 Lambda 函数不需要这些吞吐量。优化大小会生成更小的二进制文件,这也有助于缩短冷启动时间,而增加代码生成单元的数量可以增加编译过程中的并行性。禁用链接时间优化 (lto),因为它会使编译速度变慢。将以下内容添加到您的工作空间Cargo.toml文件中:

[profile.release] opt-level = "s" codegen-units = 256 lto = false strip = true

衡量对您自己的应用程序的影响。这些设置会用少量的运行时性能来换取构建时间和二进制文件大小。

避免重复的工作流程运行

在两者上运行的工作流程push和pull_request事件都会为同一个提交运行两次。 GitHub Actions缓存的作用域由分支和拉取请求确定,因此两次运行都写入不同的缓存作用域,并且都不会重复使用对方的缓存。使用在 head commit上键入的并发组,这样每次提交只有一次运行才能构建。

以下工作流程为其构建 Rust Lambda 函数Cargo的工作区arm64,并应用了上述实践:

name: Build on: push: branches: [main] pull_request: # Collapse the push and pull_request runs for the same commit into a single run. concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.head.sha || github.sha }} cancel-in-progress: true jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable with: targets: aarch64-unknown-linux-gnu # Cache the Cargo registry and the workspace target directory. The key covers # the compilation target, Cargo.lock, and the workspace Cargo.toml, so that # changing a dependency or a release profile setting starts a new cache # instead of restoring one whose artifacts Cargo discards. - uses: actions/cache@v4 with: path: | ~/.cargo/registry/index ~/.cargo/registry/cache ~/.cargo/git/db target key: cargo-arm64-${{ hashFiles('Cargo.lock', 'Cargo.toml') }} restore-keys: | cargo-arm64- - name: Install build tools run: pip install cargo-lambda 'aws-sam-cli>=1.165.0' - name: Build run: sam build

当密钥不完全匹配时,该restore-keys条目允许从最新的缓存开始运行,因此依赖关系更改会重复使用未更改的板条箱,而不是重新编译所有内容。