

# 在 AWS SAM 和基础设施编辑器中使用 Lambda 函数
<a name="foundation-iac-getting-started"></a>

在本教程中，您可以通过使用现有 Lambda 函数创建 AWS SAM 模板，然后通过添加其他 AWS 资源在基础设施编辑器中构建无服务器应用程序，从而开始将 IaC 与 Lambda 结合使用。

在学习本教程时，您将学习一些基本概念，例如如何在 AWS SAM 中指定 AWS 资源。您还将了解如何使用基础设施编辑器来构建可使用 AWS SAM 或 CloudFormation 部署的无服务器应用程序。

要完成本教程，请执行以下步骤：
+ 创建示例 Lambda 函数
+ 使用 Lambda 控制台查看函数的 AWS SAM 模板
+ 将函数的配置导出到 AWS 基础架构编辑器 并根据函数的配置设计一个简单的无服务器应用程序
+ 保存更新后的 AWS SAM 模板，可作为部署无服务器应用程序的基础

## 先决条件
<a name="foundation-iac-prerequisites"></a>

在本教程中，您将使用基础设施编辑器的[本地同步](https://docs.aws.amazon.com/application-composer/latest/dg/reference-features-local-sync.html)功能，将模板和代码文件保存到本地生成计算机。要使用此功能，您需要一个支持文件系统访问 API 的浏览器，它允许 Web 应用程序在本地文件系统中读取、写入和保存文件。我们建议使用 Google Chrome 或 Microsoft Edge。有关文件系统访问 API 的更多信息，请参阅 [What is the File System Access API?](https://docs.aws.amazon.com/application-composer/latest/dg/reference-fsa.html#reference-fsa-api)

## 创建 Lambda 函数
<a name="foundation-iac-create-function"></a>

在第一步中，您会创建 Lambda 函数以用于完成本教程的其余部分。为了简单起见，您可以使用 Lambda 控制台通过 Python 3.11 运行时系统创建基本的“Hello world”函数。

**使用控制台创建“Hello world”Lambda 函数**

1. 打开 [Lambda 控制台](https://console.aws.amazon.com/lambda)。

1. 选择 **Create function**（创建函数）。

1. 选择**从头开始创作**，然后在**基本信息**中输入 **LambdaIaCDemo** 作为**函数名称**。

1. 对于**运行时系统**，选择 **Python 3.11**。

1. 选择**创建函数**。

## 查看函数的 AWS SAM 模板
<a name="foundation-iac-view-template"></a>

在将函数配置导出到基础设施编辑器之前，请使用 Lambda 控制台将函数的当前配置作为 AWS SAM 模板查看。按照本节中的步骤操作，您将了解 AWS SAM 模板的剖析以及如何定义诸如 Lambda 函数之类的资源以开始指定无服务器应用程序。

**查看函数的 AWS SAM 模板**

1. 打开 Lamba 控制台的[函数页面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 选择您刚刚创建的函数（`LambdaIaCDemo`）。

1. 在**函数概述**窗格中，选择**模板**。

   您将看到的不是表示函数配置的图表，而是函数的 AWS SAM 模板。该模板应该如下所示。

   ```
   # This AWS SAM template has been generated from your function's 
   # configuration. If your function has one or more triggers, note 
   # that the AWS resources associated with these triggers aren't fully 
   # specified in this template and include placeholder values.Open this template 
   # in AWS Application Composer or your favorite IDE and modify 
   # it to specify a serverless application with other AWS resources. 
   AWSTemplateFormatVersion: '2010-09-09'
   Transform: AWS::Serverless-2016-10-31
   Description: An AWS Serverless Specification template describing your function.
   Resources:
     LambdaIaCDemo:
       Type: AWS::Serverless::Function
       Properties:
         CodeUri: .
         Description: ''
         MemorySize: 128
         Timeout: 3
         Handler: lambda_function.lambda_handler
         Runtime: python3.11
         Architectures:
           - x86_64
         EventInvokeConfig:
           MaximumEventAgeInSeconds: 21600
           MaximumRetryAttempts: 2
         EphemeralStorage:
           Size: 512
         RuntimeManagementConfig:
           UpdateRuntimeOn: Auto
         SnapStart:
           ApplyOn: None
         PackageType: Zip
         Policies:
           Statement:
             - Effect: Allow
               Action:
                 - logs:CreateLogGroup
               Resource: arn:aws:logs:us-east-1:123456789012:*
             - Effect: Allow
               Action:
                 - logs:CreateLogStream
                 - logs:PutLogEvents
               Resource:
                 - >-
                   arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/LambdaIaCDemo:*
   ```

我们需要花些时间查看函数的 YAML 模板并理解一些关键概念。

模板以声明 `Transform: AWS::Serverless-2016-10-31` 开头。此声明是必需的，因为 AWS SAM 模板在幕后要通过 CloudFormation 部署。使用 `Transform` 语句将模板标识为 AWS SAM 模板文件。

`Transform` 声明之后是 `Resources` 部分。在这里可以定义要使用 AWS SAM 模板部署的 AWS 资源。AWS SAM 模板可以包含 AWS SAM 资源和 CloudFormation 资源的组合。这是因为在部署过程中，AWS SAM 模板会扩展为 CloudFormation 模板，因此任何有效的 CloudFormation 语法都可以添加到 AWS SAM 模板中。

目前，模板的 `Resources` 部分中只定义了一个资源，即您的 Lambda 函数 `LambdaIaCDemo`。要向 AWS SAM 模板添加 Lambda 函数，请使用 `AWS::Serverless::Function` 资源类型。Lambda 函数资源的 `Properties` 定义函数的运行时系统、函数处理程序和其他配置选项。此处还定义了 AWS SAM 应该用于部署函数的函数源代码的路径。要了解有关 AWS SAM 中Lambda 函数资源的更多信息，请参阅*《AWS SAM 开发人员指南》*中的 [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)。

除了函数属性和配置外，该模板还指定了函数的 AWS Identity and Access Management（IAM）policy。此策略授予函数向 Amazon CloudWatch Logs 写入日志的权限。当您在 Lambda 控制台中创建函数时，Lambda 会自动将此策略附加到您的函数。要了解有关为 AWS SAM 模板中的函数指定 IAM policy 的更多信息，请参阅 *AWS SAM 开发者指南*中 [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html) 页面上的 `policies` 属性。

要了解有关 AWS SAM 模板结构的更多信息，请参阅[AWS SAM 模板剖析](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy.html)。

## 使用 AWS 基础架构编辑器 设计无服务器应用程序
<a name="foundation-iac-design-app"></a>

要从函数的 AWS SAM 模板开始构建简单的无服务器应用程序，您可以将函数配置导出到基础设施编辑器，并激活基础设施编辑器的本地同步模式。本地同步会自动将您的函数代码和 AWS SAM 模板保存到本地生成计算机，并在您在基础设施编辑器中添加其他 AWS 资源时让保存的模板保持同步。

**将函数导出到基础设施编辑器**

1. 在**函数概述**窗格中，选择**导出到应用程序编辑器**。

   为了将函数的配置和代码导出到基础设施编辑器，Lambda 在您的账户中创建了一个 Amazon S3 存储桶来临时存储此数据。

1. 在对话框中，选择**确认并创建项目**以接受此存储桶的默认名称，并将函数的配置和代码导出到基础设施编辑器。

1. （可选）要为 Lambda 创建的 Amazon S3 存储桶选择其他名称，请输入新名称并选择**确认并创建项目**。Amazon S3 存储桶的名称必须全局唯一，并遵守[存储桶命名规则](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)。

   选择**确认并创建项目**，将打开基础设施编辑器控制台。在*画布*上，您将看到 Lambda 函数。

1. 从**菜单**下拉列表中，选择**激活本地同步**。

1. 在打开的对话框中选择**选择文件夹**，然后在本地生成计算机上选择一个文件夹。

1. 选择**激活**以激活本地同步。

要将函数导出到基础设施编辑器，您需要拥有使用特定 API 操作的权限。如果您无法导出函数，请查看 [所需的权限](services-appcomposer.md#services-appcomposer-permissions) 并确保您拥有所需的权限。

**注意**  
标准 [Amazon S3 定价](https://aws.amazon.com/s3/pricing)适用于您将函数导出到基础设施编辑器时由 Lambda 创建的存储桶。由 Lambda 放入存储桶的对象会在 10 天后自动删除，但是 Lambda 不会删除存储桶本身。  
为避免给您的 AWS 账户 增加额外费用，请在将函数导出到基础设施编辑器后，按照[删除存储桶](https://docs.aws.amazon.com/AmazonS3/latest/userguide/delete-bucket.html)中的说明进行操作。有关 Lambda 创建的 Amazon S3 存储桶的更多信息，请参阅 [配合使用 AWS Lambda和 AWS 基础架构编辑器](services-appcomposer.md)。

**在基础设施编辑器中设计您的无服务器应用程序**

激活本地同步后，您在基础设施编辑器中所做的更改将反映在本地生成计算机上保存的 AWS SAM 模板中。现在，您可以将其他 AWS 资源拖放到基础设施编辑器画布上来构建应用程序。在此示例中，您添加了一个 Amazon SQS 简单队列作为 Lambda 函数的触发器，并添加了一个 DynamoDB 表供该函数写入数据。

1. 通过执行以下操作，将 Amazon SQS 触发器添加到 Lambda 函数：

   1. 在**资源**选项板的搜索字段中输入 **SQS**。

   1. 将 **SQS 队列**资源拖到画布上，然后将其放置在 Lambda 函数的左侧。

   1. 选择**详细信息**，然后在**逻辑 ID** 中输入 **LambdaIaCQueue**。

   1. 选择**保存**。

   1. 单击 SQS 队列卡上的**订阅**端口，然后将其拖到 Lambda 函数卡上的左侧端口，即可连接您的 Amazon SQS 和 Lambda 资源。两个资源之间出现一条线，表示连接成功。基础设施编辑器还会在画布底部显示一条消息，表明两个资源已连接成功。

1. 通过执行以下操作，为您的 Lambda 函数添加一个 Amazon DynamoDB 表，供其写入数据：

   1. 在**资源**选项板的搜索字段中输入 **DynamoDB**。

   1. 将 **DynamoDB 表**资源拖到画布上，然后将其放置在 Lambda 函数的右侧。

   1. 选择**详细信息**，然后在**逻辑 ID** 中输入 **LambdaIaCTable**。

   1. 选择**保存**。

   1. 单击 Lambda 函数卡的右侧端口，然后将其拖动到 DynamoDB 卡的左侧端口，即可将 DynamoDB 表连接到您的 Lambda 函数。

现在，您已经添加了这些额外资源，让我们看看基础设施编辑器创建的更新后的 AWS SAM 模板。

**查看更新后的 AWS SAM 模板**
+ 在基础设施编辑器画布上，选择**模板**以从画布视图切换到模板视图。

现在，您的 AWS SAM 模板应包含以下额外资源和属性：
+ 具有标识​符 `LambdaIaCQueue` 的 Amazon SQS 队列

  ```
  LambdaIaCQueue:
      Type: AWS::SQS::Queue
      Properties:
        MessageRetentionPeriod: 345600
  ```

  使用基础设施编辑器添加 Amazon SQS 队列时，基础设施编辑器会设置 `MessageRetentionPeriod` 属性。您也可以通过在 SQS 队列卡上选择**详细信息**并选中或取消选中 **Fifo 队列**来设置 `FifoQueue` 属性。

  要为队列设置其他属性，您可以手动编辑模板以添加这些属性。要了解有关 `AWS::SQS::Queue` 资源及其可用属性的更多信息，请参阅*《CloudFormation 用户指南》*中的 [AWS:: SQS::Queue](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sqs-queue.html)。
+ Lambda 函数定义中的一个 `Events` 属性，用于将 Amazon SQS 队列指定为函数的触发器

  ```
  Events:
    LambdaIaCQueue:
      Type: SQS
      Properties:
        Queue: !GetAtt LambdaIaCQueue.Arn
        BatchSize: 1
  ```

  `Events` 属性由一个事件类型和一组取决于类型的属性组成。要了解您可以配置用于触发 Lambda 函数的不同 AWS 服务 以及可以设置的属性，请参阅 *AWS SAM 开发者指南*中的 [EventSource](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-eventsource.html)。
+ 带有标识符 `LambdaIaCTable` 的 DynamoDB 表

  ```
  LambdaIaCTable:
      Type: AWS::DynamoDB::Table
      Properties:
        AttributeDefinitions:
          - AttributeName: id
            AttributeType: S
        BillingMode: PAY_PER_REQUEST
        KeySchema:
          - AttributeName: id
            KeyType: HASH
        StreamSpecification:
          StreamViewType: NEW_AND_OLD_IMAGES
  ```

  使用基础设施编辑器添加 DynamoDB 表时，可以通过在 DynamoDB 表卡上选择**详细信息**并编辑键值来设置表的键。基础设施编辑器还为许多其他属性设置默认值，包括 `BillingMode` 和 `StreamViewType`。

  要详细了解这些属性以及可以添加到 AWS SAM 模板中的其他属性，请参阅*《CloudFormation 用户指南》*中的 [AWS::DynamoDB::Table](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-table.html)。
+ 一项新的 IAM policy，允许您的函数对您添加的 DynamoDB 表执行 CRUD 操作。

  ```
  Policies:
  ...
    - DynamoDBCrudPolicy:
      TableName: !Ref LambdaIaCTable
  ```

最终的 AWS SAM 模板应该如下所示。

```
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: An AWS Serverless Specification template describing your function.
Resources:
  LambdaIaCDemo:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: .
      Description: ''
      MemorySize: 128
      Timeout: 3
      Handler: lambda_function.lambda_handler
      Runtime: python3.11
      Architectures:
        - x86_64
      EventInvokeConfig:
        MaximumEventAgeInSeconds: 21600
        MaximumRetryAttempts: 2
      EphemeralStorage:
        Size: 512
      RuntimeManagementConfig:
        UpdateRuntimeOn: Auto
      SnapStart:
        ApplyOn: None
      PackageType: Zip
      Policies:
        - Statement:
            - Effect: Allow
              Action:
                - logs:CreateLogGroup
              Resource: arn:aws:logs:us-east-1:594035263019:*
            - Effect: Allow
              Action:
                - logs:CreateLogStream
                - logs:PutLogEvents
              Resource:
                - arn:aws:logs:us-east-1:594035263019:log-group:/aws/lambda/LambdaIaCDemo:*
        - DynamoDBCrudPolicy:
            TableName: !Ref LambdaIaCTable
      Events:
        LambdaIaCQueue:
          Type: SQS
          Properties:
            Queue: !GetAtt LambdaIaCQueue.Arn
            BatchSize: 1
      Environment:
        Variables:
          LAMBDAIACTABLE_TABLE_NAME: !Ref LambdaIaCTable
          LAMBDAIACTABLE_TABLE_ARN: !GetAtt LambdaIaCTable.Arn
  LambdaIaCQueue:
    Type: AWS::SQS::Queue
    Properties:
      MessageRetentionPeriod: 345600
  LambdaIaCTable:
    Type: AWS::DynamoDB::Table
    Properties:
      AttributeDefinitions:
        - AttributeName: id
          AttributeType: S
      BillingMode: PAY_PER_REQUEST
      KeySchema:
        - AttributeName: id
          KeyType: HASH
      StreamSpecification:
        StreamViewType: NEW_AND_OLD_IMAGES
```

## 使用 AWS SAM（可选）部署您的无服务器应用程序
<a name="foundation-iac-deploy"></a>

如果要使用 AWS SAM 来利用刚刚在基础设施编辑器中创建的模板部署无服务器应用程序，则需要先安装 AWS SAM CLI。为此，请遵循[安装 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) 中的说明。

在部署应用程序之前，您还需要更新基础设施编辑器随模板一起保存的函数代码。目前，基础设施编辑器保存的 `lambda_function.py` 文件仅包含您在创建函数时 Lambda 提供的基本“Hello world”代码。

要更新函数代码，请复制以下代码并将其粘贴到由基础设施编辑器保存到本地生成计算机的 `lambda_function.py` 文件中。激活“本地同步”模式时，您指定了基础设施编辑器要将此文件保存到的目录。

此代码接受的键值对来自您在基础设施编辑器中创建的 Amazon SQS 队列的消息。如果键和值都是字符串，则代码会使用它们向您的模板中定义的 DynamoDB 表写入项目。

### 更新了 Python 函数代码
<a name="foundation-iac-updated-code"></a>

```
import boto3
import os
import json

# define the DynamoDB table that Lambda will connect to
tablename = os.environ['LAMBDAIACTABLE_TABLE_NAME']

# create the DynamoDB resource
dynamo = boto3.client('dynamodb')

def lambda_handler(event, context):
    # get the message out of the SQS event
    message = event['Records'][0]['body']
    data = json.loads(message)
    # write event data to DDB table
    if check_message_format(data):
        key = next(iter(data))
        value = data[key]
        dynamo.put_item(
            TableName=tablename,
            Item={
                'id': {'S': key},
                'Value': {'S': value}
            }
        )
    else:
        raise ValueError("Input data not in the correct format")

# check that the event object contains a single key value  
# pair that can be written to the database
def check_message_format(message):
    if len(message) != 1:
        return False
        
    key, value = next(iter(message.items()))
    
    if not (isinstance(key, str) and isinstance(value, str)):
        return False

    else:
        return True
```

**部署无服务器应用程序**

要使用 AWS SAM CLI 部署应用程序，请执行以下步骤。为了正确构建和部署函数，必须在您的生成计算机和 `PATH` 上安装 Python 3.11 版本。

1. 在基础设施编辑器保存 `template.yaml` 和 `lambda_function.py` 文件的目录运行以下命令。

   ```
   sam build
   ```

   此命令会收集应用程序的构建构件，并将其以适当的格式放置在适当的位置进行部署。

1. 要部署您的应用程序并创建 AWS SAM 模板中指定的 Lambda、Amazon SQS 和 DynamoDB 资源，请运行以下命令。

   ```
   sam deploy --guided
   ```

   使用 `--guided` 标志意味着 AWS SAM 将向您显示提示，以指导您完成部署过程。对于此部署，请按 Enter 接受默认选项。

在部署过程中，AWS SAM 将在 AWS 账户 中创建以下资源：
+ 一个名为 `sam-app` 的 CloudFormation [堆栈](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-whatis-concepts.html#cfn-concepts-stacks)
+ 名称格式为 `sam-app-LambdaIaCDemo-99VXPpYQVv1M` 的 Lambda 函数
+ 名称格式为 `sam-app-LambdaIaCQueue-xL87VeKsGiIo` 的 Amazon SQS 队列
+ 名称格式为 `sam-app-LambdaIaCTable-CN0S66C0VLNV` 的 DynamoDB 表

AWS SAM 还会创建必要的 IAM 角色和策略，以便您的 Lambda 函数可以读取来自 Amazon SQS 队列的消息并对 DynamoDB 表执行 CRUD 操作。

## 测试已部署的应用程序（可选）
<a name="foundation-iac-test"></a>

要确认您的无服务器应用程序已正确部署，请向您的 Amazon SQS 队列发送一条包含密钥值对的消息，并检查 Lambda 是否使用这些值将项目写入您的 DynamoDB 表。

**测试您的无服务器应用程序**

1. 打开 Amazon SQS 控制台的[队列](https://console.aws.amazon.com/sqs/v2/home#/queues)页面，然后选择 AWS SAM 通过您的模板创建的队列。名称的格式为 `sam-app-LambdaIaCQueue-xL87VeKsGiIo`。

1. 选择**发送和接收消息**，然后将以下 JSON 粘贴到**发送消息**部分的**消息正文**中。

   ```
   {
       "myKey": "myValue"
   }
   ```

1. 选择 **Send message**（发送消息）。

   将您的消息发送到队列会导致 Lambda 通过 AWS SAM 模板中定义的事件源映射调用您的函数。要确认 Lambda 已按预期调用您的函数，请确认项目已被添加到您的 DynamoDB 表。

1. 打开 DynamoDB 控制台中的[表](https://console.aws.amazon.com/dynamodbv2#tables)页面，然后选择您的表。名称的格式为 `sam-app-LambdaIaCTable-CN0S66C0VLNV`。

1. 选择 **Explore table items**（浏览表项目）。在**返回的项目**窗格中，您会看到一个带 **id** `myKey` 和**值** `myValue` 的项目。