AWS CloudFormation
用户指南 (API 版本 2010-05-15)

使用 AWS CloudFormation 宏对模板执行自定义处理

通过使用宏,您可以对模板执行自定义处理,包括查找并替换操作等简单操作以及整个模板的大型转换。

要了解可能性的广度,请考虑 AWS::IncludeAWS::Serverless 转换,它们是由 AWS CloudFormation 托管的宏:

  • AWS::Include 转换 可让您将样板文件模板代码段插入您的模板中。

  • AWS::Serverless 转换 获取用 AWS Serverless Application Model (AWS SAM) 语法编写的整个模板,并将其转换并扩展为兼容的 AWS CloudFormation 模板。(有关无服务器应用程序和 AWS SAM 的更多信息,请参阅AWS Lambda Developer Guide中的部署基于 Lambda 的应用程序。)

AWS CloudFormation 宏的工作原理

使用宏处理模板有两个主要步骤:创建宏本身,然后使用宏来对模板执行处理。

要创建宏定义,您需要创建以下内容:

  • 一个执行模板处理的 AWS Lambda 函数。此 Lambda 函数接受一个代码段或整个模板,以及您定义的任何其他参数。它返回已处理的模板代码段或整个模板作为响应。

  • 类型为 AWS::CloudFormation::Macro 的资源,它能让用户从 AWS CloudFormation 模板内调用 Lambda 函数。此资源指定要为此宏调用的 Lambda函数的 ARN,以及辅助调试的其他可选属性。要在账户中创建此资源,请创建一个堆栈模板,其中包含 AWS::CloudFormation::Macro 资源,然后从模板创建堆栈。

要使用宏,请在您的模板中引用宏:

  • 要处理模板的一个部分或代码段,请在 Fn::Transform 函数中引用宏(位置是相对于要转换的模板内容而言的)。当使用 Fn::Transform 时,您还可以传递它需要的任何指定参数。

  • 要处理整个模板,请在模板的 转换 部分中引用宏。

接下来,您通常会创建一个更改集,然后执行它。(处理宏可添加您可能不知道的多个资源。为确保您已了解宏所引入的所有更改,我们强烈建议您使用更改集。AWS CloudFormation 将指定的模板内容以及任何其他指定的参数一并传递给宏资源中指定的 Lambda 函数。Lambda 函数返回已处理的模板内容,无论是代码段还是整个模板。

在调用模板中的所有宏之后,AWS CloudFormation 会生成包含已处理模板内容的更改集。检查更改集后,执行它来应用更改。


            使用 Fn::Transform 内部函数或模板的 Transform 部分,将模板内容和关联参数传递给宏的底层 Lamdba 函数,该函数返回处理的模板内容。

注意

如果您喜欢直接从处理的模板来创建或更新堆栈,则无需先查看更改集中提议的更改,而是可以在 CreateStackUpdateStack 请求期间指定 CAPABILITY_AUTO_EXPAND 功能来直接实现。仅当您知道宏在处理什么时,才应直接从包含宏的堆栈模板创建堆栈。

此外,更改集目前不支持嵌套堆栈。如果您要从包含宏和嵌套堆栈的堆栈模板创建堆栈,则必须使用该功能直接从模板创建堆栈。

有关更多信息,请参阅 AWS CloudFormation API Reference 中的 CreateStackUpdateStack

创建 AWS CloudFormation 宏定义

当您创建宏定义时,该宏定义使底层 Lambda 函数在指定的账户中可用,以便 AWS CloudFormation 可以调用它来处理模板。

AWS CloudFormation 宏函数接口

对于宏,AWS CloudFormation 使用以下事件映射调用底层& Lambda 函数。AWS CloudFormation 以 JSON 格式发送请求,并且它希望函数响应也被格式化为 JSON。

{ "region" : "us-east-1", "accountId" : "$ACCOUNT_ID", "fragment" : { ... }, "transformId" : "$TRANSFORM_ID", "params" : { ... }, "requestId" : "$REQUEST_ID", "templateParameterValues" : { ... } }
  • 区域

    宏所在的区域。

  • accountId

    宏从中调用 Lambda 函数的账户的账户 ID。

  • fragment

    可用于自定义处理的模板内容,采用 JSON 格式。

    • 对于 Transform 模板部分中包含的宏,这是整个模板,除 Transform 部分外。

    • 对于在 Fn::Transform 内部函数调用中包含的宏,这包括基于内部函数在模板中的位置的所有同级节点(及其子节点),除 Fn::Transform 函数外。有关更多信息,请参阅 AWS CloudFormation 宏范围

  • transformId

    调用此函数的宏的名称。

  • params

    对于 Fn::Transform 函数调用,是函数的任何指定参数。AWS CloudFormation 在将这些参数传递给函数之前不会对它们进行评估。

    对于在 Transform 模板部分中包含的宏,此部分为空。

  • requestId

    调用此函数的请求的 ID。

  • templateParameterValues

    在模板的 参数 部分中指定的任何参数。AWS CloudFormation 在将这些参数传递给函数之前对其进行评估。

AWS CloudFormation 预计底层函数以以下 JSON 格式返回响应:

{ "requestId" : "$REQUEST_ID", "status" : "$STATUS", "fragment" : { ... } }
  • requestId

    调用此函数的请求的 ID。这必须在调用函数时与 AWS CloudFormation 提供的请求 ID 匹配。

  • status

    请求的状态(不区分大小写)。应设置为“成功”。AWS CloudFormation 会将任何其他响应都视为失败。

  • fragment

    要在已处理模板中包含的已处理 AWS CloudFormation 模板内容,包括同级内容。AWS CloudFormation 会将传递给 Lambda 函数的模板内容替换为它在 Lambda 响应中接收的模板片段。

    已处理模板内容必须是有效的 JSON,并且其在已处理模板中的包含必须生成有效的模板。

    如果您的函数实际上没有更改 AWS CloudFormation 传递给它的模板内容,但您仍需要将该内容包含在已处理模板中,则您的函数需要将该模板内容返回到其响应中的 AWS CloudFormation。

有关在创建宏时的其他注意事项的信息,请参阅创建 AWS CloudFormation 宏定义时的注意事项

AWS CloudFormation 宏账户范围和权限

您只能在创建宏的账户中将宏用作资源。宏的名称在给定账户中必须是唯一的。但是,您可以通过在底层 Lambda 函数上启用跨账户访问,然后创建宏定义以在多个账户中引用该函数,从而在多个账户中提供相同的功能。在下面的示例中,三个账户包含宏定义,每个宏定义都指向相同的 Lambda 函数。


                    通过允许对 Lambda 函数进行跨账户访问,AWS 能让您在引用该函数的多个账户中创建宏。

有关更多信息,请参阅AWS Lambda Developer Guide中的管理您的 AWS Lambda 资源的访问权限概述

要创建宏定义,用户必须具有在指定账户中创建堆栈的权限。

为了使 AWS CloudFormation 成功运行模板中包含的宏,用户必须对底层 Lambda 函数具有 Invoke 权限。为了防止可能的权限升级,AWS CloudFormation 会在运行宏时模拟用户。有关更多信息,请参阅AWS Lambda Developer Guide中的 Lambda 权限模型IAM 用户指南中的 AWS Lambda 的操作和条件上下文键

AWS::Serverless 转换AWS::Include 转换 转换是由 AWS CloudFormation 托管的宏。使用它们不需要特殊权限,并且可以从 AWS CloudFormation 内的任何账户中获得它们。

调试 AWS CloudFormation 宏

为了帮助调试,您还可以在为宏创建 AWS::CloudFormation::Macro 资源类型时指定 LogGroupNameLogRoleArn 属性。通过这些属性,您可以 AWS CloudFormation 在调用宏的底层 AWS Lambda 函数时向其发送错误日志记录信息的指定 CloudWatch 日志组,以及 AWS CloudFormation 在将日志条目发送到这些日志时应该担任的角色。

账单

当宏运行时,将对 Lambda 函数的所有者收取与执行该函数相关的任何费用。

AWS::Serverless 转换AWS::Include 转换 转换是由 AWS CloudFormation 托管的宏。使用它们不产生任何费用。

创建 AWS CloudFormation 宏定义时的注意事项

在创建宏定义时,请记住以下几点:

  • 只有在提供 AWS Lambda 的区域才支持宏。有关提供 Lambda 的区域的列表,请参阅http://docs.aws.amazon.com/general/latest/gr/rande.html#lambda_region

  • 任何已处理模板代码段都必须是有效的 JSON。

  • 任何已处理模板代码段都必须通过创建堆栈或更新堆栈等操作的验证检查。

  • AWS CloudFormation 先解析宏,然后再处理模板。生成的模板必须是有效的 JSON,并且不得超出模板大小限制。

  • 使用更新回滚功能时,AWS CloudFormation 会使用原始模板的副本。即使包含的代码段发生更改,它也会回滚到原始模板。

  • 在宏中包含宏是行不通的,因为我们不迭代处理宏。

  • 目前在宏中不支持 Fn::ImportValue 内部函数。

  • 模板中包含的内部函数会在任何宏之后被评估。因此,宏返回的已处理模板内容可以包括对内部函数的调用,并且像往常一样对其进行评估。

  • 堆栈集中不支持 AWS CloudFormation 宏。

  • 目前,更改集不支持嵌套堆栈。如果要使用包含宏嵌套堆栈的堆栈模板创建或更新堆栈,您必须直接创建或更新堆栈。为此,请使用 CreateStackUpdateStack 操作并指定 CAPABILITY_AUTO_EXPAND 功能。

创建 AWS CloudFormation 宏定义

  1. 构建一个 AWS Lambda 函数,用于处理 AWS CloudFormation 模板。

    您构建的 Lambda 函数执行模板内容的处理。您的函数可以处理模板的任何部分,甚至是整个模板。有关函数必须遵循的事件映射的信息,请参阅AWS CloudFormation 宏函数接口。有关在创建宏时的其他注意事项的信息,请参阅创建 AWS CloudFormation 宏定义时的注意事项

  2. 创建一个模板,其中包含 AWS::CloudFormation::Macro 资源类型。

    • 您必须指定 NameFunctionName 属性。FunctionName 属性指定在 AWS CloudFormation 运行宏时调用的 Lambda 函数的 ARN。

    • 为了帮助调试,您还可以指定 LogGroupNameLogRoleArn 属性。

  3. 从模板创建一个堆栈,其中包含所需账户中的宏。

    在 AWS CloudFormation 成功创建包含宏定义的堆栈之后,该宏便在该账户中可用。

在模板中使用 AWS CloudFormation 宏

在 AWS CloudFormation 成功创建包含宏定义的堆栈之后,该宏便在该账户中可用。您可以通过在堆栈模板中,在与要处理的模板内容相关的适当位置引用宏来使用宏。

AWS CloudFormation 宏评估顺序

您可以在给定模板中引用多个宏,包括由 AWS CloudFormation 托管的转换,例如 AWS::Include 转换AWS::Serverless 转换

将会根据宏在模板中的位置,从嵌套最深的宏向外直到最一般的宏,按顺序评估宏。对于模板中相同位置的宏,将会根据列出的顺序按顺序进行评估。

诸如 AWS::IncludeAWS::Transform 之类的转换在操作顺序和范围方面被视为与任何其他宏相同。

例如,在下面的模板示例中,AWS CloudFormation 首先评估 PolicyAdder 宏,因为它是模板中嵌套最深的宏。然后,AWS CloudFormation 在评估 AWS::Serverless 之前评估 MyMacro,因为它在 Transform 部分中在 AWS::Serverless 之前列出。

AWSTemplateFormatVersion: 2010-09-09 Transform: [MyMacro, AWS::Serverless] Resources: WaitCondition: Type: AWS::CloudFormation::WaitCondition MyBucket: Type: 'AWS::S3::Bucket' Properties: BucketName: MyBucket Tags: [{"key":"value"}] 'Fn::Transform': - Name: PolicyAdder CorsConfiguration:[] MyEc2Instance: Type: 'AWS::EC2::Instance' Properties: ImageID: "ami-123"

AWS CloudFormation 宏范围

在模板的 Transform 部分中引用的宏可以处理该模板的全部内容。

Fn::Transform 函数中引用的宏可以处理模板中该 Fn::Transform 函数的任何同级元素(包括子元素)的内容。

例如,在下面的模板示例中,AWS::Include 可以根据可以根据包含它的 Fn::Transform 函数的位置处理所有 MyBucket 属性。MyMacro 可以处理整个模板的内容,因为它包含在 Transform 部分中。

// Start of processable content for MyMacro AWSTemplateFormatVersion: 2010-09-09 Transform: [MyMacro] Resources: WaitCondition: Type: AWS::CloudFormation::WaitCondition MyBucket: Type: 'AWS::S3::Bucket' //Start of processable content for AWS::Include Properties: BucketName: MyBucket Tags: [{"key":"value"}] 'Fn::Transform': - Name: 'AWS::Include' Parameters: Location: s3://MyAmazonS3BucketName/MyFileName.yaml CorsConfiguration:[] //End of processable content for AWS::Include MyEc2Instance: Type: 'AWS::EC2::Instance' Properties: ImageID: "ami-123" // End of processable content for MyMacro

更改集和 AWS CloudFormation 宏

要使用引用宏的模板创建或更新堆栈,通常需要创建一个更改集,然后执行它。更改集描述 CloudFormation 将基于处理后的模板执行的操作。处理宏可添加您可能不知道的多个资源。为确保您已了解宏所引入的所有更改,我们强烈建议您使用更改集。在查看更改集后,您可以执行它来实际应用更改。

宏可以将 IAM 资源添加到您的模板中。对于这些资源,AWS CloudFormation 要求您确认其功能。由于 AWS CloudFormation 无法在处理模板前了解所添加的资源,因此您可能需要在创建更改集时确认 IAM 功能,具体取决于引用的宏是否包含 IAM 资源。这样一来,当您运行更改集时,AWS CloudFormation 会具有创建 IAM 资源所需的功能。

注意

如果您喜欢直接从处理的模板来创建或更新堆栈,则无需先查看更改集中提议的更改,而是可以在 CreateStackUpdateStack 请求期间指定 CAPABILITY_AUTO_EXPAND 功能来直接实现。仅当您知道宏在处理什么时,才应直接从包含宏的堆栈模板创建堆栈。

此外,更改集目前不支持嵌套堆栈。如果您要从包含宏和嵌套堆栈的堆栈模板创建堆栈,则必须使用该功能直接从模板创建堆栈。

有关更多信息,请参阅 AWS CloudFormation API Reference 中的 CreateStackUpdateStack

如果您使用 AWS CLI,则可使用 packagedeploy 命令减少从引用宏的模板启动堆栈的步骤数。有关更多信息,请参阅AWS Lambda Developer Guide中的部署基于 Lambda 的应用程序

模板阶段和 CloudFormation 宏

模板的阶段指示模板是原始用户提交的模板还是 AWS CloudFormation 已在其中处理宏的模板。

  • Original:用户最初提交的用于创建或更新堆栈的模板。

  • Processed:AWS CloudFormation 用于在处理任何引用的宏之后创建或更新堆栈的模板。即使原始模板格式化为 YAML,已处理模板也会格式化为 JSON。

使用处理后的模板可解决堆栈问题。如果模板不引用宏,则原始模板和已处理模板是相同的。

您可以使用 AWS CloudFormation 控制台AWS CLI 查看堆栈模板的阶段。

注意

当处理的堆栈模板直接传递到 CreateStackUpdateStackValidateTemplate 请求时,其最大大小为 51,200 字节,而当使用 Amazon S3 模板 URL 作为 S3 对象传递时,则为 460,800 字节。但是,在处理期间,CloudFormation 会更新模板的临时状态,因为它连续处理模板中包含的宏。因此,在处理期间,模板的大小可能会临时超出完全处理的模板所允许的大小。CloudFormation 允许为这些处理中的模板留出一些缓冲。但是,在设计模板和宏时,要始终考虑处理的堆栈模板所允许的最大大小。

如果在处理模板期间 CloudFormation 返回一个 Transformation data limit exceeded 错误,则说明您的模板超出了 CloudFormation 所允许的处理期间模板的最大大小。

要解决这一问题,可执行下列操作:

  • 将您的模板分成多个模板,以避免超出为处理中的模板规定的最大大小。例如:

  • 减小给定宏返回的模板片段大小。CloudFormation 不会篡改宏返回的片段内容。

在模板中使用 AWS CloudFormation 宏

注意

为了使 AWS CloudFormation 成功运行模板中引用的宏,用户必须对底层 Lambda 函数具有 Invoke 权限。有关更多信息,请参阅AWS Lambda Developer Guide中的管理您的 AWS Lambda 资源的访问权限概述

  1. 在模板中包含对宏的引用。

    • 要处理模板代码段,请在 Fn::Transform 函数中引用宏(位置是相对于要处理的模板内容而言的)。

    • 要处理整个模板,请在模板的 转换 部分中引用宏。

  2. 使用模板创建更改集

  3. 审核并运行更改集

宏示例

除了本指南中的宏示例:创建和使用宏演练之外,您还可以在 GitHub 上的 Amazon Web Services - Labs 存储库的 Macros Examples 部分中找到示例宏,包括源代码和模板。这些示例按“原样”提供,用于教学目的。

另请参阅

AWS::CloudFormation::Macro

转换

Fn::Transform

AWS::Serverless 转换

AWS::Include 转换