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工作空间中,则不需要此属性。

  • BuildMethodrust-cargolambda.

  • CodeUriCargo.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目录中,并且会为每个函数重新编译完整的依赖关系树,这会使您添加函数时构建速度变慢。

为每个函数包指定一个唯一的二进制名称。软件包名称在工作空间中是唯一的,因此默认的二进制名称已经是唯一的。如果你用一个[[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

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

避免重复运行工作流程

对于同一次提交,在两个pushpull_request事件上运行的工作流程会运行两次。GitHub Actions缓存受分支和拉取请求的作用域限制,因此两次运行写入不同的缓存作用域,都不会重复使用对方的缓存。使用以头部提交为键的并发组,这样每次提交只能运行一次。

以下工作流程为 Rust Lambda 函数构建 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条目允许从最新的缓存中开始运行,因此依赖项更改会重复使用未更改的箱子,而不是再次编译所有内容。