

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 在 Cargo Lambda中使用 建置 Rust Lambda 函數 AWS SAM
<a name="building-rust"></a>

使用 AWS Serverless Application Model 命令列界面 (AWS SAM CLI) 搭配 Rust AWS Lambda 函數。

**Topics**
+ [先決條件](#building-rust-prerequisites)
+ [設定 AWS SAM 搭配 Rust Lambda 函數使用](#building-rust-configure)
+ [範例](#building-rust-examples)
+ [在 中最佳化 Rust 建置 GitHub Actions](#building-rust-optimize-ci)

## 先決條件
<a name="building-rust-prerequisites"></a>

**Rust 語言**  
若要安裝 Rust，請參閱在*Rust語言網站*中[安裝 Rust](https://www.rust-lang.org/tools/install) 。

**Cargo Lambda**  
 AWS SAM CLI 需要安裝 [Cargo Lambda](https://www.cargo-lambda.info/guide/what-is-cargo-lambda.html)，這是 的子命令Cargo。如需安裝說明，請參閱 *Cargo Lambda 文件*中的[安裝](https://www.cargo-lambda.info/guide/installation.html)。

**Docker**  
建置和測試 Rust Lambda 函數需要 Docker。如需安裝指示，請參閱[安裝 Docker](install-docker.md)。

## 設定 AWS SAM 搭配 Rust Lambda 函數使用
<a name="building-rust-configure"></a>

### 步驟 1：設定您的 AWS SAM 範本
<a name="building-rust-configure-template"></a>

使用下列項目設定您的 AWS SAM 範本：
+ **二進位** – 選用。指定單一Cargo套件何時定義多個二進位檔，以識別要為此函數建置的二進位檔。當每個函數都是自己的Cargo套件時，例如在Cargo工作區中，您不需要此屬性。
+ **BuildMethod** – `rust-cargolambda`。
+ **CodeUri** – `Cargo.toml` 檔案的路徑。
+ **處理常**式 – `bootstrap`。
+ **執行時間** – `provided.al2023`。

若要進一步了解自訂執行期，請參閱《 *AWS Lambda 開發人員指南*》中的[自訂 AWS Lambda 執行期](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html)。

以下是已設定 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：搭配 Rust Lambda 函數使用 AWS SAM CLI
<a name="building-rust-configure-cli"></a>

將任何 AWS SAM CLI命令與 AWS SAM 範本搭配使用。如需詳細資訊，請參閱[AWS SAM CLI](using-sam-cli.md)。

## 範例
<a name="building-rust-examples"></a>

### Hello World 範例
<a name="building-rust-examples-hello"></a>

**在此範例中，我們使用 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
...
```

由於我們在此範例中`arm64`將架構從 修改`x86_64`為 ，因此我們執行 `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 函數專案
<a name="building-rust-examples-single"></a>

**以下是包含一個 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 函數專案
<a name="building-rust-examples-multiple"></a>

**以下是無伺服器應用程式的範例，其中包含多個 Rust Lambda 函數，組織為Cargo工作區。**

對於具有多個 Rust Lambda 函數的應用程式，我們建議使用Cargo工作區。每個函數都是自己的套件，因此函數可以在透過程式庫套件共用常見程式碼時宣告獨立相依性。每個套件都會產生以套件命名的單一二進位檔，因此您不需要設定`Binary`建置屬性。

專案目錄結構：

```
.
├── 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 SAM CLI建置到工作區的共用`target`目錄中，因此 會為每個函數Cargo編譯一次共用相依性，而不是一次。此行為需要 AWS SAM CLI 1.165.0 版或更新版本。在舊版上，每個函數都內建在自己的`target`目錄中，並且會針對每個函數重新編譯完整的相依性樹狀結構，這使得在新增函數時建置速度變慢。

為每個函數套件提供一個唯一的二進位名稱。套件名稱在工作區中是唯一的，因此預設的二進位名稱已經是唯一的。如果您使用`[[bin]]`區段覆寫二進位名稱，請勿為兩個套件提供相同的二進位名稱。它們會編譯至共用`target`目錄中的相同路徑，並互相覆寫。當 偵測到此問題時， 會 AWS SAM CLI記錄警告。

或者，單一套件可以定義多個二進位檔。在這種情況下，請使用`Binary`建置屬性來選取每個函數的二進位檔：

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

## 在 中最佳化 Rust 建置 GitHub Actions
<a name="building-rust-optimize-ci"></a>

Rust 建置是運算密集型，而持續整合執行器會從沒有編譯成品開始。具有數個共用大型相依性之函數的應用程式，例如 AWS SDK，可以花費其大部分建置時間來編譯相同的相依性。下列實務可減少 中的建置時間GitHub Actions。

**針對工作區使用 AWS SAM CLI 1.165.0 版或更新版本**  
1.165.0 版和更新版本會將Cargo工作區的每個成員建置到工作區的共用`target`目錄中，因此共用相依性會針對每個組建編譯一次，而不是針對每個函數編譯一次。在安裝 AWS SAM CLI 時指定最低版本，讓組建不會無提示地回復到較慢的行為。

**快取Cargo登錄檔和`target`目錄**  
在執行之間快取Cargo登錄檔 (`~/.cargo/registry` 和 `~/.cargo/git/db`) 和工作區`target`目錄，以便還原不變的相依性，而不是重新編譯。為每個編譯目標使用單獨的快取。跨編譯 發行成品的任務`arm64`會產生與原生編譯 的任務不同的成品`x86_64`，因此共用快取永遠不會相符。

**在快取金鑰中包含建置設定**  
Cargo 包含 `opt-level`和 等設定`codegen-units`，用於決定是否可以重複使用編譯的成品。如果您變更工作區`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快取的範圍依分支和提取請求而定，因此兩者會執行寫入不同的快取範圍，而且不會重複使用另一個快取。使用在前端遞交上鍵控的並行群組，以便只有一個執行會建置每個遞交。

下列工作流程會為 建置 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`項目可讓執行從最新的快取開始，因此相依性變更會重複使用未變更的木箱，而不是再次編譯所有項目。