演练:查找 Amazon 系统映像 ID - Amazon CloudFormation
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

演练:查找 Amazon 系统映像 ID

声明 Amazon Elastic Compute Cloud(Amazon EC2)实例的 Amazon CloudFormation 模板还必须指定 Amazon 机器映像(AMI)ID,它包含操作系统和其他软件以及用于启动此实例的配置信息。AMI ID 是否正确取决于您在其中启动堆栈的实例类型和区域。ID 可能会定期更改,比如当通过软件更新方式更新 AMI 时。

通常,您可能将 AMI ID 映射到特定实例类型和区域。要更新此 ID,您需要在您的每个模板中手动更改它们。利用自定义资源和 Amazon Lambda(Lambda),您可以创建一个函数,用于获取您正在使用的区域和实例类型的最新 AMI 的 ID,从而使您不必维护映射。

此演练演示如何创建自定义资源并将某个 Lambda 函数与它关联以查找 AMI ID。请注意,本演练假定您已了解如何使用自定义资源和 Lambda。有关更多信息,请参阅 自定义资源 或《Amazon Lambda 开发人员指南》。

演练概述

在此演练中,您将借助自定义资源、Lambda 函数和 EC2 实例来创建一个堆栈。此演练为您提供将用于创建堆栈的示例代码和示例模板。

示例模板使用自定义资源类型调用输入值并将它发送到 Lambda 函数。使用此模板时,Amazon CloudFormation 会调用此函数并向它发送信息,如请求类型、输入数据和预签名 Amazon Simple Storage Service(Amazon S3)URL。该函数使用这些信息来查找 AMI ID,然后向预签名 URL 发送响应。

在 Amazon CloudFormation 获取预签名 URL 位置的响应后,它将继续创建堆栈。Amazon CloudFormation 在创建实例时,会使用 Lambda 函数的响应指定实例的 AMI ID。

下面列出了过程摘要。您需要具有 Amazon Identity and Access Management(IAM)权限才能使用所有相应的服务,例如 Lambda、Amazon EC2 和 Amazon CloudFormation。

注意

Amazon CloudFormation 是一种免费服务;但是,您需要为您在堆栈中使用的 Amazon 资源(如 Lambda 函数和 EC2 实例)付费,费用按每种资源的现价收取。有关 Amazon 定价的详细信息,请参阅 http://aws.amazon.com 上每种产品的详细信息页。

  1. 在 Amazon Simple Storage Service (Amazon S3) 存储桶中保存示例 Lambda 包。

    示例包包含创建 Lambda 函数所需的一切内容。您必须将此包保存到将创建的堆栈所在区域的存储桶中。

  2. 使用示例模板创建堆栈。

    堆栈演示如何将 Lambda 函数与自定义资源关联,以及如何使用该函数的结果指定 AMI ID。此外,该堆栈还创建一个 IAM 角色(执行角色),Lambda 将使用该角色对 Amazon EC2 进行调用。

  3. 删除堆栈。

    删除堆栈以清理您创建的所有堆栈资源,从而避免为不必要的资源付费。

步骤 1:下载和保存 Amazon S3 中的示例包

使用 Lambda 函数创建堆栈时,必须指定包含函数源代码的 Amazon S3 存储桶的位置。存储桶必须位于创建堆栈的同一区域。

此演练提供创建 Lambda 函数所需的示例包(一个 .zip 文件)。Lambda 包包含此函数的源代码和需要的库。就本演练而言,此函数不需要额外的库。

此函数使用实例的架构和区域作为 Amazon CloudFormation 自定义资源请求的输入,将最新 AMI ID 返回到预签名 Amazon S3 URL。

下载和保存 Amazon S3 中的包
  1. 从 Amazon S3 下载示例包。保存文件时,使用示例的文件名 amilookup.zipamilookup-win.zip

  2. https://console.aws.amazon.com/s3/home 处打开 Amazon S3 控制台。

  3. 选择或创建一个存储桶 (位于创建 Amazon CloudFormation 堆栈所在的区域中)。记下存储桶名称。

    您将在此存储桶中保存示例包。有关创建桶的更多信息,请参阅《Amazon Simple Storage Service 用户指南》中的创建桶

  4. 将示例包上传到您选择或创建的存储桶中。

    有关上传对象的更多信息,请参阅《Amazon Simple Storage Service 用户指南》中的上传对象

将此包放入 Amazon S3 中后,您就可以在 Amazon CloudFormation 模板的 Lambda 资源声明中指定它的位置了。下一步演示如何声明此函数并使用自定义资源调用它。此外,您还将了解如何利用此函数的结果指定 EC2 实例的 AMI ID。

步骤 2:创建堆栈

要创建此示例 Amazon EC2 堆栈,您需要使用包含以下内容的示例模板:Lambda 函数、IAM 执行角色、调用此函数的自定义资源、使用此函数结果的 EC2 实例。

在创建堆栈期间,自定义资源将调用 Lambda 函数并等到该函数向预签名 Amazon S3 URL 发送响应。在响应中,该函数返回与 EC2 实例类型和您要在其中创建实例的区域对应的最新 AMI 的 ID。函数的响应数据存储为自定义资源的属性,用于指定 EC2 实例的 AMI ID。

以下代码段介绍示例模板的相关部分,以帮助您了解如何将 Lambda 函数与自定义资源关联以及如何使用该函数的响应。

要查看整个示例模板,请参阅:

堆栈模板代码段

要创建 Lambda 函数,您需要声明 AWS::Lambda::Function 资源,这需要函数的源代码、处理程序名称、运行时环境和执行角色 ARN。

例 JSON 语法
"AMIInfoFunction": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { "S3Bucket": { "Ref": "S3Bucket" }, "S3Key": { "Ref": "S3Key" } }, "Handler": { "Fn::Join" : [ "", [{ "Ref": "ModuleName" },".handler"] ] }, "Runtime": "nodejs18.x", "Timeout": "30", "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] } } }
例 YAML 语法
AMIInfoFunction: Type: AWS::Lambda::Function Properties: Code: S3Bucket: !Ref S3Bucket S3Key: !Ref S3Key Handler: !Sub "${ModuleName}.handler" Runtime: nodejs18.x Timeout: 30 Role: !GetAtt LambdaExecutionRole.Arn

Code 属性指定上传此示例包的 Amazon S3 位置(存储桶名称和文件名)。示例模板使用输入参数 ("Ref": "S3Bucket""Ref": "S3Key") 设置存储桶和文件名,以便在创建堆栈时指定此名称。同样,处理程序名称 (对应于 .zip 包中源文件 (JavaScript 文件) 的名称) 也使用了一个输入参数 ("Ref": "ModuleName")。源文件为 JavaScript 代码,因此运行时指定为 nodejs18.x

就此演练而言,函数的执行时间超出了 3 秒的默认值,因此将超时设置为 30 秒。如果您指定的超时时间不够长,Lambda 可能导致超时,使函数无法完成,从而造成堆栈创建失败。

执行角色 (在模板中的其他位置声明) 通过 Fn::GetAtt 属性中的 Role 内部函数指定。执行角色授予 Lambda 函数向 Amazon 发送日志和调用 EC2 DescribeImages API 的权限。下面的代码段演示授予适当权限的角色和策略:

例 JSON 语法
"LambdaExecutionRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": {"Service": ["lambda.amazonaws.com"]}, "Action": ["sts:AssumeRole"] }] }, "Path": "/", "Policies": [{ "PolicyName": "root", "PolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": ["ec2:DescribeImages"], "Resource": "*" }] } }] } }
例 YAML 语法
LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: "/" Policies: - PolicyName: root PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: arn:aws:logs:*:*:* - Effect: Allow Action: - ec2:DescribeImages Resource: "*"

对于 Linux 和 Windows 模板,自定义资源调用与其关联的 Lambda 函数。要将函数与自定义资源关联,可以使用 Fn::GetAtt 内部函数为 ServiceToken 属性指定函数的 Amazon 资源名称(ARN)。Amazon CloudFormation 将自定义资源声明中包含的其他属性(如 RegionArchitecture)作为输入发送给 Lambda 函数。Lambda 函数为这些输入属性确定正确的名称和值。

例 JSON 语法
"AMIInfo": { "Type": "Custom::AMIInfo", "Properties": { "ServiceToken": { "Fn::GetAtt" : ["AMIInfoFunction", "Arn"] }, "Region": { "Ref": "AWS::Region" }, "Architecture": { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } } }
例 YAML 语法
AMIInfo: Type: Custom::AMIInfo Properties: ServiceToken: !GetAtt AMIInfoFunction.Arn Region: !Ref "AWS::Region" Architecture: Fn::FindInMap: - AWSInstanceType2Arch - !Ref InstanceType - Arch

对于 Windows,自定义资源提供 Windows 版本给 Lambda 函数而不是实例的架构。

例 JSON 语法
"AMIInfo": { "Type": "Custom::AMIInfo", "Properties": { "ServiceToken": { "Fn::GetAtt" : ["AMIInfoFunction", "Arn"] }, "Region": { "Ref": "AWS::Region" }, "OSName": { "Ref": "WindowsVersion" } } }
例 YAML 语法
AMIInfo: Type: Custom::AMIInfo Properties: ServiceToken: !GetAtt AMIInfoFunction.Arn Region: !Ref "AWS::Region" OSName: !Ref "WindowsVersion"

当 Amazon CloudFormation 调用 Lambda 函数时,该函数调用 EC2 DescribeImages API,使用区域和实例架构或操作系统名称来筛选映像的列表。然后,该函数按日期为映像列表排序并返回最新 AMI 的 ID。

在返回最新 AMI 的 ID 时,该函数在响应对象Data 属性中向预签名 URL 发送此 ID。数据将被构造为名称/值对,如以下示例所示:

"Data": { "Id": "ami-43795473" }

以下代码段说明如何从 Lambda 函数获取数据。它使用 Fn::GetAtt 内部函数,提供自定义资源的名称以及您要获取的值的属性名。在此演练中,自定义资源名称是 AMIInfo,属性名称是 Id

例 JSON 语法
"SampleInstance": { "Type": "AWS::EC2::Instance", "Properties": { "InstanceType" : { "Ref" : "InstanceType" }, "ImageId": { "Fn::GetAtt": [ "AMIInfo", "Id" ] } } }
例 YAML 语法
SampleInstance: Type: AWS::EC2::Instance Properties: InstanceType: !Ref InstanceType ImageId: !GetAtt AMIInfo.Id

现在,您已了解模板的功能,请使用示例模板创建一个堆栈。

要创建 堆栈,请执行以下操作:
  1. 打开 Amazon CloudFormation 控制台,地址:https://console.aws.amazon.com/cloudformation/

  2. 选择Create Stack(创建堆栈)。

  3. Template (模板) 部分中,选择 Specify an Amazon S3 template URL (指定 S3 模板 URL),然后复制以下 URL 并粘贴到文本框中:

  4. 选择下一步

  5. Stack name (堆栈名称) 名称字段中,键入 SampleEC2Instance

  6. Parameters 部分,指定您创建的 Amazon S3 存储桶的名称,然后选择 Next

    其他参数的默认值为在示例 .zip 包中使用的相同名称。

  7. 在本演练中,您无需添加标记或指定高级设置,因此请选择 Next

  8. 确保堆栈名称和模板 URL 正确,然后选择 Create

Amazon CloudFormation 可能需要几分钟的时间以创建堆栈。要监控进度,可查看堆栈事件。有关更多信息,请参阅在 Amazon Web Services Management Console上查看 Amazon CloudFormation 堆栈数据和资源

如果堆栈创建成功,堆栈中的所有资源 (如 Lambda 函数、自定义资源和 EC2 实例) 也会一同创建。您成功使用 Lambda 函数和自定义资源指定了 EC2 实例的 AMI ID。在此模板中,您无需创建和维护 AMI ID 映射。

要查看创建 EC2 实例时使用的是哪个 AMI ID Amazon CloudFormation,请查看堆栈输出。

如果 Lambda 函数返回错误,则在 Amazon CloudWatch Logs 控制台中查看此函数的日志。日志流的名称与自定义资源的物理 ID 相同,您可通过查看堆栈的资源来查找该名称。有关更多信息,请参阅《Amazon CloudWatch 用户指南》中的查看日志数据

步骤 3:清理资源

要确保不因任何不必要的服务而产生费用,请删除您的堆栈。

删除堆栈
  1. 从 Amazon CloudFormation 控制台中,选择 SampleEC2Instance 堆栈。

  2. 选择 Actions,然后选择 Delete Stack

  3. 在确认消息中,选择 Yes, Delete

您创建的所有资源都会被删除。

既然您已了解如何通过 Amazon CloudFormation 创建和使用 Lambda 函数,您可以使用本演练中的示例模板和代码生成其他堆栈和函数。

相关信息