

# 使用 CloudFormation 模板
<a name="template-guide"></a>

Amazon CloudFormation 模板定义了您要在堆栈中创建、更新或删除的 Amazon 资源。模板由多个部分组成，但唯一必须具备的是 [Resources](resources-section-structure.md) 部分，其中必须至少声明一种资源。

您可以使用以下方法创建模板：
+ **Amazon 基础架构编辑器** – 用于设计模板的可视化界面。
+ **文本编辑器** – 直接使用 JSON 或 YAML 语法编写模板。
+ **IaC 生成器** – 利用您账户中已预置但当前不由 CloudFormation 管理的资源生成模板。IaC 生成器适用于云管控 API 在您所在区域支持的多种资源类型。

本部分提供有关如何使用 CloudFormation 模板的不同部分以及如何开始创建堆栈模板的全面指南。其涵盖以下主题：

**Topics**
+ [

## 模板的存储位置
](#where-they-get-stored)
+ [

## 验证模板
](#template-validation)
+ [

## 开始使用模板
](#getting-started)
+ [

## 示例模板
](#sample-templates)
+ [模板格式](template-formats.md)
+ [模板部分](template-anatomy.md)
+ [基础架构编辑器](infrastructure-composer-for-cloudformation.md)
+ [

# Amazon CloudFormation 语言服务器
](ide-extension.md)
+ [IaC 生成器](generate-IaC.md)
+ [获取存储在其他服务中的值](dynamic-references.md)
+ [获取 Amazon 值](pseudo-parameter-reference.md)
+ [获取堆栈输出](using-cfn-stack-exports.md)
+ [在运行时指定现有资源](cloudformation-supplied-parameter-types.md)
+ [演练](walkthroughs.md)
+ [模板代码段](template-snippets.md)
+ [基于 Windows 的堆栈](cfn-windows-stacks.md)
+ [使用 CloudFormation 提供的资源类型](cloudformation-supplied-resource-types.md)
+ [使用模块创建可重复使用的资源配置](modules.md)

## 模板的存储位置
<a name="where-they-get-stored"></a>

**Amazon S3 存储桶**  
您可以将 CloudFormation 模板存储在 Amazon S3 存储桶中。创建或更新堆栈时，您可以指定模板的 S3 URL，而不是直接上传模板。

如果您通过 Amazon Web Services 管理控制台 或 Amazon CLI 直接上传模板，系统将自动为您创建一个 S3 存储桶。有关更多信息，请参阅 [通过 CloudFormation 控制台创建堆栈](cfn-console-create-stack.md)。

**Git 存储库**  
使用 [Git sync](git-sync.md)，您可以将模板存储在 Git 存储库中。创建或更新堆栈时，您可以指定 Git 存储库位置和包含模板的分支，而不是直接上传模板或引用 S3 URL。CloudFormation 会自动监控指定的存储库和分支以查找模板更改。有关更多信息，请参阅 [使用 Git 同步从存储库源代码创建堆栈](git-sync-create-stack-from-repository-source-code.md)。

## 验证模板
<a name="template-validation"></a>

**语法验证**  
您可以使用 [validate-template](service_code_examples.md#validate-template-sdk) CLI 命令或通过在控制台上指定模板来验证模板的 JSON 或 YAML 语法。控制台会自动执行验证。有关更多信息，请参阅 [通过 CloudFormation 控制台创建堆栈](cfn-console-create-stack.md)。

但这些方法仅会验证模板的语法，而不会验证您为资源指定的属性值。

**其他验证工具**  
要进行更复杂的验证和最佳实践检查，您可以使用其他工具，例如：
+ [CloudFormation Linter（cfn-lint）](https://github.com/aws-cloudformation/cfn-lint)：根据 [CloudFormation 资源提供程序架构](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/resource-type-schemas.html)验证模板。其中包括检查资源属性的有效值以及最佳实践。
+ [CloudFormation Rain（rain fmt）](https://github.com/aws-cloudformation/rain)– 按统一的标准格式化 CloudFormation 模板，或者将模板从 JSON 重新格式化为 YAML（或从 YAML 格式化为 JSON）。这会在使用 YAML 时会保留注释，并尽可能将内置函数转换为简短语法。

## 开始使用模板
<a name="getting-started"></a>

要开始创建 CloudFormation 模板，请遵循以下步骤：

1. **选择资源** – 确定要包含在堆栈中的 Amazon 资源，例如 EC2 实例、VPC、安全组等。

1. **编写模板** – 以 JSON 或 YAML 格式编写模板，定义资源及其属性。

1. **保存模板**：使用以下文件扩展名在本地保存模板：`.json`、`.yaml` 或 `.txt`。

1. **验证模板** – 使用 [验证模板](#template-validation) 部分中描述的方法验证模板。

1. **创建堆栈** – 使用验证后的模板创建堆栈。

### 计划使用 CloudFormation 模板引用
<a name="additional-resources"></a>

在编写模板时，可以在 [Amazon 资源和属性类型参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-template-resource-type-ref.html)中找到不同资源类型详细语法的文档。

通常，您的堆栈模板需要内置函数来分配直到运行时才可用的属性值，并需要特殊属性来控制资源的行为。在编写模板时，请参阅以下资源以获取指导：
+ [内置函数参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference.html)：一些常用的内置函数包括：
  + `Ref` – 检索资源的参数值或物理 ID。
  + `Sub` – 用实际值替换字符串中的占位符。
  + `GetAtt` – 返回模板中的资源的属性值。
  + `Join` – 将一组值连接成单个字符串。
+ [资源属性参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-product-attribute-reference.html)：一些常用的特殊属性包括：
  + `DependsOn` – 此属性用于指定必须在一个资源创建之后才能创建另一个资源。
  + `DeletionPolicy` – 此属性用于指定 CloudFormation 如何处理资源删除的方式。

## 示例模板
<a name="sample-templates"></a>

CloudFormation 提供了您可以开始使用的开源堆栈模板。有关更多信息，请参阅 GitHub 网站上的 [Amazon CloudFormation 示例模板](https://github.com/aws-cloudformation/aws-cloudformation-templates)。

请记住，这些模板并不意味着已做好生产的准备。您应该花些时间了解模板的工作方式，根据需要进行调整，并确保它们符合自己公司的合规标准。

该存储库中的每个模板都通过了 [CloudFormation Linter](https://github.com/aws-cloudformation/cfn-lint) (cfn-lint) 检查，以及一组基于 Center for Internet Security (CIS) 前 20 项控制的基本 Amazon CloudFormation Guard 规则，但示例应侧重于单个用例的某些规则除外。

# CloudFormation 模板格式
<a name="template-formats"></a>

可使用 JSON 或 YAML 格式创作 CloudFormation 模板。这两种格式的目的相同，但在可读性和复杂性方面各有明显的优势。
+ **JSON** – JSON 是一种轻量级的数据交换格式，非常便于机器解析和生成。但对于人类来说，读写可能会变得很麻烦，配置复杂时尤其如此。在 JSON 中，模板使用嵌套的大括号 `{}` 和方括号 `[]` 来定义资源、参数和其他组件。其语法要求显式声明每个元素，因此可能会使模板变得冗长，不过可以确保严格遵守结构化的格式。
+ **YAML** – 与 JSON 相比，YAML 的设计更便于人类阅读且不那么冗长。YAML 使用缩进而不是大括号和方括号来表示嵌套，因此更便于直观地显示资源和参数的层次结构。YAML 因清晰的结构和方便易用而备受青睐，尤其是在处理更复杂的模板时。但由于 YAML 依赖缩进，如果间距不一致则可能会导致错误，因此需要仔细注意以保持准确性。

## 模板结构
<a name="template-structure"></a>

CloudFormation 模板可分为不同的部分，每个部分都专用于保存特定类型的信息。有些部分必须按特定顺序声明，而对于其他部分，顺序则无关紧要。但在构建模板时，使用以下示例中显示的逻辑顺序可能非常实用，因为一个部分中的值可能会引用前一个部分中的值。

创建模板时，不要使用重复的主要部分，例如 `Resources` 部分。尽管 CloudFormation 可能会接受该模板，但在处理该模板时将会出现未定义的行为，并且可能会错误地预置资源，或者返回无法解释的错误。

### JSON
<a name="template-structure.json"></a>

以下示例演示了 JSON 格式的模板的结构，其中包含所有可用部分。

```
{
  "AWSTemplateFormatVersion" : "version date",

  "Description" : "JSON string",

  "Metadata" : {
    template metadata
  },

  "Parameters" : {
    set of parameters
  },
  
  "Rules" : {
    set of rules
  },

  "Mappings" : {
    set of mappings
  },

  "Conditions" : {
    set of conditions
  },

  "Transform" : {
    set of transforms
  },

  "Resources" : {
    set of resources
  },
  
  "Outputs" : {
    set of outputs
  }
}
```

### YAML
<a name="template-structure.yaml"></a>

以下示例演示了 YAML 格式的模板的结构，其中包含所有可用部分。

```
---
AWSTemplateFormatVersion: version date

Description:
  String

Metadata:
  template metadata

Parameters:
  set of parameters

Rules:
  set of rules

Mappings:
  set of mappings

Conditions:
  set of conditions

Transform:
  set of transforms

Resources:
  set of resources

Outputs:
  set of outputs
```

## 评论
<a name="template-comments"></a>

JSON 格式的模板不支持注释。JSON 在设计上未包含注释语法，因此无法直接在 JSON 结构中添加注释。但如果您需要包含解释性的说明或文档，则可以考虑添加元数据。有关更多信息，请参阅 [Metadata 属性](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-attribute-metadata.html)。

在 YAML 格式的模板中，您可以使用 `#` 符号包含内联注释。

以下示例介绍一个包含内联注释的 YAML 模板。

```
AWSTemplateFormatVersion: 2010-09-09
Description: A sample CloudFormation template with YAML comments.
# Resources section
Resources:
  MyEC2Instance: 
    Type: AWS::EC2::Instance
    Properties: 
      # Linux AMI
      ImageId: ami-1234567890abcdef0 
      InstanceType: t2.micro
      KeyName: MyKey
      BlockDeviceMappings:
        - DeviceName: /dev/sdm
          Ebs:
            VolumeType: io1
            Iops: 200
            DeleteOnTermination: false
            VolumeSize: 20
```

## 规格
<a name="template-formats.supported-specifications"></a>

CloudFormation 支持以下 JSON 和 YAML 规范：

JSON  
CloudFormation 遵循 ECMA-404 JSON 标准。有关 JSON 格式的更多信息，请访问 [http://www.json.org](http://www.json.org)。

YAML  
CloudFormation 支持 YAML 版本 1.1 规范，但有一些例外。CloudFormation 不支持以下功能：  
+ `binary`、`omap`、`pairs`、`set` 和 `timestamp` 标签
+ 别名
+ 哈希合并
有关 YAML 的更多信息，请参阅 [https://yaml.org/](https://yaml.org/)。

## 了解更多
<a name="template-formats.learnmore"></a>

对于您在模板中指定的每个资源，可以使用 JSON 或 YAML 的特定语法规则定义其属性和值。有关适用于每种格式的模板语法的更多信息，请参阅[CloudFormation 模板部分](template-anatomy.md)。

# 在 CloudFormation 模板中使用正则表达式
<a name="cfn-regexes"></a>

您可以在 CloudFormation 模板中的多个位置使用正则表达式（通常称为 Regex），例如，在创建模板[参数](parameters-section-structure.md)时为 `AllowedPattern` 属性指定正则表达式。

CloudFormation 中的所有正则表达式符合 Java 正则表达式语法。有关 Java 正则表达式语法及其构造的全面说明，请参阅 [java.util.regex.Pattern](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/regex/Pattern.html)。

如果您使用 JSON 语法编写 CloudFormation 模板，则对于正则表达式中的任何反斜杠字符（\$1），您必须再添加一个反斜杠进行转义。这是因为 JSON 将反斜杠解释为转义字符，因此您需要对反斜杠进行转义，以确保在正则表达式中将其视为反斜杠字符。

例如，如果要与数字字符匹配的正则表达式包含 `\d`，则需要在 JSON 模板中将其写为 `\\d`。

在以下示例中，`AllowedPattern` 属性指定了一个匹配连续四个数字字符（`\d{4}`）的正则表达式。但是，由于正则表达式是在 JSON 模板中定义的，因此需要添加一个额外的反斜杠（`\\d`）来对反斜杠字符进行转义。

```
{
  "Parameters": {
    "MyParameter": {
      "Type": "String",
      "AllowedPattern": "\\d{4}"
    }
  }
}
```

如果您使用 YAML 语法编写 CloudFormation 模板，则必须用单引号（''）将正则表达式括起来。不需要额外的转义。

```
Parameters:
  MyParameter:
    Type: String
    AllowedPattern: '\d{4}'
```

**注意**  
CloudFormation 中的正则表达式仅在特定上下文（如 `AllowedPattern`）中支持用于验证目的。不支持在 CloudFormation 内置函数（如 `Fn::Equals`）中作为模式匹配操作使用，这些函数仅执行精确字符串比较，不进行模式匹配。

# CloudFormation 模板部分
<a name="template-anatomy"></a>

每个 CloudFormation 模板都由一个或多个部分组成，每个部分都有特定的用途。

每个 CloudFormation 模板都需要有 **Resources** 部分，这是模板的核心。这一部分用于指定堆栈资源及其属性，如 Amazon EC2 实例或 Amazon S3 存储桶。每个资源都使用唯一的逻辑 ID、类型和特定的配置详细信息进行定义。

**Parameters** 部分尽管是可选的，但对于提高模板的灵活性十分重要。这一部分让用户能够在创建或更新堆栈时传递运行时的值。这些参数可以在 `Resources` 和 `Outputs` 部分中引用，从而无需更改模板本身即可进行自定义。例如，您可以使用参数来指定不同部署的实例类型或环境设置。

**Outputs** 部分也是可选的，用于定义查看堆栈属性时返回的值。输出提供了可用于操作目的或与其他堆栈集成的实用信息，例如资源标识符或 URL 等。这一部分有助于用户检索和使用与模板所创建资源有关的重要详细信息。

其他可选部分包括 **Mappings**，其功能类似于查找表，用于管理条件值。使用映射，您可以定义键值对，并将其与 `Resources` 和 `Outputs` 部分中的 `Fn::FindInMap` 内置函数结合使用。这对于需要根据条件（例如 Amazon Web Services 区域 或环境）调整配置的场景非常实用。

**Metadata** 和 **Rules** 部分虽然不太常用，但提供了额外的功能。`Metadata` 可以包含有关模板的更多信息，而 `Rules` 会在堆栈创建或更新期间验证参数或参数组合，确保符合特定标准。**Conditions** 部分根据环境类型等条件来控制是否创建特定的资源或者属性分配值，从而进一步提高灵活性。

最后是 **Transform** 部分，用于在处理模板期间应用宏。对于无服务器应用程序（也称为 Lambda 应用程序），这一部分会指定要使用的 [Amazon Serverless Application Model（Amazon SAM）](https://github.com/awslabs/serverless-application-specification)版本。当您指定转换时，可以使用 Amazon SAM 语法声明您的模板中的资源。此模型定义您可使用的语法及其处理方式。您也可以使用 `AWS::Include` 转换来包含与主 CloudFormation 模板分开存储的模板代码片段。

以下主题提供了有关如何使用每个部分的更多信息和示例。

**Topics**
+ [Resources](resources-section-structure.md)
+ [Parameters](parameters-section-structure.md)
+ [Outputs](outputs-section-structure.md)
+ [Mappings](mappings-section-structure.md)
+ [Metadata](metadata-section-structure.md)
+ [Rules](rules-section-structure.md)
+ [Conditions](conditions-section-structure.md)
+ [Transform](transform-section-structure.md)
+ [格式版本](format-version-structure.md)
+ [Description](template-description-structure.md)

# CloudFormation 模板 Resources 语法
<a name="resources-section-structure"></a>

`Resources` 部分是 CloudFormation 模板中必需具备的一个顶级部分，用于声明您希望 CloudFormation 在堆栈中预置和配置的 Amazon 资源。

## 语法
<a name="resources-section-structure-syntax"></a>

`Resources` 部分使用以下语法：

### JSON
<a name="resources-section-structure-syntax.json"></a>

```
"Resources" : {
    "LogicalResourceName1" : {
        "Type" : "AWS::ServiceName::ResourceType",
        "Properties" : {
            "PropertyName1" : "PropertyValue1",
            ...
        }
    },

    "LogicalResourceName2" : {
        "Type" : "AWS::ServiceName::ResourceType",
        "Properties" : {
            "PropertyName1" : "PropertyValue1",
            ...
        }
    }
}
```

### YAML
<a name="resources-section-structure-syntax.yaml"></a>

```
Resources:
  LogicalResourceName1:
    Type: AWS::ServiceName::ResourceType
    Properties:
      PropertyName1: PropertyValue1
      ...

  LogicalResourceName2:
    Type: AWS::ServiceName::ResourceType
    Properties:
      PropertyName1: PropertyValue1
      ...
```

## 逻辑 ID（也称为*逻辑名称*）
<a name="resources-section-logical-id"></a>

在 CloudFormation 模板中，资源由其逻辑资源名称来标识。这些名称必须为字母数字字符（A-Za-z0-9），并且在模板中必须唯一。逻辑名称用于引用模板其他部分中的资源。

## 资源类型
<a name="resources-section-resource-type"></a>

每个资源必须有一个 `Type` 属性，用于定义 Amazon 资源的类型。`Type` 属性的格式为 `AWS::ServiceName::ResourceType`。例如，Amazon S3 存储桶的 `Type` 属性为 `AWS::S3::Bucket`。

有关支持的资源类型的完整列表，请参阅 [Amazon 资源和属性类型参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-template-resource-type-ref.html)。

## 资源属性
<a name="resources-section-resource-properties"></a>

资源属性是可以指定的附加选项，用于定义特定资源类型的详细配置。某些属性是必需的，而另一些属性则是可选的。有些属性具有默认值，因此指定这些属性是可选的。

有关每种资源类型支持的属性的详细信息，请参阅 [Amazon 资源和属性类型参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-template-resource-type-ref.html)中的主题。

属性值可以是文本字符串、字符串列表、布尔值、动态引用、参数引用、伪引用或者函数返回的值。以下示例演示了如何声明不同的属性值类型：

### JSON
<a name="resource-properties-example.json"></a>

```
"Properties" : {
    "String" : "A string value",
    "Number" : 123,
    "LiteralList" : [ "first-value", "second-value" ],
    "Boolean" : true
}
```

### YAML
<a name="resource-properties-example.yaml"></a>

```
Properties:
  String: A string value 
  Number: 123
  LiteralList:
    - first-value
    - second-value
  Boolean: true
```

## 物理 ID
<a name="resources-section-physical-id"></a>

除了逻辑 ID 外，某些资源还有物理 ID，这是资源的实际分配名称，如 EC2 实例 ID 或 S3 存储桶名称。使用物理 ID 来标识 CloudFormation 模板外部的资源，但只能在创建了资源之后进行。例如，假设您为一个 EC2 实例资源指定 `MyEC2Instance` 的逻辑 ID。当 CloudFormation 创建实例时，CloudFormation 会自动生成物理 ID（如 `i-1234567890abcdef0`）并将其分配给该实例。您可以使用该物理 ID 来标识实例，可以使用 Amazon EC2 控制台查看其属性 (如 DNS 名称)。

对于 Amazon S3 存储桶和许多其他资源，如果您没有明确指定实体名称，CloudFormation 会自动为该资源生成唯一的实体名称。该实体名称基于 CloudFormation 堆栈的名称、在 CloudFormation 模板中指定的资源逻辑名称和唯一 ID 的组合。例如，假设您在名为 `MyStack` 的堆栈中有一个逻辑名称为 `MyBucket` 的 Amazon S3 存储桶，CloudFormation 可能会使用如下物理名称 `MyStack-MyBucket-abcdefghijk1` 来命名该存储桶。

对于支持自定义名称的资源，您可以分配自己的物理名称来帮助快速标识资源。例如，您可以将存储日志的 S3 存储桶命名为 `MyPerformanceLogs`。有关更多信息，请参阅[名称类型](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-name.html)。

## 引用资源
<a name="using-cross-resource-references"></a>

您经常会需要根据一个资源的名称或属性来设置另一个资源的属性。例如，您可以创建一个使用 EC2 安全组的 EC2 实例，或由 S3 存储桶支持的 CloudFront 分配。所有这些资源都可在同一 CloudFormation 模板中创建。

CloudFormation 提供了内置函数，您可以使用这些函数来引用其他资源及其属性。这些函数让您可以在资源之间创建依赖关系，并将一个资源的值传递到另一个资源。

### `Ref` 函数
<a name="resource-properties-ref"></a>

`Ref` 函数通常用于检索在同一 CloudFormation 模板中定义的资源的标识属性。具体返回的值取决于资源的类型。对于大多数资源，该函数会返回资源的实体名称。不过对于某些资源类型，该函数可能会返回其他的值，例如 `AWS::EC2::EIP` 资源的 IP 地址或 Amazon SNS 主题的 Amazon 资源名称（ARN）。

以下示例演示了如何在属性中使用 `Ref` 函数。在以下的每个示例中，`Ref` 函数都将返回模板中其他部分声明的 `LogicalResourceName` 资源的实际名称。YAML 示例中的 `!Ref` 语法示例只是编写 `Ref` 函数的较简单方法。

#### JSON
<a name="resource-properties-ref-example.json"></a>

```
"Properties" : {
    "PropertyName" : { "Ref" : "LogicalResourceName" }
}
```

#### YAML
<a name="resource-properties-ref-example.yaml"></a>

```
Properties:
  PropertyName1:
    Ref: LogicalResourceName
  PropertyName2: !Ref LogicalResourceName
```

有关使用 `Ref` 函数的更多详细信息，请参阅 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-ref.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-ref.html)。

### `Fn::GetAtt` 函数
<a name="resource-properties-getatt"></a>

如果参数或为资源返回的值正是您需要的，则 `Ref` 函数会非常实用。不过，您可能需要资源的其他属性。例如，如果您想创建一个具有 S3 起始地址的 CloudFront 分配，就需要使用 DNS 样式的地址来指定存储桶的位置。很多资源都具有附加属性，您可以在模板中使用这些属性的值。要获取这些属性，请使用 `Fn::GetAtt` 函数。

以下示例演示了如何在属性中使用 `GetAtt` 函数。`Fn::GetAtt` 函数有两个参数，分别是资源的逻辑名称和要检索的属性名称。YAML 示例中的 `!GetAtt` 语法示例只是编写 `GetAtt` 函数的较简单方法。

#### JSON
<a name="resource-properties-getatt-example.json"></a>

```
"Properties" : {
    "PropertyName" : {
        "Fn::GetAtt" : [ "LogicalResourceName", "AttributeName" ]
    }
}
```

#### YAML
<a name="resource-properties-getatt-example.yaml"></a>

```
Properties:
  PropertyName1:
    Fn::GetAtt:
      - LogicalResourceName
      - AttributeName
  PropertyName2: !GetAtt LogicalResourceName.AttributeName
```

有关使用 `GetAtt` 函数的更多详细信息，请参阅 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-getatt.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-getatt.html)。

## 示例
<a name="resources-section-structure-examples"></a>

以下示例演示了如何声明资源以及 CloudFormation 模板会如何引用在同一模板中定义的其他资源以及现有的 Amazon 资源。

**Topics**
+ [

### 使用自定义名称声明单个资源
](#resources-section-structure-examples-single-resource)
+ [

### 使用 `Ref` 函数引用其他资源
](#resources-section-structure-examples-ref)
+ [

### 使用 `Fn::GetAtt` 函数引用资源属性
](#resources-section-structure-examples-getatt)

### 使用自定义名称声明单个资源
<a name="resources-section-structure-examples-single-resource"></a>

以下示例声明了 `AWS::S3::Bucket` 类型的单个资源，逻辑名称为 `MyBucket`。`BucketName` 属性设置为 *amzn-s3-demo-bucket*，因此应替换为您的 S3 存储桶所需的名称。

如果您使用此资源声明创建堆栈，CloudFormation 将使用默认设置创建 Amazon S3 存储桶。对于 Amazon EC2 实例或自动扩缩组等其他资源，CloudFormation 需要更多信息。

#### JSON
<a name="resources-section-structure-examples-single-resource.json"></a>

```
{
    "Resources": {
        "MyBucket": {
            "Type": "AWS::S3::Bucket",
            "Properties": {
                "BucketName": "amzn-s3-demo-bucket"
            }
        }
    }
}
```

#### YAML
<a name="resources-section-structure-examples-single-resource.yaml"></a>

```
Resources:
  MyBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: amzn-s3-demo-bucket
```

### 使用 `Ref` 函数引用其他资源
<a name="resources-section-structure-examples-ref"></a>

以下示例演示的资源声明定义了一个 EC2 实例和安全组。`Ec2Instance` 资源使用 `Ref` 函数引用 `InstanceSecurityGroup` 资源，以作为其 `SecurityGroupIds` 属性的一部分。此外还包括未在模板中声明的一个现有安全组 (`sg-12a4c434`)。您可以使用文字字符串来指代现有 Amazon 资源。

#### JSON
<a name="resources-section-structure-examples-ref.json"></a>

```
{
    "Resources": {
        "Ec2Instance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "SecurityGroupIds": [
                    {
                        "Ref": "InstanceSecurityGroup"
                    },
                    "sg-12a4c434"
                ],
                "KeyName": "MyKey",
                "ImageId": "ami-1234567890abcdef0"
            }
        },
        "InstanceSecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": "Enable SSH access via port 22",
                "SecurityGroupIngress": [
                    {
                        "IpProtocol": "tcp",
                        "FromPort": 22,
                        "ToPort": 22,
                        "CidrIp": "0.0.0.0/0"
                    }
                ]
            }
        }
    }
}
```

#### YAML
<a name="resources-section-structure-examples-ref.yaml"></a>

```
Resources:
  Ec2Instance:
    Type: AWS::EC2::Instance
    Properties:
      SecurityGroupIds:
        - !Ref InstanceSecurityGroup
        - sg-12a4c434
      KeyName: MyKey
      ImageId: ami-1234567890abcdef0
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable SSH access via port 22
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
```

### 使用 `Fn::GetAtt` 函数引用资源属性
<a name="resources-section-structure-examples-getatt"></a>

以下示例演示的资源声明定义了一个 CloudFront 分配资源和一个 S3 存储桶。`MyDistribution` 资源指定了 `MyBucket` 资源的 DNS 名称，后者使用 `Fn::GetAtt` 函数来获取存储桶的 `DomainName` 属性。`Fn::GetAtt` 函数会在一个数组中列出这两个参数。对于采用多个参数的函数，可以使用数组来指定其参数。

#### JSON
<a name="resources-section-structure-examples-getatt.json"></a>

```
{
  "Resources": {
    "MyBucket": {
      "Type": "AWS::S3::Bucket"
    },
    "MyDistribution": {
      "Type": "AWS::CloudFront::Distribution",
      "Properties": {
        "DistributionConfig": {
          "Origins": [
            {
              "DomainName": {
                "Fn::GetAtt": [
                  "MyBucket",
                  "DomainName"
                ]
              },
              "Id": "MyS3Origin",
              "S3OriginConfig": {}
            }
          ],
          "Enabled": "true",
          "DefaultCacheBehavior": {
            "TargetOriginId": "MyS3Origin",
            "ForwardedValues": {
              "QueryString": "false"
            },
            "ViewerProtocolPolicy": "allow-all"
          }
        }
      }
    }
  }
}
```

#### YAML
<a name="resources-section-structure-examples-getatt.yaml"></a>

```
Resources:
  MyBucket:
    Type: AWS::S3::Bucket
  MyDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Origins:
          - DomainName: !GetAtt 
              - MyBucket
              - DomainName
            Id: MyS3Origin
            S3OriginConfig: {}
        Enabled: 'true'
        DefaultCacheBehavior:
          TargetOriginId: MyS3Origin
          ForwardedValues:
            QueryString: 'false'
          ViewerProtocolPolicy: allow-all
```

# CloudFormation 模板 Parameters 语法
<a name="parameters-section-structure"></a>

使用可选的 `Parameters` 部分来自定义模板。利用参数，您能够在每次创建或更新堆栈时在模板中输入自定义值。通过在模板中使用参数，您可以构建可重复使用的灵活模板，以便根据具体场景进行自定义。

通过定义适当类型的参数，您可以在使用控制台创建堆栈时从现有资源的标识符列表中进行选择。有关更多信息，请参阅 [使用 CloudFormation 提供的参数类型在运行时指定现有资源](cloudformation-supplied-parameter-types.md)。

参数是指定堆栈资源属性值的一种常用方法。但是，可能会有一些因区域而异的设置，或是一些因其他条件或依赖关系而需要用户确定的复杂设置。在这些情况下，您可能需要将一些逻辑放入模板本身中，以便用户可以指定简单值（或不指定任何值）来获得期望的结果，例如通过使用映射。有关更多信息，请参阅 [CloudFormation 模板 Mappings 语法](mappings-section-structure.md)。

## 语法
<a name="parameters-section-structure-syntax"></a>

您需要在模板的 `Parameters` 部分声明参数，该部分会使用以下通用语法：

### JSON
<a name="parameters-section-structure-syntax.json"></a>

```
"Parameters" : {
  "ParameterLogicalID" : {
    "Description": "Information about the parameter",
    "Type" : "DataType",
    "Default" : "value",
    "AllowedValues" : ["value1", "value2"]
  }
}
```

### YAML
<a name="parameters-section-structure-syntax.yaml"></a>

```
Parameters:
  ParameterLogicalID:
    Description: Information about the parameter
    Type: DataType
    Default: value
    AllowedValues:
      - value1
      - value2
```

一个参数包含一系列属性，这些属性定义了其值但也限制了其值。唯一必需的属性是 `Type`，该属性可以是 `String`、`Number` 或 CloudFormation 提供的参数类型。您还可以添加 `Description` 属性来描述要指定的值的类型。在**创建堆栈**向导中使用该模板时，参数的名称和描述会在**指定参数**页面中显示。

**注意**  
默认情况下，CloudFormation 控制台按照输入参数的逻辑 ID 的字母顺序列出这些参数。要覆盖此默认排序并将相关参数组合在一起，您可以在模板中使用 `AWS::CloudFormation::Interface` 元数据键。有关更多信息，请参阅 [使用 `AWS::CloudFormation::Interface` 元数据整理 CloudFormation 参数](aws-cloudformation-interface.md)。

对于具有默认值的参数，CloudFormation 将使用默认值，除非用户指定其他值。如果省略默认属性，则用户将需要指定该参数的值。但是，要求用户输入值并不能确保该值有效。要验证参数的值，您可以声明一些约束或指定某个特定于 Amazon 的参数类型。

对于没有默认值的参数，用户必须在创建堆栈时指定一个键名称值。否则，CloudFormation 将无法创建堆栈并引发异常：

```
Parameters: [KeyName] must have values
```

## 属性
<a name="parameters-section-structure-properties"></a>

`AllowedPattern`  
一个正则表达式，表示要允许 `String` 和 `CommaDelimitedList` 类型使用的模式。应用于类型为 `String` 的参数时，模式必须与提供的整个参数值匹配。应用于类型为 `CommaDelimitedList` 的参数时，模式必须与列表中的每个值匹配。  
*必需*：否

`AllowedValues`  
包含参数允许值列表的阵列。应用于类型为 `String` 的参数时，该参数值必须是允许的值之一。应用于类型为 `CommaDelimitedList` 的参数时，列表中的每个值都必须是指定的允许的值之一。  
*必需*：否  
如果您使用 YAML，并且想要在 `AllowedValues` 中使用 `Yes` 和 `No` 字符串，请使用单引号来防止 YAML 解析器考虑这些布尔值。

`ConstraintDescription`  
用于在违反约束时说明该约束的字符串。例如，在没有约束条件描述的情况下，具有允许的 `[A-Za-z0-9]+` 模式的参数会在用户指定无效值时显示以下错误消息：  
`Malformed input-Parameter MyParameter must match pattern [A-Za-z0-9]+`  
通过添加约束描述（如 *must only contain letters (uppercase and lowercase) and numbers*），您可以显示以下自定义的错误消息：  
`Malformed input-Parameter MyParameter must only contain uppercase and lowercase letters and numbers`  
*必需*：否

`Default`  
模板适当类型的值，用于在创建堆栈时未指定值的情况下。如果您定义参数的约束，则必须指定一个符合这些约束的值。  
*必需*：否

`Description`  
用于描述参数的长度最多为 4000 个字符的字符串。  
*必需*：否

`MaxLength`  
一个整数值，确定要允许 `String` 类型使用的字符的最大数目。  
*必需*：否

`MaxValue`  
一个数字值，确定要允许 `Number` 类型使用的最大数字值。  
*必需*：否

`MinLength`  
一个整数值，确定要允许 `String` 类型使用的字符的最小数目。  
*必需*：否

`MinValue`  
一个数字值，确定要允许 `Number` 类型使用的最小数字值。  
*必需*：否

`NoEcho`  
是否遮蔽参数值以防止在控制台、命令行或 API 中显示。如果您将 `NoEcho` 属性设置为 `true`，则对于描述堆栈或堆栈事件的任何调用，CloudFormation 返回使用星号 (\$1\$1\$1\$1\$1) 遮蔽的参数值，但存储在下面指定位置的信息除外。  
*必需*：否  
使用 `NoEcho` 属性不会遮蔽在以下各区段中存储的任何信息：  
+ `Metadata` 模板区段。CloudFormation 不会转换、修改或编辑您在 `Metadata` 部分中包含的任何信息。有关更多信息，请参阅 [Metadata](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html)。
+ `Outputs` 模板区段。有关更多信息，请参阅 [Outputs](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html)。
+ 资源定义的 `Metadata` 属性。有关更多信息，请参阅 [`Metadata` 属性](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-attribute-metadata.html)。
强烈建议您不要使用这些机制来包含敏感信息，例如密码。
我们建议不要将敏感信息直接嵌入 CloudFormation 模板中，而应使用堆栈模板中的动态参数来引用在 CloudFormation 外部存储和管理的敏感信息，例如 Amazon Systems Manager Parameter Store 或 Amazon Secrets Manager 中的敏感信息。  
有关更多信息，请参阅[请勿将凭证嵌入您的模板](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/security-best-practices.html#creds)最佳实践。
我们建议不要在作为资源主标识符一部分的资源属性中包含 `NoEcho` 参数或任何敏感数据。  
当 `NoEcho` 参数包含在构成主资源标识符的属性中时，CloudFormation 可能会在主资源标识符中使用*实际明文值*。此资源 ID 可能出现在任何派生输出或目标中。  
要确定哪些资源属性构成了资源类型的主标识符，请参阅 [Amazon 资源和属性类型参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-template-resource-type-ref.html)中该资源的资源参考文档。在 **Return values**（返回值）部分，`Ref` 函数返回值，表示构成资源类型主标识符的资源属性。

`Type`  <a name="parameters-section-structure-properties-type"></a>
参数 (`DataType`) 的数据类型。  
*是否必需*：是  
CloudFormation 支持以下参数类型：    
`String`  
一个文字字符串。您可以使用以下属性来声明约束：`MinLength`、`MaxLength`、`Default`、`AllowedValues` 和 `AllowedPattern`。  
例如，用户可指定 `"MyUserName"`。  
`Number`  
整型或浮点型。CloudFormation 将参数值作为数字进行验证；但当您在模板中的其他位置使用参数时（例如，通过使用 `Ref` 内置函数），该参数值将变为字符串。  
您可以使用以下属性来声明约束：`MinValue`、`MaxValue`、`Default` 和 `AllowedValues`。  
例如，用户可指定 `"8888"`。  
`List<Number>`  
以逗号分隔的整型或浮点型数组。CloudFormation 将参数值作为数字进行验证；但当您在模板中的其他位置使用参数时（例如，通过使用 `Ref` 内置函数），该参数值将变为字符串列表。  
例如，用户可指定 `"80,20"`，并且 `Ref` 将生成 `["80","20"]`。  
`CommaDelimitedList`  
一组用逗号分隔的文本字符串。字符串的总数应比逗号总数多 1。此外，会对每个成员字符串进行空间修剪。  
例如，用户可指定 `"test,dev,prod"`，并且 `Ref` 将生成 `["test","dev","prod"]`。  
特定于 Amazon 的参数类型  
Amazon 值，例如 Amazon EC2 密钥对名称和 VPC ID。有关更多信息，请参阅 [在运行时指定现有资源](cloudformation-supplied-parameter-types.md)。  
Systems Manager 参数类型  
与 Systems Manager Parameter Store 中的现有参数对应的参数。您指定 Systems Manager 参数键作为 Systems Manager 参数类型的值，然后 CloudFormation 从 Parameter Store 中检索最新的值来用于堆栈。有关更多信息，请参阅 [在运行时指定现有资源](cloudformation-supplied-parameter-types.md)。

## 参数的一般要求
<a name="parameters-section-structure-requirements"></a>

使用参数时存在以下要求：
+ 一个 CloudFormation 模板中最多可包含 200 个参数。
+ 必须为每个参数提供一个逻辑名称（也称为逻辑 ID），该名称必须是字母数字，并且在模板内的所有逻辑名称中必须唯一。
+ 必须向每个参数分配一个 CloudFormation 支持的参数类型。有关更多信息，请参阅[类型](#parameters-section-structure-properties-type)。
+ 必须向每个参数分配一个运行时的值，这样 CloudFormation 才能成功预置堆栈。您可以选择为要使用的 CloudFormation 指定默认值，除非提供有其他值。
+ 必须在同一模板内声明和引用参数。您可以引用模板的 `Resources` 和 `Outputs` 部分中的参数。

## 示例
<a name="parameters-section-examples"></a>

**Topics**
+ [

### 简单字符串参数
](#parameters-section-structure-example-1)
+ [

### 密码参数
](#parameters-section-structure-example-2)
+ [

### 引用参数
](#parameters-section-structure-example-3)
+ [

### 逗号分隔列表参数
](#parameters-section-structure-example-4)
+ [

### 从逗号分隔列表参数返回值
](#parameters-section-structure-example-5)

### 简单字符串参数
<a name="parameters-section-structure-example-1"></a>

以下示例声明了一个名为 `InstanceTypeParameter`，类型为 `String` 的参数。利用此参数，您可以为堆栈指定 Amazon EC2 实例类型。如果在创建或更新堆栈期间未提供任何值，CloudFormation 将使用 `t2.micro` 的默认值。

#### JSON
<a name="parameters-section-structure-example-1.json"></a>

```
"Parameters" : {
  "InstanceTypeParameter" : {
    "Description" : "Enter t2.micro, m1.small, or m1.large. Default is t2.micro.",
    "Type" : "String",
    "Default" : "t2.micro",
    "AllowedValues" : ["t2.micro", "m1.small", "m1.large"]
  }
}
```

#### YAML
<a name="parameters-section-structure-example-1.yaml"></a>

```
Parameters:
  InstanceTypeParameter:
    Description: Enter t2.micro, m1.small, or m1.large. Default is t2.micro.
    Type: String
    Default: t2.micro
    AllowedValues:
      - t2.micro
      - m1.small
      - m1.large
```

### 密码参数
<a name="parameters-section-structure-example-2"></a>

以下示例声明了一个名为 `DBPwd`，类型为 `String` 且没有默认值的参数。将 `NoEcho` 属性设置为 `true` 是为了防止在堆栈描述中显示参数值。可指定的最小长度为 `1`，可指定的最大长度为 `41`。该模式允许小写和大写字母字符和数字。此示例还演示了 `AllowedPattern` 属性的正则表达式用法。

#### JSON
<a name="parameters-section-structure-example-2.json"></a>

```
"Parameters" : {
  "DBPwd" : {
    "NoEcho" : "true",
    "Description" : "The database admin account password",
    "Type" : "String",
    "MinLength" : "1",
    "MaxLength" : "41",
    "AllowedPattern" : "^[a-zA-Z0-9]*$"
  }
}
```

#### YAML
<a name="parameters-section-structure-example-2.yaml"></a>

```
Parameters: 
  DBPwd: 
    NoEcho: true
    Description: The database admin account password
    Type: String
    MinLength: 1
    MaxLength: 41
    AllowedPattern: ^[a-zA-Z0-9]*$
```

### 引用参数
<a name="parameters-section-structure-example-3"></a>

您可以使用 `Ref` 内置函数来引用某个参数，然后 CloudFormation 将使用该参数的值来预置堆栈。您可以引用同一模板的 `Resources` 和 `Outputs` 部分中的参数。

在以下示例中，EC2 实例资源的 `InstanceType` 属性引用了 `InstanceTypeParameter` 参数值：

#### JSON
<a name="parameters-section-structure-example-3.json"></a>

```
"Ec2Instance" : {
  "Type" : "AWS::EC2::Instance",
  "Properties" : {
    "InstanceType" : { "Ref" : "InstanceTypeParameter" },
    "ImageId" : "ami-0ff8a91507f77f867"
  }
}
```

#### YAML
<a name="parameters-section-structure-example-3.yaml"></a>

```
Ec2Instance:
  Type: AWS::EC2::Instance
  Properties:
    InstanceType:
      Ref: InstanceTypeParameter
    ImageId: ami-0ff8a91507f77f867
```

### 逗号分隔列表参数
<a name="parameters-section-structure-example-4"></a>

需要为单个属性提供多个值时，`CommaDelimitedList` 参数类型可能非常实用。以下示例声明了一个名为 `DbSubnetIpBlocks` 的参数，其默认值为用逗号分隔的三个 CIDR 块。

#### JSON
<a name="parameters-section-structure-example-4.json"></a>

```
"Parameters" : {
  "DbSubnetIpBlocks": {
    "Description": "Comma-delimited list of three CIDR blocks",
    "Type": "CommaDelimitedList",
    "Default": "10.0.48.0/24, 10.0.112.0/24, 10.0.176.0/24"
  }
}
```

#### YAML
<a name="parameters-section-structure-example-4.yaml"></a>

```
Parameters: 
  DbSubnetIpBlocks: 
    Description: "Comma-delimited list of three CIDR blocks"
    Type: CommaDelimitedList
    Default: "10.0.48.0/24, 10.0.112.0/24, 10.0.176.0/24"
```

### 从逗号分隔列表参数返回值
<a name="parameters-section-structure-example-5"></a>

要引用以逗号分隔的参数列表中的特定值，请在模板的 `Resources` 部分中使用 `Fn::Select` 内置函数。可传递所需对象的索引值以及对象列表，如以下示例所示。

#### JSON
<a name="parameters-section-structure-example-5.json"></a>

```
{
    "Parameters": {
        "VPC": {
            "Type": "String",
            "Default": "vpc-123456"
        },
        "VpcAzs": {
            "Type": "CommaDelimitedList",
            "Default": "us-west-2a, us-west-2b, us-west-2c"
        },
        "DbSubnetIpBlocks": {
            "Type": "CommaDelimitedList",
            "Default": "172.16.0.0/26, 172.16.0.64/26, 172.16.0.128/26"
        }
    },
    "Resources": {
        "DbSubnet1": {
            "Type": "AWS::EC2::Subnet",
            "Properties": {
                "AvailabilityZone": {
                    "Fn::Select": [
                      0,
                      { 
                        "Ref": "VpcAzs" 
                      }
                   ]
                },
                "VpcId": {
                    "Ref": "VPC"
                },
                "CidrBlock": {
                    "Fn::Select": [
                        0,
                        { "Ref": "DbSubnetIpBlocks" }
                    ]
                }
            }
        },
        "DbSubnet2": {
            "Type": "AWS::EC2::Subnet",
            "Properties": {
                "AvailabilityZone": {
                    "Fn::Sub": [
                        "${AWS::Region}${AZ}",
                        {
                            "AZ": {
                                "Fn::Select": [
                                    1,
                                    { "Ref": "VpcAzs" }
                                ]
                            }
                        }
                    ]
                },
                "VpcId": {
                    "Ref": "VPC"
                },
                "CidrBlock": {
                    "Fn::Select": [
                        1,
                        { "Ref": "DbSubnetIpBlocks" }
                    ]
                }
            }
        },
        "DbSubnet3": {
            "Type": "AWS::EC2::Subnet",
            "Properties": {
                "AvailabilityZone": {
                    "Fn::Sub": [
                        "${AWS::Region}${AZ}",
                        {
                            "AZ": {
                                "Fn::Select": [
                                    2,
                                    { "Ref": "VpcAzs" }
                                ]
                            }
                        }
                    ]
                },
                "VpcId": {
                    "Ref": "VPC"
                },
                "CidrBlock": {
                    "Fn::Select": [
                        2,
                        { "Ref": "DbSubnetIpBlocks" }
                    ]
                }
            }
        }
    }
}
```

#### YAML
<a name="parameters-section-structure-example-5.yaml"></a>

```
Parameters:
  VPC:
    Type: String
    Default: vpc-123456
  VpcAzs:
    Type: CommaDelimitedList
    Default: us-west-2a, us-west-2b, us-west-2c
  DbSubnetIpBlocks:
    Type: CommaDelimitedList
    Default: 172.16.0.0/26, 172.16.0.64/26, 172.16.0.128/26
Resources:
  DbSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select
        - 0 
        - !Ref VpcAzs
      VpcId: !Ref VPC
      CidrBlock: !Select
        - 0
        - !Ref DbSubnetIpBlocks
  DbSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Sub
        - ${AWS::Region}${AZ}
        - AZ: !Select
            - 1
            - !Ref VpcAzs
      VpcId: !Ref VPC
      CidrBlock: !Select
        - 1
        - !Ref DbSubnetIpBlocks
  DbSubnet3:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Sub
        - ${AWS::Region}${AZ}
        - AZ: !Select
            - 2
            - !Ref VpcAzs
      VpcId: !Ref VPC
      CidrBlock: !Select
        - 2
        - !Ref DbSubnetIpBlocks
```

## 相关资源
<a name="parameters-section-structure-related-resources"></a>

CloudFormation 还支持使用动态引用来动态指定属性值。例如，您可能需要引用存储在 Systems Manager Parameter Store 中的安全字符串。有关更多信息，请参阅 [使用动态引用获取存储在其他服务中的值](dynamic-references.md)。

您也可以在 `Ref` 或 `Sub` 函数中使用伪参数来动态填充值。有关更多信息，请参阅 [使用伪参数获取 Amazon 值](pseudo-parameter-reference.md)。

# CloudFormation 模板 Outputs 语法
<a name="outputs-section-structure"></a>

可选的 `Outputs` 部分用于声明堆栈的输出值。这些输出值可以通过多种方式使用：
+ **捕获与资源有关的重要信息** – 通过输出可以方便地捕获与资源有关的重要信息。例如，您可以输出堆栈的 S3 存储桶名称以使该存储桶更容易找到。可以在 CloudFormation 控制台的**输出**选项卡中或使用 [describe-stacks](service_code_examples.md#describe-stacks-sdk) CLI 命令查看输出值。
+ **跨堆栈引用** – 您可以将输出值导入其他堆栈，以便[在堆栈之间创建引用](using-cfn-stack-exports.md)。当您需要跨多个堆栈共享资源或配置时，这会非常实用。

**重要**  
CloudFormation 不会对 `Outputs` 部分中包含的任何信息进行编辑或模糊处理。我们强烈建议您不要使用此部分输出敏感信息，例如密码或密钥。  
堆栈操作完成后，输出值可用。当堆栈状态处于任何 `IN_PROGRESS` [状态](view-stack-events.md#cfn-console-view-stack-data-resources-status-codes)时，堆栈输出值都不可用。我们不建议在服务运行时和堆栈输出值之间建立依赖关系，因为输出值可能并非始终都可用。

## 语法
<a name="outputs-section-syntax"></a>

`Outputs` 部分包括键名称 `Outputs`。您最多可在一个模板中声明 200 个输出。

以下示例演示了 `Outputs` 部分的结构。

### JSON
<a name="outputs-section-structure-syntax.json"></a>

使用括号将所有输出声明括起来。使用逗号分隔多个输出。

```
"Outputs" : {
  "OutputLogicalID" : {
    "Description" : "Information about the value",
    "Value" : "Value to return",
    "Export" : {
      "Name" : "Name of resource to export"
    }
  }
}
```

### YAML
<a name="outputs-section-structure-syntax.yaml"></a>

```
Outputs:
  OutputLogicalID:
    Description: Information about the value
    Value: Value to return
    Export:
      Name: Name of resource to export
```

### 输出字段
<a name="outputs-section-structure-output-fields"></a>

`Outputs` 部分包含以下字段。

**逻辑 ID（也称为*逻辑名称*）**  
当前输出的标识符。逻辑 ID 必须为字母数字（`a–z`、`A–Z` 和 `0–9`），并且在模板中具有唯一性。

**`Description`（可选）**  
一个描述输出类型的 `String` 类型。描述声明的值必须是长度介于 0 和 1024 个字节之间的文字字符串。您无法使用参数或函数来指定描述。

**`Value`（必需）**  
[describe-stacks](service_code_examples.md#describe-stacks-sdk) 命令返回的属性值。输出值可以包括文字、参数引用、伪参数、映射值或内置函数。

**`Export`（可选）**  
要为跨堆栈引用导出的资源输出的名称。  
您可使用内部函数自定义导出的 `Name` 值。  
有关更多信息，请参阅 [获取从已部署的 CloudFormation 堆栈导出的输出](using-cfn-stack-exports.md)。

要将条件与输出关联，请在模板的 [Conditions](conditions-section-structure.md) 部分中定义条件。

## 示例
<a name="outputs-section-structure-examples"></a>

以下示例说明了堆栈输出的工作原理。

**Topics**
+ [

### 堆栈输出
](#outputs-section-structure-examples-stack-output)
+ [

### 使用 `Fn::Sub` 自定义导出名称
](#outputs-section-structure-examples-cross-stack)
+ [

### 使用 `Fn::Join` 自定义导出名称
](#outputs-section-structure-examples-join-export-name)
+ [

### 返回使用 `Fn::Join` 构造的 URL
](#outputs-section-structure-examples-join-export-url)

### 堆栈输出
<a name="outputs-section-structure-examples-stack-output"></a>

在以下示例中，仅当 `BackupLoadBalancerDNSName` 条件为 true 时，名为 `BackupLoadBalancer` 的输出才返回逻辑 ID 为 `CreateProdResources` 的资源的 DNS 名称。名为 `InstanceID` 的输出会返回逻辑 ID 为 `EC2Instance` 的 EC2 实例的 ID。

#### JSON
<a name="outputs-section-structure-example.json"></a>

```
"Outputs" : {
  "BackupLoadBalancerDNSName" : {
    "Description": "The DNSName of the backup load balancer",  
    "Value" : { "Fn::GetAtt" : [ "BackupLoadBalancer", "DNSName" ]},
    "Condition" : "CreateProdResources"
  },
  "InstanceID" : {
    "Description": "The Instance ID",  
    "Value" : { "Ref" : "EC2Instance" }
  }
}
```

#### YAML
<a name="outputs-section-structure-example.yaml"></a>

```
Outputs:
  BackupLoadBalancerDNSName:
    Description: The DNSName of the backup load balancer
    Value: !GetAtt BackupLoadBalancer.DNSName
    Condition: CreateProdResources
  InstanceID:
    Description: The Instance ID
    Value: !Ref EC2Instance
```

### 使用 `Fn::Sub` 自定义导出名称
<a name="outputs-section-structure-examples-cross-stack"></a>

在以下示例中，名为 `StackVPC` 的输出返回 VPC 的 ID，然后在堆栈名称中附加 `VPCID` 导出跨堆栈引用的值。

#### JSON
<a name="outputs-section-structure-cross-stack-example.json"></a>

```
"Outputs" : {
  "StackVPC" : {
    "Description" : "The ID of the VPC",
    "Value" : { "Ref" : "MyVPC" },
    "Export" : {
      "Name" : {"Fn::Sub": "${AWS::StackName}-VPCID" }
    }
  }
}
```

#### YAML
<a name="outputs-section-structure-cross-stack-example.yaml"></a>

```
Outputs:
  StackVPC:
    Description: The ID of the VPC
    Value: !Ref MyVPC
    Export:
      Name: !Sub "${AWS::StackName}-VPCID"
```

有关 `Fn::Sub` 函数的更多信息，请参阅[https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-sub.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-sub.html)。

### 使用 `Fn::Join` 自定义导出名称
<a name="outputs-section-structure-examples-join-export-name"></a>

还可以使用 `Fn::Join` 函数以根据参数、资源属性和其他字符串来构造值。

以下示例使用 `Fn::Join` 函数而不是 `Fn::Sub` 函数，自定义导出名称。示例 `Fn::Join` 函数将冒号用作分隔符，连接堆栈名称与名称 `VPCID`。

#### JSON
<a name="outputs-section-structure-join-export-name-example.json"></a>

```
"Outputs" : {
  "StackVPC" : {
    "Description" : "The ID of the VPC",
    "Value" : { "Ref" : "MyVPC" },
    "Export" : {
      "Name" : { "Fn::Join" : [ ":", [ { "Ref" : "AWS::StackName" }, "VPCID" ] ] }
    }
  }
}
```

#### YAML
<a name="outputs-section-structure-join-export-name-example.yaml"></a>

```
Outputs:
  StackVPC:
    Description: The ID of the VPC
    Value: !Ref MyVPC
    Export:
      Name: !Join [ ":", [ !Ref "AWS::StackName", VPCID ] ]
```

有关 `Fn::Join` 函数的更多信息，请参阅[https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-join.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-join.html)。

### 返回使用 `Fn::Join` 构造的 URL
<a name="outputs-section-structure-examples-join-export-url"></a>

在以下用于创建 WordPress 网站的模板示例中，`InstallURL` 是 `Fn::Join` 函数调用返回的字符串，该字符串将 `http://`、资源 `ElasticLoadBalancer` 的 DNS 名称和 `/wp-admin/install.php` 连接起来。该输出值可能会与以下值相似：

```
http://mywptests-elasticl-1gb51l6sl8y5v-206169572.aws-region.elb.amazonaws.com/wp-admin/install.php
```

#### JSON
<a name="outputs-section-structure-examples-join-export-url.json"></a>

```
{
    "Outputs": {
        "InstallURL": {
            "Value": {
                "Fn::Join": [
                    "",
                    [
                        "http://",
                        {
                            "Fn::GetAtt": [
                                "ElasticLoadBalancer",
                                "DNSName"
                            ]
                        },
                        "/wp-admin/install.php"
                    ]
                ]
            },
            "Description": "Installation URL of the WordPress website"
        }
    }
}
```

#### YAML
<a name="outputs-section-structure-examples-join-export-url.yaml"></a>

```
Outputs:
  InstallURL:
    Value: !Join 
      - ''
      - - 'http://'
        - !GetAtt 
          - ElasticLoadBalancer
          - DNSName
        - /wp-admin/install.php
    Description: Installation URL of the WordPress website
```

有关 `Fn::Join` 函数的更多信息，请参阅[https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-join.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-join.html)。

# CloudFormation 模板 Mappings 语法
<a name="mappings-section-structure"></a>

您可以借助可选的 `Mappings` 部分来创建键值对，从而可以根据特定条件或依赖项指定值。

`Mappings` 部分的一个常见应用场景是根据部署堆栈的 Amazon Web Services 区域来设置值。这可以通过使用 `AWS::Region` 伪参数来实现。`AWS::Region` 伪参数是 CloudFormation 用来解析到创建堆栈所在区域的值。在创建堆栈时，CloudFormation 解析了这些伪参数。

要检索映射中的值，您可以在模板的 `Resources` 部分中使用 `Fn::FindInMap` 内置函数。

## 语法
<a name="mappings-section-structure-syntax"></a>

`Mappings` 部分使用以下语法：

### JSON
<a name="mappings-section-structure-syntax.json"></a>

```
"Mappings" : {
  "MappingLogicalName" : {
    "Key1" : {
      "Name" : "Value1"
    },
    "Key2" : {
      "Name" : "Value2"
    },
    "Key3" : {
      "Name" : "Value3"
    }
  }
}
```

### YAML
<a name="mappings-section-structure-syntax.yaml"></a>

```
Mappings: 
  MappingLogicalName: 
    Key1: 
      Name: Value1
    Key2: 
      Name: Value2
    Key3: 
      Name: Value3
```
+ `MappingLogicalName` 是映射的逻辑名称。
+ 在映射中，每个映射是一个键，后跟另一个映射。
+ 键必须是名称/值对映射，且在映射中必须唯一。
+ 名值对是一个标签，该值是用来映射的。您可以通过给值命名以将多组值映射到密钥中。
+ 映射中的键必须为文字字符串。
+ 值可以是 `String` 或 `List` 类型。

**注意**  
不得在 `Mappings` 部分包含参数、伪参数或内部函数。  
如果堆栈目前未使用映射中的值，则无法单独更新映射。您必须包含添加、修改或删除资源的更改。

## 示例
<a name="mappings-section-structure-examples"></a>

**Topics**
+ [

### 基本映射
](#mappings-section-structure-basic-example)
+ [

### 带有多个值的映射
](#mappings-section-structure-multiple-values-example)
+ [

### 从映射返回值
](#mappings-section-structure-return-value-example)
+ [

### 输入参数和 `Fn::FindInMap`
](#mappings-section-structure-input-parameter-example)

### 基本映射
<a name="mappings-section-structure-basic-example"></a>

以下示例显示的是带映射 `Mappings` 的 `RegionToInstanceType` 部分，该映射包含五个映射到含单字符串值的名称-值对的密钥。密钥为区域名称。每个名称值对都是该键所表示区域内的 T 系列中可用的一种实例类型。名称值对中有一个名称（示例中的 `InstanceType`）和一个值。

#### JSON
<a name="mappings-section-structure-basic-example.json"></a>

```
"Mappings" : {
  "RegionToInstanceType" : {
    "us-east-1"      : { "InstanceType" : "t2.micro" },
    "us-west-1"      : { "InstanceType" : "t2.micro" },
    "eu-west-1"      : { "InstanceType" : "t2.micro" },
    "eu-north-1"     : { "InstanceType" : "t3.micro" },
    "me-south-1"     : { "InstanceType" : "t3.micro" }
  }
}
```

#### YAML
<a name="mappings-section-structure-basic-example.yaml"></a>

```
Mappings:
  RegionToInstanceType:
    us-east-1:
      InstanceType: t2.micro
    us-west-1:
      InstanceType: t2.micro
    eu-west-1:
      InstanceType: t2.micro
    eu-north-1:
      InstanceType: t3.micro
    me-south-1:
      InstanceType: t3.micro
```

### 带有多个值的映射
<a name="mappings-section-structure-multiple-values-example"></a>

以下示例中的区域键映射到两组值：一组名为 `MyAMI1`，另一组为 `MyAMI2`。

**注意**  
这些示例中显示的 AMI ID 是演示用的占位符。应尽量考虑使用 Amazon Systems Manager 参数的动态引用，作为 `Mappings` 部分的替代方案。要避免每次要使用的 AMI 发生更改时都使用新 ID 来更新所有模板，请在创建或更新堆栈时使用 Amazon Systems Manager 参数来检索最新 AMI ID。常用 AMI 的最新版本也可作为 Systems Manager 中的公有参数提供。有关更多信息，请参阅[使用动态引用获取存储在其他服务中的值](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/dynamic-references.html)。

#### JSON
<a name="mappings-section-structure-multiple-values-example"></a>

```
"Mappings" : {
  "RegionToAMI" : {
    "us-east-1"        : { "MyAMI1" : "ami-12345678901234567", "MyAMI2" : "ami-23456789012345678" },
    "us-west-1"        : { "MyAMI1" : "ami-34567890123456789", "MyAMI2" : "ami-45678901234567890" },
    "eu-west-1"        : { "MyAMI1" : "ami-56789012345678901", "MyAMI2" : "ami-67890123456789012" },
    "ap-southeast-1"   : { "MyAMI1" : "ami-78901234567890123", "MyAMI2" : "ami-89012345678901234" },
    "ap-northeast-1"   : { "MyAMI1" : "ami-90123456789012345", "MyAMI2" : "ami-01234567890123456" }
  }
}
```

#### YAML
<a name="mappings-section-structure-multiple-values-example.yaml"></a>

```
Mappings:
  RegionToAMI:
    us-east-1:
      MyAMI1: ami-12345678901234567
      MyAMI2: ami-23456789012345678
    us-west-1:
      MyAMI1: ami-34567890123456789
      MyAMI2: ami-45678901234567890
    eu-west-1:
      MyAMI1: ami-56789012345678901
      MyAMI2: ami-67890123456789012
    ap-southeast-1:
      MyAMI1: ami-78901234567890123
      MyAMI2: ami-89012345678901234
    ap-northeast-1:
      MyAMI1: ami-90123456789012345
      MyAMI2: ami-01234567890123456
```

### 从映射返回值
<a name="mappings-section-structure-return-value-example"></a>

您可以使用 `Fn::FindInMap` 函数根据指定的密钥返回命名的值。以下示例模板包含由 `FindInMap` 函数分配其 `InstanceType` 属性的 Amazon EC2 资源。`FindInMap` 函数将键指定为创建堆栈的 Amazon Web Services 区域（使用 `AWS::Region` 伪参数），并将 `InstanceType` 指定为要映射到的值的名称。`ImageId` 使用 Systems Manager 参数动态检索最新的 Amazon Linux 2 AMI。有关伪参数的更多信息，请参阅[使用伪参数获取 Amazon 值](pseudo-parameter-reference.md)。

#### JSON
<a name="mappings-section-structure-return-value-example.json"></a>

```
{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Mappings" : {
    "RegionToInstanceType" : {
      "us-east-1"      : { "InstanceType" : "t2.micro" },
      "us-west-1"      : { "InstanceType" : "t2.micro" },
      "eu-west-1"      : { "InstanceType" : "t2.micro" },
      "eu-north-1"     : { "InstanceType" : "t3.micro" },
      "me-south-1"     : { "InstanceType" : "t3.micro" }
    }
  },
  "Resources" : {
    "myEC2Instance" : {
      "Type" : "AWS::EC2::Instance",
      "Properties" : {
        "ImageId" : "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}",
        "InstanceType" : { "Fn::FindInMap" : [ "RegionToInstanceType", { "Ref" : "AWS::Region" }, "InstanceType" ]}
      }
    }
  }
}
```

#### YAML
<a name="mappings-section-structure-return-value-example.yaml"></a>

```
AWSTemplateFormatVersion: 2010-09-09
Mappings: 
  RegionToInstanceType: 
    us-east-1:
      InstanceType: t2.micro
    us-west-1:
      InstanceType: t2.micro
    eu-west-1:
      InstanceType: t2.micro
    eu-north-1:
      InstanceType: t3.micro
    me-south-1:
      InstanceType: t3.micro
Resources: 
  myEC2Instance: 
    Type: AWS::EC2::Instance
    Properties: 
      ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}'
      InstanceType: !FindInMap [RegionToInstanceType, !Ref 'AWS::Region', InstanceType]
```

### 输入参数和 `Fn::FindInMap`
<a name="mappings-section-structure-input-parameter-example"></a>

以下示例模板显示如何使用多个映射来创建 EC2 实例。该模板使用嵌套映射，根据目标 Amazon Web Services 区域 和环境类型（`Dev` 或 `Prod`）自动选择相应的实例类型和安全组。模板还使用 Systems Manager 参数来动态检索最新的 Amazon Linux 2 AMI。

#### JSON
<a name="mappings-section-structure-input-parameter-example.json"></a>

```
{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Parameters" : {
    "EnvironmentType" : {
      "Description" : "The environment type (Dev or Prod)",
      "Type" : "String",
      "Default" : "Dev",
      "AllowedValues" : [ "Dev", "Prod" ]
    }
  },
  "Mappings" : {
    "RegionAndEnvironmentToInstanceType" : {
      "us-east-1"        : { "Dev" : "t3.micro", "Prod" : "c5.large" },
      "us-west-1"        : { "Dev" : "t2.micro", "Prod" : "m5.large" }
    },
    "RegionAndEnvironmentToSecurityGroup" : {
      "us-east-1"        : { "Dev" : "sg-12345678", "Prod" : "sg-abcdef01" },
      "us-west-1"        : { "Dev" : "sg-ghijkl23", "Prod" : "sg-45678abc" }
    }
  },
  "Resources" : {
    "Ec2Instance" : {
      "Type" : "AWS::EC2::Instance",
      "Properties" : {
        "ImageId" : "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}",
        "InstanceType" : { "Fn::FindInMap": [ "RegionAndEnvironmentToInstanceType", { "Ref": "AWS::Region" }, { "Ref": "EnvironmentType" } ]},
        "SecurityGroupIds" : [{ "Fn::FindInMap" : [ "RegionAndEnvironmentToSecurityGroup", { "Ref" : "AWS::Region" }, { "Ref" : "EnvironmentType" } ]}]
      }
    }
  }
}
```

#### YAML
<a name="mappings-section-structure-input-parameter-example.yaml"></a>

```
AWSTemplateFormatVersion: 2010-09-09
Parameters:
  EnvironmentType: 
    Description: The environment type (Dev or Prod)
    Type: String
    Default: Dev
    AllowedValues: 
      - Dev
      - Prod
Mappings:
  RegionAndEnvironmentToInstanceType:
    us-east-1: 
      Dev: t3.micro
      Prod: c5.large
    us-west-1: 
      Dev: t2.micro
      Prod: m5.large
  RegionAndEnvironmentToSecurityGroup: 
    us-east-1: 
      Dev: sg-12345678
      Prod: sg-abcdef01
    us-west-1: 
      Dev: sg-ghijkl23
      Prod: sg-45678abc
Resources:
  Ec2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}'
      InstanceType: !FindInMap [RegionAndEnvironmentToInstanceType, !Ref 'AWS::Region', !Ref EnvironmentType]
      SecurityGroupIds:
        - !FindInMap [RegionAndEnvironmentToSecurityGroup, !Ref 'AWS::Region', !Ref EnvironmentType]
```

## 相关资源
<a name="mappings-section-related-resources"></a>

在开发使用 `Fn::FindInMap` 函数的模板时，这些相关主题可能对您有所帮助。
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-findinmap.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-findinmap.html)
+ [Fn::FindInMap 增强功能](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-findinmap-enhancements.html)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-sub.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-sub.html)

# CloudFormation 模板 Metadata 语法
<a name="metadata-section-structure"></a>

`Metadata` 使用 JSON 或 YAML 对象存储其他信息。您可以在模板中使用的模板级元数据类型包括：

自定义元数据  
存储用户定义的键值对。例如，您可以提供其他信息，这些信息不影响资源创建，但可以提供有关基础设施、团队或部署细节的其他背景信息。

`AWS::CloudFormation::Interface`  
定义在 CloudFormation 控制台中显示输入参数时的分组和排序。默认情况下，CloudFormation 控制台按照参数的逻辑 ID 的字母顺序排序。

`AWS::CloudFormation::Designer`  
Amazon CloudFormation Designer (Designer) 已于 2025 年 2 月 5 日终止使用。



**重要**  
堆栈更新期间，您无法更新 `Metadata` 部分本身。您只能在包括添加、修改或删除资源的更改时更新它。  
CloudFormation 不会转换、修改或编辑您在 `Metadata` 部分中包含的任何信息。因此，我们强烈建议您不要使用此部分存储敏感信息，例如密码或密钥。

## 语法
<a name="metadata-section-structure-syntax"></a>

要在 CloudFormation 模板中声明自定义元数据，请使用以下语法：

### JSON
<a name="metadata-section-structure-syntax.json"></a>

```
"Metadata" : {
  "Instances" : {"Description" : "Information about the instances"},
  "Databases" : {"Description" : "Information about the databases"}
}
```

### YAML
<a name="metadata-section-structure-syntax.yaml"></a>

```
Metadata:
  Instances:
    Description: "Information about the instances"
  Databases: 
    Description: "Information about the databases"
```

有关 `AWS::CloudFormation::Interface` 的语法，请参阅 [使用 `AWS::CloudFormation::Interface` 元数据整理 CloudFormation 参数](aws-cloudformation-interface.md)。

# 使用 `AWS::CloudFormation::Interface` 元数据整理 CloudFormation 参数
<a name="aws-cloudformation-interface"></a>

`AWS::CloudFormation::Interface` 是一种元数据键，用于定义参数在 CloudFormation 控制台中的分组和排序方式。在控制台中创建或更新堆栈时，默认情况下控制台会依照输入参数的逻辑 ID 的字母顺序将其列出。您可以借助此键定义自己的参数分组和排序方法，以便用户高效地指定参数值。例如，您可以将所有 EC2 相关的参数放到一个组中、将所有 VPC 相关的参数放到另一个组中。

在元数据键中，您可以指定要创建的组、每个组包含的参数以及控制台在其分组中显示各个参数时的顺序。

您还可以定义参数标签。标签是控制台显示的易记名称或描述，以代替参数的逻辑 ID。标签可帮助用户了解为每个参数指定的值。例如，您可以将 `KeyPair` 参数标记为 `Select an EC2 key pair`。

在元数据键中引用的所有参数都必须在模板的 `Parameters` 部分中声明。

**注意**  
仅 CloudFormation 控制台使用 `AWS::CloudFormation::Interface` 元数据键。Amazon CLI 和 API 调用不使用此键。

## 语法
<a name="aws-resource-cloudformation-interface-syntax"></a>

要在 CloudFormation 模板中声明此实体，请使用以下语法：

### JSON
<a name="aws-resource-cloudformation-interface-syntax.json"></a>

```
"Metadata" : {
  "AWS::CloudFormation::Interface" : {
    "ParameterGroups": [
      {
        "Label": {
          "default": "Group Label"
        },
        "Parameters": [
          "Parameter1",
          "Parameter2"
        ]
      }
    ],
    "ParameterLabels": {
      "Parameter1": {
        "default": "Friendly Name for Parameter1"
      }
    }
  }
}
```

### YAML
<a name="aws-resource-cloudformation-interface-syntax.yaml"></a>

```
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Group Label
        Parameters:
          - Parameter1
          - Parameter2
    ParameterLabels:
      Parameter1:
        default: Friendly Name for Parameter1
```

## 属性
<a name="w2aac11c23c29c17c17"></a>

`ParameterGroups`  
参数组类型的列表、指定组名称的地方、每个组中的参数以及参数的显示顺序。  
*必需*：否    
`Label`  
参数组的名称。  
*必需*：否  
`default`  
CloudFormation 控制台用于命名参数组的默认标签。  
*必需*：否  
*类型*：字符串  
`Parameters`  
要包含在组中的参数逻辑 ID (区分大小写) 的列表。参数必须已在模板的 `Parameters` 部分中定义。参数只能包含在一个参数组中。  
控制台在 `Other parameters` 组中按字母顺序列出未与参数组关联的参数。  
*必需*：否  
*类型*：字符串值列表

`ParameterLabels`  
创建或更新堆栈时，CloudFormation 控制台显示的参数与易记名称的映射。  
*必需*：否    
参数标签  
参数的标签。标签定义在创建或更新堆栈时 CloudFormation 控制台在 **Specify Parameters** 页面上显示的易记名称或描述。参数标签必须为已在模板的 `Parameters` 部分中声明的有效参数的逻辑 ID（区分大小写）。  
*必需*：否  
`default`  
CloudFormation 控制台用于命名参数的默认标签。  
*必需*：否  
*类型*：字符串

## 示例
<a name="w2aac11c23c29c17c19"></a>

以下示例定义了两个参数组：`Network Configuration` 和 `Amazon EC2 Configuration`。`Network Configuration` 组包含 `VPCID`、`SubnetId` 和 `SecurityGroupID` 参数 (在模板的 `Parameters` 部分中定义，未显示)。参数的列出顺序定义了控制台显示这些参数的顺序，以 `VPCID` 参数开始。以下示例以相似方式分组和排序 `Amazon EC2 Configuration` 参数。

该示例还为 `VPCID` 参数定义了一个标签。控制台将显示**应将此元素部署到哪个 VPC？**，而不是参数的逻辑 ID (`VPCID`)。

### JSON
<a name="aws-cloudformation-interface-example.json"></a>

```
"Metadata" : {
  "AWS::CloudFormation::Interface" : {
    "ParameterGroups" : [
      {
        "Label" : { "default" : "Network Configuration" },
        "Parameters" : [ "VPCID", "SubnetId", "SecurityGroupID" ]
      },
      {
        "Label" : { "default":"Amazon EC2 Configuration" },
        "Parameters" : [ "InstanceType", "KeyName" ]
      }
    ],
    "ParameterLabels" : {
      "VPCID" : { "default" : "Which VPC should this be deployed to?" }
    }
  }
}
```

### YAML
<a name="aws-cloudformation-interface-example.yaml"></a>

```
Metadata: 
  AWS::CloudFormation::Interface: 
    ParameterGroups: 
      - Label: 
          default: "Network Configuration"
        Parameters: 
          - VPCID
          - SubnetId
          - SecurityGroupID
      - Label: 
          default: "Amazon EC2 Configuration"
        Parameters: 
          - InstanceType
          - KeyName
    ParameterLabels: 
      VPCID: 
        default: "Which VPC should this be deployed to?"
```

### 控制台中的参数组
<a name="w2aac11c23c29c17c19c11"></a>

下图展示了使用本示例中的元数据键后，在创建或更新堆栈时控制台如何显示参数组：**控制台中的参数组** 

![\[显示该示例的参数组的控制台。\]](http://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/images/console-create-stack-parameter-groups.png)


# CloudFormation 模板 Rules 语法
<a name="rules-section-structure"></a>

`Rules` 部分是 CloudFormation 模板的可选部分，可启用自定义验证逻辑。如果包含，此部分包含在 CloudFormation 创建或更新任何资源之前验证参数值的规则函数。

当标准参数约束不足时，规则非常有用。例如，如果启用了 SSL，则必须同时提供证书和域名。规则可以确保满足这些依赖关系。

## 语法
<a name="template-constraint-rules-syntax"></a>

`Rules` 部分使用以下语法：

### JSON
<a name="rules-section-structure-syntax.json"></a>

模板的`Rules` 部分由后跟冒号的密钥名称 `Rules` 组成。必须使用括号将所有规则声明括起来。如果您声明多个规则，则可用逗号将它们分隔开。对于每个规则，您必须声明一个用引号引起来的逻辑名称，后跟冒号以及将规则条件和断言括起来的括号。

```
{
    "Rules": {
        "LogicalRuleName1": {
            "RuleCondition": {
                "rule-specific intrinsic function": "Value"
            },
            "Assertions": [
                {
                    "Assert": {
                        "rule-specific intrinsic function": "Value"
                    },
                    "AssertDescription": "Information about this assert"
                },
                {
                    "Assert": {
                        "rule-specific intrinsic function": "Value"
                    },
                    "AssertDescription": "Information about this assert"
                }
            ]
        },
        "LogicalRuleName2": {
            "Assertions": [
                {
                    "Assert": {
                        "rule-specific intrinsic function": "Value"
                    },
                    "AssertDescription": "Information about this assert"
                }
            ]
        }
    }
}
```

### YAML
<a name="rules-section-structure-syntax.yaml"></a>

```
Rules:
  LogicalRuleName1:
    RuleCondition:
      rule-specific intrinsic function: Value
    Assertions:
      - Assert:
          rule-specific intrinsic function: Value
        AssertDescription: Information about this assert
      - Assert:
          rule-specific intrinsic function: Value
        AssertDescription: Information about this assert
  LogicalRuleName2:
    Assertions:
      - Assert:
          rule-specific intrinsic function: Value
        AssertDescription: Information about this assert
```

### 规则字段
<a name="rules-section-fields"></a>

`Rules` 部分包含以下字段。

**逻辑 ID（也称为*逻辑名称*）**  
每条规则的唯一标识符。

**`RuleCondition`（可选）**  
确定规则生效时间的属性。如果您未定义规则条件，则规则的断言始终生效。对于每个规则，您只能定义一个规则条件。

**`Assertions`（必需）**  
指定特定参数可接受值的一条或多条语句。

**`Assert`**  
必须计算为 `true` 的条件。

**`AssertDescription`**  
断言失败时显示的消息。

## 特定于规则的内部函数
<a name="rules-specific-intrinsic-section-structure"></a>

要定义规则，您必须使用*特定于规则的函数*，只能在模板的 `Rules` 部分中使用这些函数。虽然可以嵌套这些函数，但规则条件或断言的最终结果必须为 `true` 或 `false`。

以下规则函数可用：
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-and](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-and)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-rules.html#fn-contains](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-rules.html#fn-contains)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-rules.html#fn-eachmemberequals](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-rules.html#fn-eachmemberequals)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-rules.html#fn-eachmemberin](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-rules.html#fn-eachmemberin)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-equals](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-equals)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-if](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-if)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-not](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-not)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-or](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-or)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-rules.html#fn-refall](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-rules.html#fn-refall)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-rules.html#fn-valueof](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-rules.html#fn-valueof)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-rules.html#fn-valueofall](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-rules.html#fn-valueofall)

这些函数在规则的条件或断言中使用。条件属性确定 CloudFormation 是否应用断言。如果条件的计算结果为 `true`，则 CloudFormation 将评估断言以验证在创建或更新预配置产品时参数值是否有效。如果参数值无效，则 CloudFormation 不会创建或更新堆栈。如果条件的计算结果为 `false`，则 CloudFormation 不会检查参数值并继续堆栈操作。

## 示例
<a name="template-constraint-rules-example"></a>

**Topics**
+ [

### 按条件验证参数值
](#template-constraint-rules-example-verify)
+ [

### 交叉参数验证
](#template-cross-parameter-rules-example)

### 按条件验证参数值
<a name="template-constraint-rules-example-verify"></a>

在以下示例中，两个规则检查 `InstanceType` 参数的值。根据环境参数（`test` 或 `prod`）的值，用户必须为 `InstanceType` 参数指定 `t3.medium` 或 `t3.large`。必须在同一模板的 `InstanceType` 部分中声明 `Environment` 和 `Parameters` 参数。

#### JSON
<a name="rules-section-example-conditionally-verify.json"></a>

```
{
  "Rules": {
    "testInstanceType": {
      "RuleCondition": {
        "Fn::Equals": [
          {"Ref": "Environment"},
          "test"
        ]
      },
      "Assertions": [
        {
          "Assert": {
            "Fn::Contains": [
              ["t3.medium"],
              {"Ref": "InstanceType"}
            ]
          },
          "AssertDescription": "For a test environment, the instance type must be t3.medium"
        }
      ]
    },
    "prodInstanceType": {
      "RuleCondition": {
        "Fn::Equals": [
          {"Ref": "Environment"},
          "prod"
        ]
      },
      "Assertions": [
        {
          "Assert": {
            "Fn::Contains": [
              ["t3.large"],
              {"Ref": "InstanceType"}
            ]
          },
          "AssertDescription": "For a production environment, the instance type must be t3.large"
        }
      ]
    }
  }
}
```

#### YAML
<a name="rules-section-example-conditionally-verify.yaml"></a>

```
Rules:
  testInstanceType:
    RuleCondition: !Equals 
      - !Ref Environment
      - test
    Assertions:
      - Assert:
          'Fn::Contains':
            - - t3.medium
            - !Ref InstanceType
        AssertDescription: 'For a test environment, the instance type must be t3.medium'
  prodInstanceType:
    RuleCondition: !Equals 
      - !Ref Environment
      - prod
    Assertions:
      - Assert:
          'Fn::Contains':
            - - t3.large
            - !Ref InstanceType
        AssertDescription: 'For a production environment, the instance type must be t3.large'
```

### 交叉参数验证
<a name="template-cross-parameter-rules-example"></a>

以下示例模板演示如何使用规则进行跨参数验证。其创建了一个在负载均衡器背后自动扩缩组上运行的示例网站。根据输入参数，该网站可在端口 80 或 443 上使用。可以将自动扩缩组中的实例配置为在任何端口上侦听（默认为 8888）。

此模板中的规则会在创建堆栈之前验证输入参数。其验证所有子网是否属于指定的 VPC，并确保将 `UseSSL` 参数设置为 `Yes` 时，同时提供 SSL 证书 ARN 和托管区域名称。

**注意**  
如果您通过本模板创建堆栈，则需为使用的 Amazon 资源支付相应费用。

#### JSON
<a name="rules-section-example-cross-parameter-validation.json"></a>

```
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Parameters": {
    "VpcId": {
      "Type": "AWS::EC2::VPC::Id",
      "Description": "VpcId of your existing Virtual Private Cloud (VPC)",
      "ConstraintDescription": "must be the VPC Id of an existing Virtual Private Cloud."
    },
    "Subnets": {
      "Type": "List<AWS::EC2::Subnet::Id>",
      "Description": "The list of SubnetIds in your Virtual Private Cloud (VPC)",
      "ConstraintDescription": "must be a list of at least two existing subnets associated with at least two different availability zones."
    },
    "InstanceType": {
      "Description": "WebServer EC2 instance type",
      "Type": "String",
      "Default": "t2.micro",
      "AllowedValues": ["t2.micro", "t3.micro"],
      "ConstraintDescription": "must be a valid EC2 instance type."
    },
    "KeyName": {
      "Description": "Name of an existing EC2 KeyPair to enable SSH access to the instances",
      "Type": "AWS::EC2::KeyPair::KeyName",
      "ConstraintDescription": "must be the name of an existing EC2 KeyPair."
    },
    "SSHLocation": {
      "Description": "The IP address range that can be used to SSH to the EC2 instances",
      "Type": "String",
      "MinLength": "9",
      "MaxLength": "18",
      "Default": "0.0.0.0/0",
      "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
      "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
    },
    "UseSSL": {
      "AllowedValues": ["Yes", "No"],
      "Default": "No",
      "Description": "Select \"Yes\" to implement SSL, \"No\" to skip (default).",
      "Type": "String"
    },
    "ALBSSLCertificateARN": {
      "Default": "",
      "Description": "[Optional] The ARN of the SSL certificate to be used for the Application Load Balancer",
      "Type": "String"
    },
    "HostedZoneName": {
      "AllowedPattern": "^$|(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$",
      "Default": "",
      "Description": "[Optional] The domain name of a valid Hosted Zone on AWS.",
      "Type": "String"
    }
  },
  "Conditions": {
    "UseALBSSL": {"Fn::Equals": [{"Ref": "UseSSL"}, "Yes"]}
  },
  "Rules": {
    "SubnetsInVPC": {
      "Assertions": [
        {
          "Assert": {"Fn::EachMemberEquals": [{"Fn::ValueOf": ["Subnets", "VpcId"]}, {"Ref": "VpcId"}]},
          "AssertDescription": "All subnets must be in the VPC"
        }
      ]
    },
    "ValidateHostedZone": {
      "RuleCondition": {"Fn::Equals": [{"Ref": "UseSSL"}, "Yes"]},
      "Assertions": [
        {
          "Assert": {"Fn::Not": [{"Fn::Equals": [{"Ref": "ALBSSLCertificateARN"}, ""]}]},
          "AssertDescription": "ACM Certificate value cannot be empty if SSL is required"
        },
        {
          "Assert": {"Fn::Not": [{"Fn::Equals": [{"Ref": "HostedZoneName"}, ""]}]},
          "AssertDescription": "Route53 Hosted Zone Name is mandatory when SSL is required"
        }
      ]
    }
  },
  "Resources": {
    "WebServerGroup": {
      "Type": "AWS::AutoScaling::AutoScalingGroup",
      "Properties": {
        "VPCZoneIdentifier": {"Ref": "Subnets"},
        "LaunchTemplate": {
          "LaunchTemplateId": {"Ref": "LaunchTemplate"},
          "Version": {"Fn::GetAtt": ["LaunchTemplate","LatestVersionNumber"]}
        },
        "MinSize": "2",
        "MaxSize": "2",
        "TargetGroupARNs": [{"Ref": "ALBTargetGroup"}]
      },
      "CreationPolicy": {
        "ResourceSignal": {"Timeout": "PT15M"}
      },
      "UpdatePolicy": {
        "AutoScalingRollingUpdate": {
          "MinInstancesInService": "1",
          "MaxBatchSize": "1",
          "PauseTime": "PT15M",
          "WaitOnResourceSignals": true
        }
      }
    },
    "LaunchTemplate": {
      "Type": "AWS::EC2::LaunchTemplate",
      "Metadata": {
        "Comment": "Install a simple application",
        "AWS::CloudFormation::Init": {
          "config": {
            "packages": {"yum": {"httpd": []}},
            "files": {
              "/var/www/html/index.html": {
                "content": {"Fn::Join": ["\n", ["<h1>Congratulations, you have successfully launched the AWS CloudFormation sample.</h1>"]]},
                "mode": "000644",
                "owner": "root",
                "group": "root"
              },
              "/etc/cfn/cfn-hup.conf": {
                "content": {"Fn::Join": ["", [
                  "[main]\n",
                  "stack=", {"Ref": "AWS::StackId"}, "\n",
                  "region=", {"Ref": "AWS::Region"}, "\n"
                ]]},
                "mode": "000400",
                "owner": "root",
                "group": "root"
              },
              "/etc/cfn/hooks.d/cfn-auto-reloader.conf": {
                "content": {"Fn::Join": ["", [
                  "[cfn-auto-reloader-hook]\n",
                  "triggers=post.update\n",
                  "path=Resources.LaunchTemplate.Metadata.AWS::CloudFormation::Init\n",
                  "action=/opt/aws/bin/cfn-init -v ",
                  "         --stack ", {"Ref": "AWS::StackName"},
                  "         --resource LaunchTemplate ",
                  "         --region ", {"Ref": "AWS::Region"}, "\n",
                  "runas=root\n"
                ]]},
                "mode": "000400",
                "owner": "root",
                "group": "root"
              }
            },
            "services": {
              "sysvinit": {
                "httpd": {
                  "enabled": "true",
                  "ensureRunning": "true"
                },
                "cfn-hup": {
                  "enabled": "true",
                  "ensureRunning": "true",
                  "files": [
                    "/etc/cfn/cfn-hup.conf",
                    "/etc/cfn/hooks.d/cfn-auto-reloader.conf"
                  ]
                }
              }
            }
          }
        }
      },
      "Properties": {
        "LaunchTemplateName": {"Fn::Sub": "${AWS::StackName}-launch-template"},
        "LaunchTemplateData": {
          "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}",
          "SecurityGroupIds": [{"Ref": "InstanceSecurityGroup"}],
          "InstanceType": {"Ref": "InstanceType"},
          "KeyName": {"Ref": "KeyName"},
          "UserData": {
            "Fn::Base64": {"Fn::Join": ["", [
              "#!/bin/bash\n",
              "yum install -y aws-cfn-bootstrap\n",
              "/opt/aws/bin/cfn-init -v ",
              "         --stack ", {"Ref": "AWS::StackName"},
              "         --resource LaunchTemplate ",
              "         --region ", {"Ref": "AWS::Region"}, "\n",
              "/opt/aws/bin/cfn-signal -e $? ",
              "         --stack ", {"Ref": "AWS::StackName"},
              "         --resource WebServerGroup ",
              "         --region ", {"Ref": "AWS::Region"}, "\n"
            ]]}
          }
        }
      }
    },
    "ELBSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupDescription": "Allow access to the ELB",
        "VpcId": {"Ref": "VpcId"},
        "SecurityGroupIngress": [{
          "Fn::If": [
            "UseALBSSL",
            {
              "IpProtocol": "tcp",
              "FromPort": 443,
              "ToPort": 443,
              "CidrIp": "0.0.0.0/0"
            },
            {
              "IpProtocol": "tcp",
              "FromPort": 80,
              "ToPort": 80,
              "CidrIp": "0.0.0.0/0"
            }
          ]
        }]
      }
    },
    "ApplicationLoadBalancer": {
      "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
      "Properties": {
        "Subnets": {"Ref": "Subnets"},
        "SecurityGroups": [{"Ref": "ELBSecurityGroup"}]
      }
    },
    "ALBListener": {
      "Type": "AWS::ElasticLoadBalancingV2::Listener",
      "Properties": {
        "DefaultActions": [{
          "Type": "forward",
          "TargetGroupArn": {"Ref": "ALBTargetGroup"}
        }],
        "LoadBalancerArn": {"Ref": "ApplicationLoadBalancer"},
        "Port": {"Fn::If": ["UseALBSSL", 443, 80]},
        "Protocol": {"Fn::If": ["UseALBSSL", "HTTPS", "HTTP"]},
        "Certificates": [{
          "Fn::If": [
            "UseALBSSL",
            {"CertificateArn": {"Ref": "ALBSSLCertificateARN"}},
            {"Ref": "AWS::NoValue"}
          ]
        }]
      }
    },
    "ALBTargetGroup": {
      "Type": "AWS::ElasticLoadBalancingV2::TargetGroup",
      "Properties": {
        "HealthCheckIntervalSeconds": 30,
        "HealthCheckTimeoutSeconds": 5,
        "HealthyThresholdCount": 3,
        "Port": 80,
        "Protocol": "HTTP",
        "UnhealthyThresholdCount": 5,
        "VpcId": {"Ref": "VpcId"}
      }
    },
    "InstanceSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupDescription": "Enable SSH access and HTTP access on the inbound port",
        "SecurityGroupIngress": [
          {
            "IpProtocol": "tcp",
            "FromPort": 80,
            "ToPort": 80,
            "SourceSecurityGroupId": {"Fn::Select": [0, {"Fn::GetAtt": ["ApplicationLoadBalancer", "SecurityGroups"]}]}
          },
          {
            "IpProtocol": "tcp",
            "FromPort": 22,
            "ToPort": 22,
            "CidrIp": {"Ref": "SSHLocation"}
          }
        ],
        "VpcId": {"Ref": "VpcId"}
      }
    },
    "RecordSet": {
      "Type": "AWS::Route53::RecordSetGroup",
      "Condition": "UseALBSSL",
      "Properties": {
        "HostedZoneName": {"Fn::Join": ["", [{"Ref": "HostedZoneName"}, "."]]},
        "RecordSets": [{
          "Name": {"Fn::Join": ["", [
            {"Fn::Select": ["0", {"Fn::Split": [".", {"Fn::GetAtt": ["ApplicationLoadBalancer", "DNSName"]}]}]},
            ".",
            {"Ref": "HostedZoneName"},
            "."
          ]]},
          "Type": "A",
          "AliasTarget": {
            "DNSName": {"Fn::GetAtt": ["ApplicationLoadBalancer", "DNSName"]},
            "EvaluateTargetHealth": true,
            "HostedZoneId": {"Fn::GetAtt": ["ApplicationLoadBalancer", "CanonicalHostedZoneID"]}
          }
        }]
      }
    }
  },
  "Outputs": {
    "URL": {
      "Description": "URL of the website",
      "Value": {"Fn::Join": ["", [
        {"Fn::If": [
          "UseALBSSL",
          {"Fn::Join": ["", [
            "https://",
            {"Fn::Join": ["", [
              {"Fn::Select": ["0", {"Fn::Split": [".", {"Fn::GetAtt": ["ApplicationLoadBalancer", "DNSName"]}]}]},
              ".",
              {"Ref": "HostedZoneName"},
              "."
            ]]}
          ]]},
          {"Fn::Join": ["", [
            "http://",
            {"Fn::GetAtt": ["ApplicationLoadBalancer", "DNSName"]}
          ]]}
        ]}
      ]]}
    }
  }
}
```

#### YAML
<a name="rules-section-example-syntax.yaml"></a>

```
AWSTemplateFormatVersion: 2010-09-09
Parameters:
  VpcId:
    Type: AWS::EC2::VPC::Id
    Description: VpcId of your existing Virtual Private Cloud (VPC)
    ConstraintDescription: must be the VPC Id of an existing Virtual Private Cloud.
  Subnets:
    Type: List<AWS::EC2::Subnet::Id>
    Description: The list of SubnetIds in your Virtual Private Cloud (VPC)
    ConstraintDescription: >-
      must be a list of at least two existing subnets associated with at least
      two different availability zones. They should be residing in the selected
      Virtual Private Cloud.
  InstanceType:
    Description: WebServer EC2 instance type
    Type: String
    Default: t2.micro
    AllowedValues:
      - t2.micro
      - t3.micro
    ConstraintDescription: must be a valid EC2 instance type.
  KeyName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instances
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription: must be the name of an existing EC2 KeyPair.
  SSHLocation:
    Description: The IP address range that can be used to SSH to the EC2 instances
    Type: String
    MinLength: '9'
    MaxLength: '18'
    Default: 0.0.0.0/0
    AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})'
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
  UseSSL:
    AllowedValues:
      - 'Yes'
      - 'No'
    ConstraintDescription: Select Yes to create a HTTPS Listener
    Default: 'No'
    Description: 'Select "Yes" to implement SSL, "No" to skip (default).'
    Type: String
  ALBSSLCertificateARN:
    Default: ''
    Description: >-
      [Optional] The ARN of the SSL certificate to be used for the Application
      Load Balancer
    Type: String
  HostedZoneName:
    AllowedPattern: >-
      ^$|(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$
    Default: ''
    Description: '[Optional] The domain name of a valid Hosted Zone on AWS.'
    Type: String
Conditions:
  UseALBSSL: !Equals 
    - !Ref UseSSL
    - 'Yes'
Rules:
  SubnetsInVPC:
    Assertions:
      - Assert:
          'Fn::EachMemberEquals':
            - 'Fn::ValueOf':
                - Subnets
                - VpcId
            - Ref: VpcId
        AssertDescription: All subnets must be in the VPC
  ValidateHostedZone:
    RuleCondition: !Equals 
      - !Ref UseSSL
      - 'Yes'
    Assertions:
      - Assert: !Not 
          - !Equals 
            - !Ref ALBSSLCertificateARN
            - ''
        AssertDescription: ACM Certificate value cannot be empty if SSL is required
      - Assert: !Not 
          - !Equals 
            - !Ref HostedZoneName
            - ''
        AssertDescription: Route53 Hosted Zone Name is mandatory when SSL is required
Resources:
  WebServerGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      VPCZoneIdentifier: !Ref Subnets
      LaunchTemplate:
        LaunchTemplateId: !Ref LaunchTemplate
        Version: !GetAtt LaunchTemplate.LatestVersionNumber
      MinSize: '2'
      MaxSize: '2'
      TargetGroupARNs:
        - !Ref ALBTargetGroup
    CreationPolicy:
      ResourceSignal:
        Timeout: PT15M
    UpdatePolicy:
      AutoScalingRollingUpdate:
        MinInstancesInService: '1'
        MaxBatchSize: '1'
        PauseTime: PT15M
        WaitOnResourceSignals: 'true'
  LaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Metadata:
      Comment: Install a simple application
      AWS::CloudFormation::Init:
        config:
          packages:
            yum:
              httpd: []
          files:
            /var/www/html/index.html:
              content: !Join 
                - |+
                - - >-
                    <h1>Congratulations, you have successfully launched the AWS
                    CloudFormation sample.</h1>
              mode: '000644'
              owner: root
              group: root
            /etc/cfn/cfn-hup.conf:
              content: !Sub |
                [main]
                stack=${AWS::StackId}
                region=${AWS::Region}
              mode: '000400'
              owner: root
              group: root
            /etc/cfn/hooks.d/cfn-auto-reloader.conf:
              content: !Sub |-
                [cfn-auto-reloader-hook]
                triggers=post.update
                path=Resources.LaunchTemplate.Metadata.AWS::CloudFormation::Init
                action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchTemplate --region ${AWS::Region}
                runas=root
              mode: '000400'
              owner: root
              group: root
          services:
            sysvinit:
              httpd:
                enabled: 'true'
                ensureRunning: 'true'
              cfn-hup:
                enabled: 'true'
                ensureRunning: 'true'
                files:
                  - /etc/cfn/cfn-hup.conf
                  - /etc/cfn/hooks.d/cfn-auto-reloader.conf
    Properties:
      LaunchTemplateName: !Sub ${AWS::StackName}-launch-template
      LaunchTemplateData:
        ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}'
        SecurityGroupIds:
        - !Ref InstanceSecurityGroup
        InstanceType: !Ref InstanceType
        KeyName: !Ref KeyName
        UserData: !Base64
          Fn::Sub: |
            #!/bin/bash
            yum install -y aws-cfn-bootstrap
            /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchTemplate --region ${AWS::Region}
            /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerGroup --region ${AWS::Region}
  ELBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow access to the ELB
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - !If 
          - UseALBSSL
          - IpProtocol: tcp
            FromPort: 443
            ToPort: 443
            CidrIp: 0.0.0.0/0
          - IpProtocol: tcp
            FromPort: 80
            ToPort: 80
            CidrIp: 0.0.0.0/0
  ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Subnets: !Ref Subnets
      SecurityGroups:
        - !Ref ELBSecurityGroup
  ALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref ALBTargetGroup
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: !If
        - UseALBSSL
        - 443
        - 80
      Protocol: !If 
        - UseALBSSL
        - HTTPS
        - HTTP
      Certificates:
        - !If 
          - UseALBSSL
          - CertificateArn: !Ref ALBSSLCertificateARN
          - !Ref 'AWS::NoValue'
  ALBTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 30
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 3
      Port: 80
      Protocol: HTTP
      UnhealthyThresholdCount: 5
      VpcId: !Ref VpcId
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable SSH access and HTTP access on the inbound port
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Select 
            - 0
            - !GetAtt 
              - ApplicationLoadBalancer
              - SecurityGroups
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref SSHLocation
      VpcId: !Ref VpcId
  RecordSet:
    Type: AWS::Route53::RecordSetGroup
    Condition: UseALBSSL
    Properties:
      HostedZoneName: !Join 
        - ''
        - - !Ref HostedZoneName
          - .
      RecordSets:
        - Name: !Join 
            - ''
            - - !Select 
                - '0'
                - !Split 
                  - .
                  - !GetAtt 
                    - ApplicationLoadBalancer
                    - DNSName
              - .
              - !Ref HostedZoneName
              - .
          Type: A
          AliasTarget:
            DNSName: !GetAtt 
              - ApplicationLoadBalancer
              - DNSName
            EvaluateTargetHealth: true
            HostedZoneId: !GetAtt 
              - ApplicationLoadBalancer
              - CanonicalHostedZoneID
Outputs:
  URL:
    Description: URL of the website
    Value: !Join 
      - ''
      - - !If 
          - UseALBSSL
          - !Join 
            - ''
            - - 'https://'
              - !Join 
                - ''
                - - !Select 
                    - '0'
                    - !Split 
                      - .
                      - !GetAtt 
                        - ApplicationLoadBalancer
                        - DNSName
                  - .
                  - !Ref HostedZoneName
                  - .
          - !Join 
            - ''
            - - 'http://'
              - !GetAtt 
                - ApplicationLoadBalancer
                - DNSName
```

# CloudFormation 模板 Conditions 语法
<a name="conditions-section-structure"></a>

可选的 `Conditions` 部分包含一些声明，以定义在哪些情况下创建或配置实体。例如，您可以创建一个条件，然后将其与某个资源或输出关联，以便 CloudFormation 仅在该条件成立时创建该资源或输出。同样，您可以将条件与一个属性关联，以便 CloudFormation 仅在该条件为 true 时将该属性设置为特定的值。如果该条件为 false，则 CloudFormation 会将该属性设置为您指定的其他值。

当您需要重新使用模板在不同环境（如测试环境与生产环境）中创建资源时，可以使用条件。例如，在模板中，您可以添加 `EnvironmentType` 输入参数，它接受 `prod` 或 `test` 以作为输入。对于 `prod` 环境，您可以采用带特定功能的 EC2 实例；但对于 `test` 环境，您可以使用更少功能，以便节约资金。通过定义条件，您可以定义为每个环境类型创建哪些资源以及如何配置资源。

## 语法
<a name="conditions-section-structure-syntax"></a>

`Conditions` 部分包括键名称 `Conditions`。每个条件声明均包括一个逻辑 ID 和多个内置函数。

### JSON
<a name="conditions-section-structure-syntax.json"></a>

```
"Conditions": {
  "LogicalConditionName1": {
    "Intrinsic function": ...[
  },

  "LogicalConditionName2": {
    "Intrinsic function": ...
  }
}
```

### YAML
<a name="conditions-section-structure-syntax.yaml"></a>

```
Conditions:
  LogicalConditionName1:
    Intrinsic function:
      ...

  LogicalConditionName2:
    Intrinsic function:
      ...
```

## 条件的工作原理
<a name="conditions-section-structure-overview"></a>

要使用条件，请按照下列步骤操作：

1. **添加参数定义**：定义条件在模板 `Parameters` 部分中进行评估的输入。根据这些输入参数的值，条件评估结果为 true 或 false。请注意，伪参数是自动可用的，不需要在 `Parameters` 部分中进行明确定义。有关伪参数的更多信息，请参阅[使用伪参数获取 Amazon 值](pseudo-parameter-reference.md)。

1. **添加条件定义**：使用内置函数（例如 `Fn::If` 或 `Fn::Equals`）在 `Conditions` 部分中定义条件。这些条件将决定 CloudFormation 何时创建关联的资源。条件可以基于：
   + 输入或伪参数值
   + 其他条件
   + 映射值

   但是，您不能在条件中引用资源逻辑 ID 或其属性。

1. **将条件与资源或输出关联**：使用 `Condition` 键和条件的逻辑 ID 在资源或输出中引用条件。或者，也可以在模板的其他部分（例如属性值）中使用 `Fn::If` 以根据条件设置值。有关更多信息，请参阅 [使用 `Condition` 密钥](#using-conditions-in-templates)。

在创建或更新堆栈时，CloudFormation 会评估条件。CloudFormation 创建与成立的条件关联的实体，并忽略与不成立的条件关联的实体。在每个堆栈更新期间，CloudFormation 还会在修改任何资源之前重新评估这些条件。与 true 条件关联的实体将会更新，与 false 条件关联的实体将会删除。

**重要**  
堆栈更新期间，您无法更新条件本身。您只能在包含添加、修改或删除资源的更改时更新条件。

## 条件内部函数
<a name="conditions-section-structure-functions"></a>

您可以使用以下内部函数定义条件：
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-and](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-and)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-equals](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-equals)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-foreach.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-foreach.html)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-if](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-if)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-not](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-not)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-or](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-or)

**注意**  
仅在模板的 `Resources` 和 `Outputs` 部分中的元数据属性、更新策略属性和属性值中支持 `Fn::If`。

## 使用 `Condition` 密钥
<a name="using-conditions-in-templates"></a>

定义条件后，您可以使用 `Condition` 密钥将其应用于模板中的多个位置，例如 `Resources` 和 `Outputs`。`Condition` 密钥引用条件的逻辑名称并返回指定条件的评估结果。

**Topics**
+ [

### 将条件与资源关联
](#associate-conditions-with-resources)
+ [

### 将条件与输出关联
](#associate-conditions-with-outputs)
+ [

### 其他条件中的引用条件
](#reference-conditions-in-other-conditions)
+ [

### 使用 `Fn::If` 有条件地返回属性值
](#conditional-return-property-values-using-fn-if)

### 将条件与资源关联
<a name="associate-conditions-with-resources"></a>

要有条件地创建资源，请添加 `Condition` 密钥，并将条件的逻辑 ID 作为属性添加到该资源中。仅当 条件评估为 true 时，CloudFormation 才会创建 资源。

#### JSON
<a name="associate-conditions-with-resources.json"></a>

```
"NewVolume" : {
  "Type" : "AWS::EC2::Volume",
  "Condition" : "IsProduction",
  "Properties" : {
     "Size" : "100",
     "AvailabilityZone" : { "Fn::GetAtt" : [ "EC2Instance", "AvailabilityZone" ]}
  }
}
```

#### YAML
<a name="associate-conditions-with-resources.yaml"></a>

```
NewVolume:
  Type: AWS::EC2::Volume
  Condition: IsProduction
  Properties:
    Size: 100
    AvailabilityZone: !GetAtt EC2Instance.AvailabilityZone
```

### 将条件与输出关联
<a name="associate-conditions-with-outputs"></a>

您还可以将条件与输出关联。仅当关联条件的评估结果为 true 时，CloudFormation 才会创建输出。

#### JSON
<a name="associate-conditions-with-outputs.json"></a>

```
"Outputs" : {
  "VolumeId" : {
    "Condition" : "IsProduction",
    "Value" : { "Ref" : "NewVolume" }
  }
}
```

#### YAML
<a name="associate-conditions-with-outputs.yaml"></a>

```
Outputs:
  VolumeId:
    Condition: IsProduction
    Value: !Ref NewVolume
```

### 其他条件中的引用条件
<a name="reference-conditions-in-other-conditions"></a>

在 `Conditions` 部分中定义条件时，可以使用 `Condition` 密钥引用其他条件。这使您能够通过组合多个条件来创建更复杂的条件逻辑。

在以下示例中，仅当 `IsProduction` 和 `IsProdAndFeatureEnabled` 条件的评估结果为 true 时，`IsFeatureEnabled` 条件才会评估为 true。

#### JSON
<a name="reference-conditions-in-other-conditions.json"></a>

```
"Conditions": {
  "IsProduction" : {"Fn::Equals" : [{"Ref" : "Environment"}, "prod"]},
  "IsFeatureEnabled" : { "Fn::Equals" : [{"Ref" : "FeatureFlag"}, "enabled"]},
  "IsProdAndFeatureEnabled" : {
    "Fn::And" : [
      {"Condition" : "IsProduction"},
      {"Condition" : "IsFeatureEnabled"}
    ]
  }
}
```

#### YAML
<a name="reference-conditions-in-other-conditions.yaml"></a>

```
Conditions:
  IsProduction:
    !Equals [!Ref Environment, "prod"]
  IsFeatureEnabled:
    !Equals [!Ref FeatureFlag, "enabled"]
  IsProdAndFeatureEnabled: !And
    - !Condition IsProduction
    - !Condition IsFeatureEnabled
```

### 使用 `Fn::If` 有条件地返回属性值
<a name="conditional-return-property-values-using-fn-if"></a>

要进行更精细的控制，您可以使用 `Fn::If` 内置函数有条件地返回资源或输出中的两个属性值之一。该函数会对条件进行评估，如果条件为 true，则返回一个值；如果条件为 false，则返回另一个值。

#### 条件属性值
<a name="using-fn-if-for-conditional-values"></a>

以下示例演示了如何根据环境条件设置 EC2 实例类型。如果 `IsProduction` 条件的评估结果为 true，则实例类型设置为 `c5.xlarge`。否则，该值将设置为 `t3.small`。

##### JSON
<a name="using-fn-if-for-conditional-values.json"></a>

```
"Properties" : {
  "InstanceType" : {
    "Fn::If" : [
      "IsProduction",
      "c5.xlarge",
      "t3.small"
    ]
  }
}
```

##### YAML
<a name="using-fn-if-for-conditional-values.yaml"></a>

```
Properties:
  InstanceType: !If
    - IsProduction
    - c5.xlarge
    - t3.small
```

#### 条件属性移除
<a name="using-fn-if-with-novalue"></a>

您也可以使用 `AWS::NoValue` 伪参数名称】作为返回值，在条件为 false 时移除对应的属性。

##### JSON
<a name="using-fn-if-with-novalue.json"></a>

```
"DBSnapshotIdentifier" : {
  "Fn::If" : [
    "UseDBSnapshot",
    {"Ref" : "DBSnapshotName"},
    {"Ref" : "AWS::NoValue"}
  ]
}
```

##### YAML
<a name="using-fn-if-with-novalue.yaml"></a>

```
DBSnapshotIdentifier: !If
  - UseDBSnapshot
  - !Ref DBSnapshotName
  - !Ref "AWS::NoValue"
```

## 示例
<a name="conditions-section-structure-examples"></a>

**Topics**
+ [

### 基于环境创建资源
](#environment-based-resource-creation)
+ [

### 多条件资源预置
](#multi-condition-resource-provisioning)

### 基于环境创建资源
<a name="environment-based-resource-creation"></a>

以下示例将预置一个 EC2 实例，并且仅当环境类型为 `prod` 时，才会有条件地创建和附加新的 EBS 卷。如果环境是 `test`，示例则只会创建不带额外卷的 EC2 实例。

#### JSON
<a name="conditions-section-example-resource-creation.json"></a>

```
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Parameters": {
        "EnvType": {
            "Description": "Environment type",
            "Default": "test",
            "Type": "String",
            "AllowedValues": [
                "prod",
                "test"
            ],
            "ConstraintDescription": "must specify prod or test"
        }
    },
    "Conditions": {
        "IsProduction": {
            "Fn::Equals": [
                {
                    "Ref": "EnvType"
                },
                "prod"
            ]
        }
    },
    "Resources": {
        "EC2Instance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": "ami-1234567890abcdef0",
                "InstanceType": "c5.xlarge"
            }
        },
        "MountPoint": {
            "Type": "AWS::EC2::VolumeAttachment",
            "Condition": "IsProduction",
            "Properties": {
                "InstanceId": {
                    "Ref": "EC2Instance"
                },
                "VolumeId": {
                    "Ref": "NewVolume"
                },
                "Device": "/dev/sdh"
            }
        },
        "NewVolume": {
            "Type": "AWS::EC2::Volume",
            "Condition": "IsProduction",
            "Properties": {
                "Size": 100,
                "AvailabilityZone": {
                    "Fn::GetAtt": [
                        "EC2Instance",
                        "AvailabilityZone"
                    ]
                }
            }
        }
    }
}
```

#### YAML
<a name="conditions-section-example-resource-creation.yaml"></a>

```
AWSTemplateFormatVersion: 2010-09-09
Parameters:
  EnvType:
    Description: Environment type
    Default: test
    Type: String
    AllowedValues:
      - prod
      - test
    ConstraintDescription: must specify prod or test
Conditions:
  IsProduction: !Equals
    - !Ref EnvType
    - prod
Resources:
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-1234567890abcdef0
      InstanceType: c5.xlarge
  MountPoint:
    Type: AWS::EC2::VolumeAttachment
    Condition: IsProduction
    Properties:
      InstanceId: !Ref EC2Instance
      VolumeId: !Ref NewVolume
      Device: /dev/sdh
  NewVolume:
    Type: AWS::EC2::Volume
    Condition: IsProduction
    Properties:
      Size: 100
      AvailabilityZone: !GetAtt
        - EC2Instance
        - AvailabilityZone
```

### 多条件资源预置
<a name="multi-condition-resource-provisioning"></a>

如果提供了存储桶名称，则以下示例会有条件地创建 S3 存储桶，并且仅当环境设置为 `prod` 时，才会附加存储桶策略。如果未提供存储桶名称或环境为 `test`，则不会创建任何资源。

#### JSON
<a name="conditions-section-example-multi-condition.json"></a>

```
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Parameters": {
        "EnvType": {
            "Type": "String",
            "AllowedValues": [
                "prod",
                "test"
            ]
        },
        "BucketName": {
            "Default": "",
            "Type": "String"
        }
    },
    "Conditions": {
        "IsProduction": {
            "Fn::Equals": [
                {
                    "Ref": "EnvType"
                },
                "prod"
            ]
        },
        "CreateBucket": {
            "Fn::Not": [
                {
                    "Fn::Equals": [
                        {
                            "Ref": "BucketName"
                        },
                        ""
                    ]
                }
            ]
        },
        "CreateBucketPolicy": {
            "Fn::And": [
                {
                    "Condition": "IsProduction"
                },
                {
                    "Condition": "CreateBucket"
                }
            ]
        }
    },
    "Resources": {
        "Bucket": {
            "Type": "AWS::S3::Bucket",
            "Condition": "CreateBucket",
            "Properties": {
                "BucketName": {
                    "Ref": "BucketName"
                }
            }
        },
        "Policy": {
            "Type": "AWS::S3::BucketPolicy",
            "Condition": "CreateBucketPolicy",
            "Properties": {
                "Bucket": {
                    "Ref": "Bucket"
                },
                "PolicyDocument": { ... }
            }
        }
    }
}
```

#### YAML
<a name="conditions-section-example-multi-condition.yaml"></a>

```
AWSTemplateFormatVersion: 2010-09-09
Parameters:
  EnvType:
    Type: String
    AllowedValues:
      - prod
      - test
  BucketName:
    Default: ''
    Type: String
Conditions:
  IsProduction: !Equals
    - !Ref EnvType
    - prod
  CreateBucket: !Not
    - !Equals
      - !Ref BucketName
      - ''
  CreateBucketPolicy: !And
    - !Condition IsProduction
    - !Condition CreateBucket
Resources:
  Bucket:
    Type: AWS::S3::Bucket
    Condition: CreateBucket
    Properties:
      BucketName: !Ref BucketName
  Policy:
    Type: AWS::S3::BucketPolicy
    Condition: CreateBucketPolicy
    Properties:
      Bucket: !Ref Bucket
      PolicyDocument: ...
```

在此示例中，`CreateBucketPolicy` 条件演示了如何使用 `Condition` 密钥引用其他条件。只有当 `IsProduction` 和 `CreateBucket` 条件的评估结果都为 true 时，才会创建策略。

**注意**  
有关使用条件的更复杂的示例，请参阅《*Amazon CloudFormation模板参考指南*》中的[Condition 属性](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-attribute-condition.html)主题。

# CloudFormation 模板 Transform 部分
<a name="transform-section-structure"></a>

可选的 `Transform` 部分指定 CloudFormation 用来以某种方式处理模板的一个或多个宏。

宏可以执行查找和替换文本等简单任务，也可以对整个模板进行更广泛的转换。CloudFormation 按照指定的顺序执行宏。当您创建更改集时，CloudFormation 会生成一个包含已处理模板内容的更改集。然后，您可以查看更改并执行更改集。有关宏工作原理的更多信息，请参阅[使用模板宏对 CloudFormation 模板执行自定义处理](template-macros.md)。

CloudFormation 还支持*转换*，后者是由 CloudFormation 托管的宏。在执行顺序和范围方面，CloudFormation 以相同的方法处理转换以及您创建的任何宏。有关更多信息，请参阅[转换参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/transform-reference.html)。

要声明多个宏，请使用列表格式并指定一个或多个宏。

例如，在下面的模板示例中，CloudFormation 会首先评估 `MyMacro`，然后再评估 `AWS::Serverless`，并且两者都可以处理整个模板的内容，因为它们包含在 `Transform` 部分中。

```
# Start of processable content for MyMacro and AWS::Serverless
Transform:
  - MyMacro
  - 'AWS::Serverless'
Resources:
  WaitCondition:
    Type: AWS::CloudFormation::WaitCondition
  MyBucket:
    Type: AWS::S3::Bucket
    Properties: 
      BucketName: amzn-s3-demo-bucket
      Tags: [{"key":"value"}]
      CorsConfiguration: []
  MyEc2Instance:
    Type: AWS::EC2::Instance 
    Properties:
      ImageId: ami-1234567890abcdef0
# End of processable content for MyMacro and AWS::Serverless
```

# CloudFormation 模板格式版本语法
<a name="format-version-structure"></a>

`AWSTemplateFormatVersion` 部分（可选）用于标识模板要符合的模板格式版本。最新的模板格式版本是 `2010-09-09`，并且它是目前唯一的有效值。

模板格式版本与 API 版本不同。模板格式版本可独立于 API 版本进行更改。

模板格式版本声明的值必须是文字字符串。您无法使用参数或函数来指定模板格式版本。如果您没有指定任何值，则 CloudFormation 会假定为最新的模板格式版本。以下代码段是有效的模板格式版本声明的示例：

## JSON
<a name="format-version-structure-example.json"></a>

```
"AWSTemplateFormatVersion" : "2010-09-09"
```

## YAML
<a name="format-version-structure-example.yaml"></a>

```
AWSTemplateFormatVersion: 2010-09-09
```

# CloudFormation 模板 Description 语法
<a name="template-description-structure"></a>

`Description` 部分（可选）可用来包含描述模板的文本字符串。此部分必须始终紧随模板格式版本部分之后。

描述声明的值必须是长度介于 0 和 1024 个字节之间的文字字符串。您无法使用参数或函数来指定描述。以下代码段是描述声明的示例：

**重要**  
堆栈更新期间，您无法更新 `Description` 部分本身。您只能在包括添加、修改或删除资源的更改时更新它。

## JSON
<a name="template-description-structure-example.json"></a>

```
"Description" : "Here are some details about the template."
```

## YAML
<a name="template-description-structure-example.yaml"></a>

```
Description: > Here are some details about the template.
```

# 使用基础设施编辑器直观地创建模板
<a name="infrastructure-composer-for-cloudformation"></a>

Amazon 基础架构编辑器（以前称为**应用程序编辑器**）可帮助您在 Amazon 上直观地构建和配置现代应用程序。您可以通过拖放各种资源来直观地构建应用程序，而不必编写代码。

*CloudFormation 控制台模式下的基础设施编辑器*是直观地处理 CloudFormation 模板的推荐工具。此版本的基础设施编辑器可以从 CloudFormation 控制台访问，是对名为 Amazon CloudFormation Designer 的旧版工具的改进。

通过在 CloudFormation 控制台模式下使用基础设施编辑器，您可以在直观的画布中拖放、配置和连接各种资源（称为*卡片*）。借助这种直观的方法，您可以轻松设计和编辑应用程序架构，而无需直接使用模板。要从 [CloudFormation 控制台](https://console.amazonaws.cn/cloudformation/)访问此模式，请从左侧导航菜单中选择**基础设施编辑器**。

有关更多信息，请参阅《Amazon 基础架构编辑器 开发人员指南》中的 [How to compose in Amazon 基础架构编辑器](https://docs.amazonaws.cn/infrastructure-composer/latest/dg/using-composer-basics.html)**。

## 为什么要在 CloudFormation 控制台模式下使用基础设施编辑器？
<a name="app-composer-for-cloudformation-why-use"></a>

通过在基础设施编辑器中直观地显示模板，有助于您发现 CloudFormation 模板和应用程序架构中的差距和需要改进的领域。基础设施编辑器可以直观地构建和修改 CloudFormation 堆栈，从而提升开发体验，实现轻松和高效。您可以从初始草稿开始，创建可部署的代码，并将开发人员工作流与基础设施编辑器中的可视化设计器进行集成。

## 该模式与基础设施编辑器控制台有何不同？
<a name="app-composer-for-cloudformation-differences"></a>

虽然 CloudFormation 控制台版本的基础设施编辑器在功能上与标准的基础设施编辑器控制台相似，不过也有一些区别。与 Lambda 相关的卡片（**Lambda 函数**和 **Lambda 层**）需要代码生成和打包解决方案，而这些解决方案在 CloudFormation 控制台模式下的基础设施编辑器中不可用。此模式不支持本地同步。

但在[基础设施编辑器控制台](https://console.amazonaws.cn/composer/home)或 Amazon Toolkit for Visual Studio Code 中则可以使用这些与 Lambda 相关的卡片和本地同步功能。有关更多信息，请参阅《Amazon 基础架构编辑器 Developer Guide》[https://docs.amazonaws.cn/infrastructure-composer/latest/dg/what-is-composer.html](https://docs.amazonaws.cn/infrastructure-composer/latest/dg/what-is-composer.html)以及《Amazon Toolkit for Visual Studio Code User Guide》**中的 [Infrastructure Composer](https://docs.amazonaws.cn/toolkit-for-vscode/latest/userguide/appcomposer.html)。

# Amazon CloudFormation 语言服务器
<a name="ide-extension"></a>

Amazon CloudFormation 语言服务器提供加速撰写基础设施即代码（IaC）和安全、自信地部署 Amazon 资源的功能。它遵循[语言服务器协议](https://microsoft.github.io/language-server-protocol/)（LSP），以提供有关悬停、自动补全、通过静态验证进行的诊断、转至定义以及代码操作的相关文档。除了这些传统语言服务器功能外，该服务器还添加了在线功能，可用于通过 CloudFormation 浏览和部署 Amazon 资源。这包括使用更改集来验证和部署模板的能力；查看堆栈差异、事件、资源和输出；列出堆栈并按类型浏览资源；以及直接将实时资源状态插入到 CloudFormation 模板中。

**Topics**
+ [

## IDE 与 Amazon CloudFormation 语言服务器集成
](#ide-extension-supported-ides)
+ [

## 开始使用
](#ide-extension-getting-started)
+ [

## 在 IDE 中初始化 CloudFormation 项目（仅限 VS Code）
](#ide-extension-initialize-project)
+ [

## 开源
](#ide-extension-open-source)
+ [

## 需要帮助？
](#ide-extension-need-help)

## IDE 与 Amazon CloudFormation 语言服务器集成
<a name="ide-extension-supported-ides"></a>

Amazon 通过 Amazon 工具包为以下 IDE 提供与 CloudFormation 语言服务器的现成集成：
+ [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=AmazonWebServices.aws-toolkit-vscode)
+ [JetBrains IDE](https://plugins.jetbrains.com/plugin/11349-aws-toolkit)（版本 2025.3 或更高版本），包括 IntelliJ IDEA、WebStorm 和 PyCharm

以下 IDE 还支持 CloudFormation 语言服务器：
+ [Kiro](https://kiro.dev/downloads/)
+ [Cursor](https://cursor.com/)
+ 大多数 VS Code 分叉和分配

CloudFormation 语言服务器遵守[语言服务器协议](https://microsoft.github.io/language-server-protocol/)（LSP），因此其他集成是可配置的。有关将语言服务器与其他编辑器集成的说明，请参阅[安装指南](https://github.com/aws-cloudformation/cloudformation-languageserver/blob/main/INSTALLATION.md)。

## 开始使用
<a name="ide-extension-getting-started"></a>

**Topics**
+ [

### 先决条件
](#ide-extension-prerequisites)
+ [

### 第 1 步：安装或升级 Amazon 工具包
](#ide-extension-install-toolkit)
+ [

### 第 2 步：在 Amazon 工具包中访问 CloudFormation
](#ide-extension-access-toolkit-panel)
+ [

### 第 3 步：验证、测试和优化您的模板
](#ide-extension-validate-test-refine)
+ [

### 第 4 步：浏览模板
](#ide-extension-navigate-template)
+ [

### 第 5 步：验证和部署
](#ide-extension-validate-deploy)

### 先决条件
<a name="ide-extension-prerequisites"></a>

在您开始之前，请确保：
+ 您正在支持的操作系统（macOS、Windows 或 Linux）上使用支持的 IDE。
+ 您已为自己的 IDE 安装或升级到最新版本的 Amazon 工具包。

Amazon CloudFormation 语言服务器中的某些功能需要有效的 Amazon Web Services 账户和已配置的凭证。您必须使用有效的凭证通过 Amazon 工具包登录您的 Amazon Web Services 账户。

### 第 1 步：安装或升级 Amazon 工具包
<a name="ide-extension-install-toolkit"></a>

从 IDE 的扩展程序或插件管理器中安装或更新到最新版本的 Amazon 工具包，然后重新启动 IDE。

安装后，Amazon 工具包会自动启用 CloudFormation IDE 支持。首次安装或升级带有 Amazon CloudFormation 语言服务器的 Amazon 工具包时，系统会提示您授予 Amazon 收集匿名使用数据的权限。这些数据有助于 Amazon 改进 CloudFormation 语言服务器并增强撰写体验。不会收集任何敏感信息，Amazon 也不会记录或存储模板内容、资源配置或任何可识别身份的客户数据。您可以随时从 IDE 设置中更改遥测首选项。重新启动 IDE 以使更改生效。所收集的使用数据仅涵盖功能交互和性能指标。这些见解有助于 Amazon 识别并确定需要改进方面优先顺序，例如加快验证速度、增强自动补全功能以及改进错误诊断机制。

### 第 2 步：在 Amazon 工具包中访问 CloudFormation
<a name="ide-extension-access-toolkit-panel"></a>

安装 Amazon 工具包后，在 IDE 中打开 CloudFormation 面板。在 VS Code 中，从活动栏打开 Amazon 工具包面板，然后选择 **CLOUDFORMATION**。在 JetBrains IDE 中，从侧栏打开 **Amazon 工具包**工具窗口，然后选择 **CloudFormation** 选项卡。

CloudFormation 面板包含以下部分：
+ **区域**：显示当前 Amazon Web Services 区域。在 VS Code 中，您可以通过选择区域名称或使用命令面板中的 **Amazon CloudFormation: Select Region** 命令来更改区域。在 JetBrains IDE 中，区域是通过 Amazon 工具包连接设置配置的。
+ **堆栈**：显示您的账户中 CloudFormation 堆栈的分页列表。展开堆栈，以便查看其**更改集**节点，其中列出了与该堆栈关联的更改集。使用“查看堆栈详细信息”操作打开堆栈详细信息视图，该视图显示堆栈概述、事件、输出和资源。
+ **资源**：添加资源类型后，面板将显示您账户中该类型的 Amazon 资源。您可以查看、刷新、复制或将它们导入到您的模板中。

在 JetBrains IDE 中，树上方的工具栏可快速访问常见操作，包括**验证和部署**、**重新运行、验证和部署**、**添加资源类型**和**刷新**。也可以通过右键单击树节点上的上下文菜单来执行操作。

### 第 3 步：验证、测试和优化您的模板
<a name="ide-extension-validate-test-refine"></a>

在您编写 CloudFormation 模板时，IDE 会提供智能的撰写辅助功能，以帮助您更快速地创建准确且符合规范的基础设施。CloudFormation 语言服务器在后台运行，并提供以下撰写功能：
+ 代码完成：根据 CloudFormation 架构来建议资源类型、参数和属性。
+ 添加现有的 Amazon 资源：允许您将现有资源从您的 Amazon Web Services 账户导入您的模板。IDE 使用 [Amazon 云端控制 API（CCAPI）](https://docs.amazonaws.cn/cloudcontrolapi/latest/userguide/what-is-cloudcontrolapi.html)检索资源的实时配置和属性，从而帮助您克隆或重复使用模板中的现有基础设施。
+ 提取到参数：当光标位于模板中的字面值（例如，类似 `t2.micro` 的字符串）上时，IDE 会提供重构操作，用于将该值提取到 `Parameters` 部分中，并将字面值替换为指向新参数的 `!Ref`。如果在多个位置出现相同的字面值，则可以选择一次提取所有出现的字面值。

#### 要向模板添加资源
<a name="ide-extension-add-resources-to-template"></a>
+ **添加资源类型**：在 Amazon 工具包 CloudFormation 面板的**资源**下，添加要浏览的资源类型。在 VS Code 中，单击**添加 \$1** 图标或使用命令面板中的 **Amazon CloudFormation: Add Resource Types** 命令。在 JetBrains 中，单击工具栏中的**添加资源类型**按钮或右键单击**资源**节点。
+ **搜索资源类型**：在搜索对话框中，键入要添加的 Amazon 资源类型。示例：
  + `AWS::S3::Bucket`
  + `AWS::Lambda::Function`
+ **浏览资源**：在**资源**部分，将显示您的账户中检测到的 Amazon 资源的分页列表。如果您拥有大量资源，则只会显示第一页。使用导航控件来浏览其他页面并查看所有可用资源。
+ 选择要包含在您的模板中的资源。
+ 您可以通过两种方式将资源插入到您的模板中，具体方式取决于您的目标：
  + **克隆现有资源**：使用现有 Amazon 资源的实时配置和属性在模板中创建新资源。
  + **导入现有资源**：通过将资源的实时状态添加到模板中，将其插入到您的堆栈中。

**提示**
+ 您可以随时刷新**资源**部分，查看您的账户或区域中可用的最新资源列表。
+ 如果您正在导入资源，请不要在同一个账户中添加属于现有 CloudFormation 堆栈的已存在资源。
+ 要确认资源是否已由 CloudFormation 管理，请使用资源旁边的信息操作。在 VS Code 中，单击 **i** 图标。在 JetBrains IDE 中，右键单击资源并选择**获取堆栈管理信息**。

##### 添加相关资源
<a name="ide-extension-add-related-resources"></a>

在 VS Code 中，您可以使用命令 **Amazon CloudFormation: Add Related Resources by Type** 将相关资源添加到所选资源。一旦您从模板中已定义的资源类型中选择了一个资源类型，IDE 就会显示与该类型通常相关联或依赖于该类型的资源列表。例如，如果您选择 `AWS::EC2::Instance`，IDE 可能会建议添加相关资源，例如 `AWS::EC2::SecurityGroup` 或 `AWS::EC2::Subnet`。此功能可帮助您快速构建相互连接的基础设施组件，而无需手动搜索兼容的资源类型。此功能目前在 JetBrains IDE 中不受支持。

#### 静态验证
<a name="ide-extension-static-validation"></a>

CloudFormation 语言服务器提供了由 [Amazon CloudFormation Linter (cfn-lint)](https://github.com/aws-cloudformation/cfn-lint) 和 [Amazon CloudFormation Guard](https://docs.amazonaws.cn/cfn-guard/latest/ug/what-is-guard.html) 提供支持的内置静态验证。在您撰写模板的过程中，这些验证会在后台进行，帮助您在部署前发现语法错误、合规性缺口以及最佳实践方面的问题。

**静态验证概述**

您将在 IDE 中看到两种类型的实时静态验证：
+ CloudFormation Linter（`cfn-lint`）：根据 CloudFormation 资源规范和架构规则验证您的模板。
+ Guard（`cfn-guard`）：根据合规性规则和组织策略包验证您的模板。

##### CloudFormation Linter（cfn-lint）
<a name="ide-extension-cfn-linter-details"></a>

CloudFormation Linter 已集成到 IDE 中，以在您键入时自动检查模板的语法和结构。
+ **架构验证**：检测语法和架构错误，以确保您的模板符合 CloudFormation 资源架构。
+ **错误突出显示**：在出现问题时，会显示内联标记，这些标记代表部署拦截器或警告信息。
+ **悬停获取帮助**：将鼠标悬停在错误上方时，IDE 会显示与该问题相关的诊断消息。如果有快速修复方案可用，也会提供。

##### Guard 集成
<a name="ide-extension-cfn-guard-integration"></a>

Guard 会根据定义合规性和安全策略的规则集来验证您的模板。IDE 通过 CloudFormation 语言服务器实时运行 Guard 验证，以在您撰写模板时为您提供即时反馈。
+ **默认规则包**：IDE 包含了一套预先注册好的 Guard 规则，这些规则侧重于资源安全和配置维护方面的基本最佳实践。要了解更多信息，请参见 [guard 规则注册表](https://github.com/aws-cloudformation/aws-guard-rules-registry)。
+ **添加规则包**：要添加或修改规则集，请打开“IDE 设置”，导航到“Guard 配置”部分，然后选择或上传其他 Guard 规则包。

**提示**：了解诊断指示器
+ 蓝色指示器：最佳实践提示或优化建议。
+ 黄色指示器：关于非拦截问题的警告（例如，缺少标签或参数）。
+ 红色指示器：部署拦截器，例如无效的属性名称、缺少必填字段或架构不匹配。

### 第 4 步：浏览模板
<a name="ide-extension-navigate-template"></a>

IDE 提供 CloudFormation 模板的结构化分层视图，该视图分为 `Parameters`、`Resources`、`Outputs` 和 `Mappings` 等部分，显示了每种资源类型和逻辑 ID。这使得在大型模板中能够轻松快速地定位并导航到特定的资源或参数。在 VS Code 中，**探索器**侧栏中的**大纲**面板显示此结构。在 JetBrains IDE 中，打开**结构**工具窗口，查看当前打开的文件的模板结构。

您可以将**转到定义**用于 `GetAtt` 和 `Ref` 之类的内置函数，从而使您可以直接跳转到模板中引用的资源或参数。这可以帮助您跟踪依赖项、了解资源关系并更高效地进行编辑。

### 第 5 步：验证和部署
<a name="ide-extension-validate-deploy"></a>

当您准备好部署 CloudFormation 模板时，请使用“验证和部署”功能来创建更改集。IDE 会验证您的模板，如果未发现任何拦截错误，则会继续创建[偏差感知更改集](drift-aware-change-sets.md)。然后 IDE 会显示差异视图，以便您可以在执行更改集之前查看所有提议的更改。

在 VS Code 中，打开命令面板并运行 **Amazon CloudFormation: Validate and Deploy**。命令面板将引导您逐步选择模板、堆栈名称、参数、功能和其他部署选项。在 JetBrains IDE 中，使用**验证和部署**工具栏按钮，在编辑器中右键单击模板文件或右键单击树中的堆栈。JetBrains 会显示一个向导对话框，您可以在其中配置所有部署选项，包括模板选择、堆栈名称、参数、功能、标签和高级选项。

#### 验证的工作原理
<a name="ide-extension-how-validation-works"></a>

IDE 会在[部署前自动执行验证检查](validate-stack-deployments.md)，并根据常见的故障原因对模板进行验证，包括：
+ 无效的属性语法或架构不匹配：这些问题通常在撰写过程中被 `cfn-lint` 检测出来，但如果您在未解决这些问题的情况下继续进行部署，那么在创建或更新堆栈时，CloudFormation 的部署时验证也会显示出同样的错误。
+ 资源名称与您账户中的现有资源冲突。
+ 特定于服务的约束，例如 S3 存储桶名称冲突或缺少加密。

如果验证检测到错误，IDE 会直接在模板中突出显示问题，并在诊断面板中列出错误。每个问题都包括导致故障的特定属性或资源，并附上相应的解决建议。如果没有阻止错误，则可以继续进入部署阶段。

如果发现警告（非阻止问题），会出现一个对话框，让您可以选择继续进行部署操作，或者取消操作并进行修正。

IDE 将打开一个[偏差感知更改集](drift-aware-change-sets.md)，其中显示当前模板与已部署堆栈配置之间的任何差异。这使您能够在执行之前查看、确认或取消更改集。取消部署会删除更改集。

偏差感知更改集能够增强 CloudFormation 的部署流程，使您能够安全地处理堆栈的偏差问题。当您的资源的实际状态与 CloudFormation 模板中所定义的内容不一致时，就会出现堆栈偏差，这种情况通常因通过 Amazon Web Services 管理控制台、CLI 或 SDK 进行的手动更改导致。CloudFormation [偏差感知更改集](drift-aware-change-sets.md)将处理后的堆栈配置与实时资源状态进行比较，IDE 会显示这些差异，这样您就可以在部署之前使资源恢复合规性。

#### 查看堆栈事件
<a name="ide-extension-view-stack-events"></a>

部署开始后，您可以从 CloudFormation 面板实时监控进度。在**堆栈事件**下，您将看到部署期间执行的操作列表。每个事件都包含详细信息，例如：
+ **时间戳**：事件发生的时间
+ **资源**：正在创建、更新或删除的特定 Amazon 资源
+ **状态**：操作的当前状态（例如 `CREATE_IN_PROGRESS`、`UPDATE_COMPLETE` 或 `ROLLBACK_IN_PROGRESS`）
+ **原因**：其他背景信息或错误消息（如果适用）

您也可以通过此面板查看堆栈的**资源**和**输出**。**堆栈事件**视图有助于您跟踪部署进度、识别潜在问题，并确认您的堆栈是否已成功完成部署。

## 在 IDE 中初始化 CloudFormation 项目（仅限 VS Code）
<a name="ide-extension-initialize-project"></a>

在 IDE 中初始化 CloudFormation 项目可以帮助您使用正确的文件夹、环境配置和 Amazon 凭证设置结构化工作区，以便您可以可靠地验证和部署模板。您可以直接从 IDE 来初始化一个新的 CloudFormation 项目，从而创建此建议设置。此功能目前仅在 VS Code 中可用，在 JetBrains IDE 中不受支持。

**要初始化 CloudFormation 项目，请执行以下操作：**
+ **打开命令面板**
  + 从 VS Code，打开命令面板（macOS 上的 `Ctrl+Shift+P` 或 `Cmd+Shift+P`）。
  + 选择 **Amazon CloudFormation：CFN Init：初始化项目**。
+ **选择项目目录**
  + 默认情况下，IDE 将使用您当前的工作目录。
  + 您可以将此路径更改为您希望存储 CloudFormation 模板所在的任何文件夹。
+ **选择您的 Amazon 凭证配置文件**
  + 系统将提示您选择 Amazon 凭证配置文件。所选配置文件用于环境检测、验证和部署。
+ **设置环境**
  + 系统将提示您创建或选择环境。
  + 环境定义了您的模板在何处以及以何种方式进行部署或验证（例如，开发环境、测试环境或生产环境）。您可以使用 **Amazon CloudFormation：CFN Init：添加环境**来选择或更改您的环境。
  + 您可以使用 **Amazon CloudFormation: CFN Init: Remove Environment** 移除您选择的环境。
+ **（可选）导入参数文件**
  + 如果您已经有现有的参数文件，那么该 IDE 会在初始化时允许您导入这些文件。
  + IDE 会自动检测兼容的文件，并将它们链接到您的项目中，以便在模板验证和部署过程中使用。
+ **命名并最终确定项目**
  + 提供项目名称，例如 beta-environment，然后完成设置。
  + IDE 将为您创建初始项目结构和配置文件。

您可以直接从 IDE 中进行验证、预览部署操作，或者在不同环境中进行切换。

## 开源
<a name="ide-extension-open-source"></a>

Amazon CloudFormation 语言服务器根据 Apache-2.0 许可开源，让客户能够全面了解模板诊断、架构验证以及静态分析是如何进行的。对于在采用工具之前需要来源级可见性的客户来说，这减少了安全性和合规性方面的摩擦。

该代码库已在 GitHub 上公开发布：[https://github.com/aws-cloudformation/cloudformation-languageserver/](https://github.com/aws-cloudformation/cloudformation-languageserver/)。

## 需要帮助？
<a name="ide-extension-need-help"></a>

在 Amazon Web Services re:Post 上试用 [CloudFormation 社区](https://repost.aws/tags/TAm3R3LNU3RfSX9L23YIpo3w)。

# 使用 IaC 生成器为现有资源生成模板
<a name="generate-IaC"></a>

借助 CloudFormation 基础设施即代码生成器（IaC 生成器），您可以使用账户中已预置但尚未由 CloudFormation 管理的 Amazon 资源生成模板。

IaC 生成器的优点如下：
+ 将整个应用程序置于 CloudFormation 管理之下，或者将其迁移到 Amazon CDK 应用程序中。
+ 生成模板时无需逐个描述资源属性，然后将其转换为 JSON 或 YAML 语法。
+ 使用该模板在新账户或区域中复制资源。

IaC 生成过程包括以下步骤：

1. **扫描资源** – 第一步是启动资源扫描。该扫描为全区域扫描，持续 30 天。在此期间，您可以根据同一扫描创建多个模板。

1. **创建模板** – 您可以通过两个选项来创建模板：
   + 从头开始创建新模板并将扫描的资源和相关资源添加到模板中。
   + 以现有的 CloudFormation 堆栈作为起点，并将扫描的资源和相关资源添加到其模板中。

1. **导入资源** – 使用您的模板，将资源作为 CloudFormation 堆栈导入或将其迁移到 Amazon CDK 应用程序中。

IaC 生成器功能适用于所有商业区域，并支持许多常见的 Amazon 资源类型。有关受支持资源的完整列表，请参阅[资源类型支持](resource-import-supported-resources.md)。

**Topics**
+ [

## 注意事项
](#iac-generator-considerations)
+ [

## 扫描资源所需的 IAM 权限
](#iac-generator-permissions)
+ [

## 用于模板生成、管理和删除的常用命令
](#iac-generator-commonly-used-commands)
+ [

## 将模板迁移到 Amazon CDK
](#iac-generator-cdk-migrate)
+ [

# 使用 CloudFormation IaC 生成器启动资源扫描
](iac-generator-start-resource-scan.md)
+ [

# 在 CloudFormation 控制台中查看扫描摘要
](generate-IaC-view-scan-summary.md)
+ [

# 使用 IaC 生成器根据扫描的资源创建 CloudFormation 模板
](iac-generator-create-template-from-scanned-resources.md)
+ [

# 根据扫描的资源创建 CloudFormation 堆栈
](iac-generator-create-stack-from-scanned-resources.md)
+ [

# 解决只写属性问题
](generate-IaC-write-only-properties.md)

## 注意事项
<a name="iac-generator-considerations"></a>

您可以为您具有读取权限的 Amazon 资源生成 JSON 或 YAML 模板。IaC 生成器功能模板晋江可靠、快速地对云资源进行建模，而无需按属性描述资源属性。

下表列出了 IaC 生成功能的可用限额。


| 名称 | 完全扫描 | 部分扫描 | 
| --- | --- | --- | 
|  一次扫描可以处理的最大资源数  |  100000  |  100000  | 
|  每天的扫描次数（适用于少于 10,000 个资源的扫描）  |  10  |  10  | 
|  每天的扫描次数（适用于超过 10,000 个资源的扫描）  |  1  |  1  | 
|  每个账户生成的并发模板数量  |  5  |  5  | 
|  为一次模板生成建模的并发资源数量  |  5  |  5  | 
|  可以在一个模板中建模的资源总数  |  500  |  500  | 
|  每账户最大生成的模板数  |  1000  |  1000  | 

**重要**  
IaC 生成器仅支持您所在区域的 Cloud Control API 支持的 Amazon 资源。有关更多信息，请参阅 [资源类型支持](resource-import-supported-resources.md)。

## 扫描资源所需的 IAM 权限
<a name="iac-generator-permissions"></a>

要使用 IaC 生成器扫描资源，您的 IAM 主体（用户、角色或组）必须具备：
+ CloudFormation 扫描权限
+ 目标 Amazon 服务的读取权限

扫描范围仅限于您有读取权限的资源。缺少权限不会导致扫描失败，但会排除那些资源。

有关授予扫描和模板管理权限的 IAM 策略示例，请参阅 [允许所有 IaC 生成器操作](security_iam_id-based-policy-examples.md#iam-policy-example-for-iac-generator)。

## 用于模板生成、管理和删除的常用命令
<a name="iac-generator-commonly-used-commands"></a>

使用 IaC 生成器的常用命令包括：
+ [start-resource-scan](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/start-resource-scan.html)，用于启动扫描该账户在 Amazon Web Services 区域中的资源。
+ [describe-resource-scan](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/describe-resource-scan.html)，用于监控资源扫描的进度。
+ [list-resource-scans](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/list-resource-scans.html)，用于列出 Amazon Web Services 区域中的已扫描资源。
+ [list-resource-scan-resources](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/list-resource-scan-resources.html)，用于列出在资源扫描期间找到的资源。
+  [list-resource-scan-related-resources](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/list-resource-scan-related-resources.html)，用于列出与您扫描的资源相关的资源。
+ [create-generated-template](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/create-generated-template.html)，用于根据一组扫描的资源生成 CloudFormation 模板。
+ [update-generated-template](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/update-generated-template.html)，用于更新生成的模板。
+ [describe-generated-template](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/describe-generated-template.html)，用于返回有关已生成模板的信息。
+ [list-generated-templates](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/list-generated-templates.html)，用于列出您的账户和当前区域中所有生成的模板。
+ [delete-generated-template](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/delete-generated-template.html)，用于删除生成的模板。

## 将模板迁移到 Amazon CDK
<a name="iac-generator-cdk-migrate"></a>

Amazon Cloud Development Kit (Amazon CDK) 是一个开源软件开发框架，您可以通过该框架使用流行的编程语言开发、管理和部署 CloudFormation 资源。

Amazon CDK CLI 提供了与 IaC 生成器的集成。使用 Amazon CDK CLI `cdk migrate` 命令生成 CloudFormation 模板并创建包含您的资源的新 CDK 应用程序。然后，您可以使用 Amazon CDK 管理您的资源并部署到 CloudFormation。

有关更多信息，请参阅《Amazon Cloud Development Kit (Amazon CDK) 开发人员指南》**中的[迁移到 Amazon CDK](https://docs.amazonaws.cn/cdk/v2/guide/migrate.html)。

# 使用 CloudFormation IaC 生成器启动资源扫描
<a name="iac-generator-start-resource-scan"></a>

在从现有资源创建模板之前，您必须首先启动资源扫描以发现当前资源及其关系。

您可以使用以下选项之一启动资源扫描。对于首次使用 IaC 生成器的用户，我们推荐第一个选项。
+ **扫描所有资源（完全扫描）** - 扫描当前账户和区域中的所有现有资源。对于 1,000 个资源，此扫描过程最多可能需要 10 分钟。
+ **扫描特定资源（部分扫描）** – 在当前账户和区域中手动选择要扫描的资源类型。此选项提供更快、更集中的扫描过程，使其成为迭代模板开发的理想选择。

扫描完成后，您可以选择生成模板时要包括哪些资源及其相关资源。使用部分扫描时，相关资源仅在以下任一情况下在模板生成期间可用：
+ 您在开始扫描之前特意选择了它们，或者
+ 它们是发现所选资源类型所必需的。

例如，如果您选择 `AWS::EKS::Nodegroup` 而不选择 `AWS::EKS::Cluster`，IaC 生成器会自动在扫描中包括 `AWS::EKS::Cluster` 资源，因为发现节点组需要先发现集群。在所有其他情况下，扫描将仅包含您专门选择的资源。

**注意**  
在继续操作之前，请确认您拥有使用 IaC 生成器所需的权限。有关更多信息，请参阅 [扫描资源所需的 IAM 权限](generate-IaC.md#iac-generator-permissions)。

**Topics**
+ [

## 启动资源扫描（控制台）
](#start-resource-scan-console)
+ [

## 启动资源扫描（Amazon CLI）
](#start-resource-scan-cli)

## 启动资源扫描（控制台）
<a name="start-resource-scan-console"></a>

**启动所有资源类型的资源扫描（完全扫描）**

1. 打开 CloudFormation 控制台的 [IaC 生成器页面](https://console.amazonaws.cn/cloudformation/home?#iac-generator)。

1. 在屏幕顶部的导航栏上，选择包含要扫描的资源的 Amazon Web Services 区域。

1. 从**扫描**面板中，选择**启动新扫描**，然后选择**扫描所有资源**。

**启动特定资源类型的资源扫描（部分扫描）**

1. 打开 CloudFormation 控制台的 [IaC 生成器页面](https://console.amazonaws.cn/cloudformation/home?#iac-generator)。

1. 在屏幕顶部的导航栏上，选择包含要扫描的资源的 Amazon Web Services 区域。

1. 从**扫描**面板中，选择**开始新扫描**，然后选择**扫描特定资源**。

1. 在**启动部分扫描**对话框中，最多选择 100 种资源类型，然后选择**启动扫描**。

## 启动资源扫描（Amazon CLI）
<a name="start-resource-scan-cli"></a>

**启动所有资源类型的资源扫描（完全扫描）**  
使用以下 [start-resource-scan](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/start-resource-scan.html) 命令。将 *us-east-1* 替换为包含要扫描的资源的 Amazon Web Services 区域。

```
aws cloudformation start-resource-scan --region us-east-1
```

如果成功，该命令会返回该扫描的 ARN。记下 `ResourceScanId` 属性中的 ARN。创建模板将会需要该数据。

```
{
    "ResourceScanId":
      "arn:aws:cloudformation:region:account-id:resourceScan/0a699f15-489c-43ca-a3ef-3e6ecfa5da60"
}
```

**启动特定资源类型的资源扫描（部分扫描）**

1. 使用以下 [cat](https://en.wikipedia.org/wiki/Cat_(Unix)) 命令将要扫描的资源类型存储在主目录中名为 `config.json` 的 JSON 文件中。下面是扫描 Amazon EC2 实例、安全组和所有 Amazon S3 资源的示例扫描配置。

   ```
   $ cat > config.json
   [
     {
       "Types":[
         "AWS::EC2::Instance",
         "AWS::EC2::SecurityGroup",
         "AWS::S3::*"
       ]
     }
   ]
   ```

1. 使用带有 `--scan-filters` 选项的 [start-resource-scan](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/start-resource-scan.html) 命令以及您创建 `config.json` 的文件来启动部分扫描。将 *us-east-1* 替换为包含要扫描的资源的 Amazon Web Services 区域。

   ```
   aws cloudformation start-resource-scan --scan-filters file://config.json --region us-east-1
   ```

   如果成功，该命令会返回该扫描的 ARN。记下 `ResourceScanId` 属性中的 ARN。创建模板将会需要该数据。

   ```
   {
       "ResourceScanId":
         "arn:aws:cloudformation:region:account-id:resourceScan/0a699f15-489c-43ca-a3ef-3e6ecfa5da60"
   }
   ```

**监控资源扫描的进度**  
使用 [describe-resource-scan](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/describe-resource-scan.html) 命令。对于 `--resource-scan-id` 选项，请将示例 ARN 替换为实际的 ARN。

```
aws cloudformation describe-resource-scan --region us-east-1 \
  --resource-scan-id arn:aws:cloudformation:us-east-1:123456789012:resourceScan/0a699f15-489c-43ca-a3ef-3e6ecfa5da60
```

如果成功，该命令返回类似以下内容的输出：

```
{
    "ResourceScanId": "arn:aws:cloudformation:region:account-id:resourceScan/0a699f15-489c-43ca-a3ef-3e6ecfa5da60",
    "Status": "COMPLETE",
    "StartTime": "2023-08-21T03:10:38.485000+00:00",
    "EndTime": "2023-08-21T03:20:28.485000+00:00",
    "PercentageCompleted": 100.0,
    "ResourceTypes": [
        "AWS::CloudFront::CachePolicy",
        "AWS::CloudFront::OriginRequestPolicy",
        "AWS::EC2::DHCPOptions",
        "AWS::EC2::InternetGateway",
        "AWS::EC2::KeyPair",
        "AWS::EC2::NetworkAcl",
        "AWS::EC2::NetworkInsightsPath",
        "AWS::EC2::NetworkInterface",
        "AWS::EC2::PlacementGroup",
        "AWS::EC2::Route",
        "AWS::EC2::RouteTable",
        "AWS::EC2::SecurityGroup",
        "AWS::EC2::Subnet",
        "AWS::EC2::SubnetCidrBlock",
        "AWS::EC2::SubnetNetworkAclAssociation",
        "AWS::EC2::SubnetRouteTableAssociation",
        ...
    ],
    "ResourcesRead": 676
}
```

对于部分扫描，输出将类似于以下内容：

```
{
    "ResourceScanId": "arn:aws:cloudformation:region:account-id:resourceScan/0a699f15-489c-43ca-a3ef-3e6ecfa5da60",
    "Status": "COMPLETE",
    "StartTime": "2025-03-06T18:24:19.542000+00:00",
    "EndTime": "2025-03-06T18:25:23.142000+00:00",
    "PercentageCompleted": 100.0,
    "ResourceTypes": [
        "AWS::EC2::Instance",
        "AWS::EC2::SecurityGroup",
        "AWS::S3::Bucket",
        "AWS::S3::BucketPolicy"
    ],
    "ResourcesRead": 65,
    "ScanFilters": [
        {
            "Types": [
                "AWS::EC2::Instance",
                "AWS::EC2::SecurityGroup",
                "AWS::S3::*"
            ]
        }
    ]
}
```

有关输出中字段的描述，请参阅《Amazon CloudFormation API 参考》中的 [DescribeResourceScan](https://docs.amazonaws.cn/AWSCloudFormation/latest/APIReference/API_DescribeResourceScan.html)**。

# 在 CloudFormation 控制台中查看扫描摘要
<a name="generate-IaC-view-scan-summary"></a>

扫描完成后，您可以通过可视化界面查看扫描期间发现的资源，以帮助确定不同产品类型的资源集中情况。

**查看有关扫描期间所发现资源的信息**

1. 打开 CloudFormation 控制台的 [IaC 生成器页面](https://console.amazonaws.cn/cloudformation/home?#iac-generator)。

1. 在屏幕顶部的导航栏上，选择包含要查看的资源扫描的 Amazon Web Services 区域。

1. 从导航窗格中，选择 **IaC 生成器**。

1. 在**已扫描资源明细**下，您可以通过可视化界面查看按产品类型（例如**计算**和**存储**）划分的已扫描资源明细。

1. 要自定义显示的产品类型数量，请选择**筛选显示的数据**。这有助您自定义可视化效果，从而聚焦您最感兴趣的产品类型。

1. 页面右侧为**扫描摘要详细信息**面板。要打开该面板，请选择**打开面板**图标。

![\[IaC 生成器控制台直观地显示了已扫描资源的明细。\]](http://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/images/IaC-generator-scan-summary.png)


# 使用 IaC 生成器根据扫描的资源创建 CloudFormation 模板
<a name="iac-generator-create-template-from-scanned-resources"></a>

本主题介绍了如何使用 IaC 生成器功能，根据扫描的资源创建模板。

## 根据扫描的资源创建模板（控制台）
<a name="create-template-from-scanned-resources-console"></a>

**根据扫描的资源创建堆栈模板**

1. 打开 CloudFormation 控制台的 [IaC 生成器页面](https://console.amazonaws.cn/cloudformation/home?#iac-generator)。

1. 在屏幕顶部的导航栏上，选择包含已扫描资源的 Amazon Web Services 区域。

1. 从**模板**部分中，选择**创建模板**。

1. 选择**从新模板开始**。

   1. 对于**模板名称**，请提供模板的名称。

   1. （可选）配置您的**删除策略**和**更新替换策略**。

   1. 选择**下一步**将扫描的资源添加到模板中。

1. 对于**添加扫描的资源**，浏览扫描的资源列表，然后选择要添加到模板中的资源。您可以按资源标识符、资源类型或标签筛选资源。筛选器是互相包容的。

1. 将所有需要的资源添加到模板后，选择**下一步**以退出**添加扫描的资源**页面，然后进入**添加相关资源**页面。

1. 查看推荐的相关资源列表。诸如 Amazon EC2 实例和安全组之类的相关资源是相互依赖的，通常属于同一个工作负载。选择要包含在生成的模板中的相关资源。
**注意**  
建议您将所有相关资源添加到此模板中。

1. 查看模板详细信息、扫描的资源和相关资源。

1. 选择**创建模板**退出**查看并创建**页面并创建模板。

## 根据扫描的资源创建模板（Amazon CLI）
<a name="create-template-from-scanned-resources-cli"></a>

**根据扫描的资源创建堆栈模板**

1. 使用 [list-resource-scan-resources](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/list-resource-scan-resources.html) 命令来列出在扫描期间找到的资源，还可选择指定 `--resource-identifier` 选项来限制输出范围。对于 `--resource-scan-id` 选项，请将示例 ARN 替换为实际的 ARN。

   ```
   aws cloudformation list-resource-scan-resources \
     --resource-scan-id arn:aws:cloudformation:us-east-1:123456789012:resourceScan/0a699f15-489c-43ca-a3ef-3e6ecfa5da60 \
     --resource-identifier MyApp
   ```

   示例响应如下，其中 `ManagedByStack` 指示 CloudFormation 是否已管理该资源。复制输出。您在下一个步骤中需要用到它。

   ```
   {
       "Resources": [
           {
               "ResourceType": "AWS::EKS::Cluster",
               "ResourceIdentifier": {
                   "ClusterName": "MyAppClusterName"
               },
               "ManagedByStack": false
           },
           {
               "ResourceType": "AWS::AutoScaling::AutoScalingGroup",
               "ResourceIdentifier": {
                   "AutoScalingGroupName": "MyAppASGName"
               },
               "ManagedByStack": false
           }
       ]
   }
   ```

   有关输出中字段的描述，请参阅《Amazon CloudFormation API 参考》中的 [ScannedResource](https://docs.amazonaws.cn/AWSCloudFormation/latest/APIReference/API_ScannedResource.html)**。

1. 使用 `cat` 命令将资源类型和标识符存储到您主目录中名为 `resources.json` 的 JSON 文件中。以下是基于上一步中示例输出的示例 JSON。

   ```
   $ cat > resources.json
   [
       {
           "ResourceType": "AWS::EKS::Cluster",
           "ResourceIdentifier": {
               "ClusterName": "MyAppClusterName"
           }
       },
       {
           "ResourceType": "AWS::AutoScaling::AutoScalingGroup",
           "ResourceIdentifier": {
               "AutoScalingGroupName": "MyAppASGName"
           }
       }
   ]
   ```

1. 使用 [list-resource-scan-related-resources](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/list-resource-scan-related-resources.html) 命令以及您创建的 `resources.json` 文件来列出与您扫描的资源相关的资源。

   ```
   aws cloudformation list-resource-scan-related-resources \
     --resource-scan-id arn:aws:cloudformation:us-east-1:123456789012:resourceScan/0a699f15-489c-43ca-a3ef-3e6ecfa5da60 \
     --resources file://resources.json
   ```

   示例响应如下，其中 `ManagedByStack` 指示 CloudFormation 是否已管理该资源。将这些资源添加到您在上一步中创建的 JSON 文件中。您需要这些输出来创建模板。

   ```
   {
       "RelatedResources": [
           {
               "ResourceType": "AWS::EKS::Nodegroup",
               "ResourceIdentifier": {
                   "NodegroupName": "MyAppNodegroupName"
               },
               "ManagedByStack": false
           },
           {
               "ResourceType": "AWS::IAM::Role",
               "ResourceIdentifier": {
                   "RoleId": "arn:aws::iam::account-id:role/MyAppIAMRole"
               },
               "ManagedByStack": false
           }
       ]
   }
   ```

   有关输出中字段的描述，请参阅《Amazon CloudFormation API 参考》中的 [ScannedResource](https://docs.amazonaws.cn/AWSCloudFormation/latest/APIReference/API_ScannedResource.html)**。
**注意**  
资源输入列表的长度不能超过 100。如果要列出的资源数超过了 100 个，请按照一个批次 100 个资源的方式，来运行 **list-resource-scan-related-resources** 命令并合并结果。  
请注意，输出列表中可能包含重复的资源。

1. 使用 [create-generated-template](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/create-generated-template.html) 命令来创建新的堆栈模板，并进行下列修改：
   + 将 `us-east-1` 替换为包含已扫描资源的 Amazon Web Services 区域。
   + 将 `MyTemplate` 替换为要创建的模板的名称。

   ```
   aws cloudformation create-generated-template --region us-east-1 \
    --generated-template-name MyTemplate \
     --resources file://resources.json
   ```

   下面是一个 `resources.json` 示例文件。

   ```
   [
       {
           "ResourceType": "AWS::EKS::Cluster",
           "LogicalResourceId":"MyCluster",
           "ResourceIdentifier": {
               "ClusterName": "MyAppClusterName"
           }
       },
       {
           "ResourceType": "AWS::AutoScaling::AutoScalingGroup",
           "LogicalResourceId":"MyASG",
           "ResourceIdentifier": {
               "AutoScalingGroupName": "MyAppASGName"
           }
       },
       {
           "ResourceType": "AWS::EKS::Nodegroup",
           "LogicalResourceId":"MyNodegroup",
           "ResourceIdentifier": {
               "NodegroupName": "MyAppNodegroupName"
           }
       },
       {
           "ResourceType": "AWS::IAM::Role",
           "LogicalResourceId":"MyRole",
           "ResourceIdentifier": {
               "RoleId": "arn:aws::iam::account-id:role/MyAppIAMRole"
           }
       }
   ]
   ```

   如果成功，该命令会返回以下响应。

   ```
   {
     "Arn":
       "arn:aws:cloudformation:region:account-id:generatedtemplate/7fc8512c-d8cb-4e02-b266-d39c48344e48",
     "Name": "MyTemplate"
   }
   ```

# 根据扫描的资源创建 CloudFormation 堆栈
<a name="iac-generator-create-stack-from-scanned-resources"></a>

创建模板后，您可以在创建堆栈并导入扫描的资源前，使用基础设施编辑器预览生成的模板。这有助于您直观地查看完整的应用程序架构以及资源及其关系。有关基础设施编辑器的更多信息，请参阅[使用基础设施编辑器直观地创建模板](infrastructure-composer-for-cloudformation.md)。

**创建堆栈并导入已扫描资源**

1. 打开 CloudFormation 控制台的 [IaC 生成器页面](https://console.amazonaws.cn/cloudformation/home?#iac-generator)。

1. 在屏幕顶部的导航栏中，选择模板所在的 Amazon Web Services 区域。

1. 选择**模板**选项卡，然后选择模板名称以查看更多信息。

1. 在**模板定义**选项卡中**模板**部分的顶部，您可以根据自己的喜好将模板从 YAML 语法切换为 JSON 语法。

1. 检查模板的详细信息，以确保所有设置都正确无误。为更便于检查和理解模板，您可以从默认的代码视图切换到图形视图，使用基础设施编辑器来查看模板中描述的基础设施。要执行此操作，请在**模板**下选择**画布**，而不是**模板**。

    **画布操作** 
   + 要聚焦模板中特定资源的详细信息，请双击卡片以打开**资源属性**面板。
   + 要在画布上直观地排列和整理卡片，请在画布的左上角选择**排列**。
   + 要放大和缩小画布，请使用画布右下角的缩放控件。

1. 要在控制台中查看特定资源，请选择**模板资源**选项卡，然后选择要查看的资源的物理 ID。这时您将进入该特定资源的控制台。您也可以通过**模板资源**选项卡在模板定义中添加、移除和重新同步资源。

1. 在**模板定义**选项卡中，IaC 生成器可能会对包含只写属性的资源发出警告。查看警告后，您可以下载生成的模板并进行任何必要的更改。有关更多信息，请参阅 [解决只写属性问题](generate-IaC-write-only-properties.md)。

1. 如果模板定义符合要求，请在**模板定义**选项卡中选择**导入到堆栈**，然后选择**下一步**。

1. 在**指定堆栈详细信息**页面的**指定堆栈**面板上输入堆栈名称，然后选择**下一步**。

1. 查看并输入堆栈的参数。选择**下一步**。

1. 在**查看更改**页面上查看您的选项，然后选择**下一步**。

1. 在**查看和导入**页面上查看您的详细信息，然后选择**导入资源**。

# 解决只写属性问题
<a name="generate-IaC-write-only-properties"></a>

使用 CloudFormation IaC 生成器，您可以使用账户中已预置但尚未由 CloudFormation 管理的资源生成模板。但是，某些资源属性被指定为*只写*，这意味着 CloudFormation 可以写入但不能读取这些属性，例如数据库密码。

利用现有资源生成 CloudFormation 模板时，只写属性会带来挑战。通常，CloudFormation 会在生成的模板中将这些属性转换为参数。这允许您在导入操作期间输入属性作为参数值。但在某些情况下无法实现这种转换，而且 CloudFormation 对这些情况的处理方式有所不同。

## 互斥属性
<a name="write-only-mutually-exclusive-properties"></a>

一些资源有多组互斥属性，其中至少有一些是只写属性。对于这些情况，IaC 生成器无法确定在创建期间对资源应用了哪组互斥属性。例如，您可以使用其中一组属性提供 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html) 代码。
+ `Code/S3Bucket`、`Code/S3Key` 以及可选的 `Code/S3ObjectVersion`
+ `Code/ImageUri`
+ `Code/ZipFile`

所有这些属性均为只写属性。IaC 生成器会选择其中一组独占属性并将其添加到生成的模板中。为每个只写属性添加参数。参数名称包括 `OneOf`，参数说明表示相应的属性可以替换为其他独占属性。IaC 生成器为包含的属性设置的警告类型为 `MUTUALLY_EXCLUSIVE_PROPERTIES`。

## 互斥类型
<a name="write-only-mutually-exclusive-types"></a>

在某些情况下，只写属性可以为多种数据类型。例如，[https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-apigateway-restapi.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-apigateway-restapi.html) 的 `Body` 属性可以是 `object` 或 `string`。遇到这种情况时，IaC 生成器会使用 `string` 类型在生成的模板中包含该属性，并将警告类型设置为 `MUTUALLY_EXCLUSIVE_TYPES`。

## Array 属性
<a name="write-only-array-properties"></a>

如果只写属性的类型为 `array`，则 IaC 生成器无法将其包含在生成的模板中，因为参数只能是标量值。在这种情况下，模板中会忽略该属性，并设置 `UNSUPPORTED_PROPERTIES` 警告类型。

## 可选属性
<a name="write-only-optional-properties"></a>

对于可选的只写属性，IaC 生成器无法检测在设置资源时是否使用过该属性。在这种情况下，生成的模板中会忽略该属性，并设置 `UNSUPPORTED_PROPERTIES` 警告类型。

## 警告和后续步骤
<a name="write-only-properties-warnings-and-next-steps"></a>

要确定哪些属性为只写属性，您必须查看 IaC 生成器控制台返回的警告。[Amazon 资源和属性类型参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-template-resource-type-ref.html)并未指示某个属性是否为只写属性，也未指示其是否支持多种类型。

您也可从资源提供程序架构中查看哪些属性为只写属性。要下载资源提供程序架构，请参阅 [CloudFormation 资源提供程序架构](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/resource-type-schemas.html)。

**解决只写属性问题**

1. 打开 CloudFormation 控制台的 [IaC 生成器页面](https://console.amazonaws.cn/cloudformation/home?#iac-generator)。

1. 在屏幕顶部的导航栏中，选择模板所在的 Amazon Web Services 区域。

1. 选择**模板**选项卡，然后选择您创建的模板的名称。

1. 在**模板定义**选项卡中，当生成的模板包含具有只写属性的资源时，IaC 生成器控制台会显示一条警告，其中包含问题类型的摘要。例如：  
![\[IaC 生成器控制台关于生成的模板中包含只写属性的警告\]](http://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/images/IaC-generator-write-only-property-warning.png)

1. 选择**查看警告详细信息**以了解更多详情。具有只写属性的资源由生成的模板中使用的逻辑 ID 和资源类型标识。

   使用警告列表来识别具有只写属性的资源，并查看每个资源以确定需要对生成的模板进行哪些更改（如果有）。  
![\[IaC 生成器控制台关于生成的模板中包含只写属性的详细警告\]](http://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/images/IaC-generator-write-only-property-resource-warning.png)

1. 如果必须更新模板才能解决只写属性问题，请执行以下操作：

   1. 选择**下载**以下载模板的副本。

   1. 编辑模板。

   1. 完成更改后，您可以选择**导入已编辑的模板**按钮以继续完成导入过程。

# 如何解决 AWS::ApiGateway::RestAPI 资源中的只写属性问题
<a name="generate-IaC-apigateway-restapi"></a>

本主题介绍如何解决在使用 IaC 生成器时的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-apigateway-restapi.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-apigateway-restapi.html) 资源只写属性问题。

## 问题
<a name="apigateway-restapi-write-only-properties-issue"></a>

当生成的模板包含 `AWS::ApiGateway::RestApi` 资源时，会生成警告，指明 `Body`、`BodyS3Location` 和 `CloneFrom` 属性将标识为 `UNSUPPORTED_PROPERTIES`。这是因为这些是可选的只写属性。IaC 生成器不知道这些属性是否曾应用于资源，因此生成的模板中会忽略这些属性。

## 解决方案
<a name="apigateway-restapi-write-only-properties-resolution"></a>

要为您的 REST API 设置 `Body` 属性，请更新生成的模板。

1. 使用 Amazon API Gateway [https://docs.amazonaws.cn/apigateway/latest/api/API_GetExport.html](https://docs.amazonaws.cn/apigateway/latest/api/API_GetExport.html) API 操作下载 API。例如，通过使用 [https://docs.amazonaws.cn/cli/latest/reference/apigateway/get-export.html](https://docs.amazonaws.cn/cli/latest/reference/apigateway/get-export.html) Amazon CLI 命令。有关更多信息，请参阅《API Gateway 开发人员指南》**中的[从 API Gateway 导出 REST API](https://docs.amazonaws.cn/apigateway/latest/developerguide/api-gateway-export-api.html)。

1. 从 `GetExport` API 操作的响应中检索 `Body` 属性。将其上传到 Amazon S3 存储桶。

1. 下载生成的模板。

1. 将 `BodyS3Location/Bucket` 和 `BodyS3Location/Key` 属性添加到模板中，指定存储 `Body` 的桶名称和密钥。

1. 在 IaC 生成器控制台中打开生成的模板，然后选择**导入编辑的模板**。

# 如何解决 AWS::Lambda::Function 资源中的只写属性问题
<a name="generate-IaC-lambda-function"></a>

本主题介绍如何解决在使用 IaC 生成器时的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html) 资源只写属性问题。

## 问题
<a name="lambda-function-mutually-exclusive-properties-issue"></a>

`AWS::Lambda::Function` 资源具有三组互斥属性，用于指定 Lambda 代码：
+ `Code/S3Bucket` 和 `Code/S3Key` 属性，以及可选的 `Code/S3ObjectVersion` 属性
+ `Code/ImageUri` 属性
+ `Code/ZipFile` 属性

任何给定的 `AWS::Lambda::Function` 资源只能使用其中的一组属性。

IaC 生成器无法确定使用了哪组互斥只写属性来创建或更新资源，因此，生成的模板中仅包含第一组属性。`Code/ImageUri` 和 `Code/ZipFile` 属性将被忽略。

此外，IaC 生成器会发出以下警告：
+ **`MUTUALLY_EXCLUSIVE_PROPERTIES`** – 警告 `Code/S3Bucket` 和 `Code/S3Key` 被标识为互斥属性。
+ **`UNSUPPORTED_PROPERTIES`** – 警告 `Code/S3ObjectVersion` 属性不受支持。

要在生成的模板中包含 `AWS::Lambda::Function` 资源，您必须下载模板并使用正确的代码属性更新该模板。

## 解决方案
<a name="lambda-function-mutually-exclusive-properties-resolution"></a>

**如果您将 Lambda 代码存储在 Amazon S3 存储桶中并且不使用 `S3ObjectVersion` 属性**，则无需任何修改即可导入生成的模板。在导入操作期间，IaC 生成器将要求您提供 Amazon S3 存储桶和密钥作为模板参数。

****如果将 Lambda 代码存储为 Amazon ECR 存储库**，则您可以按照以下说明更新您的模板：**

1. 下载生成的模板。

1. 从生成的模板中删除 `Code/S3Bucket` 和 `Code/S3Key` 属性的属性和相应参数。

1. 将生成的模板中已删除的属性替换为 `Code/ImageUri` 属性，指定 Amazon ECR 存储库的 URL。

1. 在 IaC 生成器控制台中打开生成的模板，然后选择**导入编辑的模板**按钮。

****如果您将 Lambda 代码存储为 zip 文件**，则可以按照以下说明更新您的模板：**

1. 下载生成的模板。

1. 从生成的模板中删除 `Code/S3Bucket` 和 `Code/S3Key` 属性的属性和相应参数。

1. 将生成的模板中已删除的属性替换为 `Code/ZipFile` 属性。

1. 在 IaC 生成器控制台中打开生成的模板，然后选择**导入编辑的模板**按钮。

****如果没有 Lambda 代码的副本**，则您可以按照以下说明更新您的模板：**

1. 使用 Amazon Lambda [https://docs.amazonaws.cn/lambda/latest/api/API_GetFunction.html](https://docs.amazonaws.cn/lambda/latest/api/API_GetFunction.html) API 操作（例如，通过使用 [https://docs.amazonaws.cn/cli/latest/reference/lambda/get-function.html](https://docs.amazonaws.cn/cli/latest/reference/lambda/get-function.html) Amazon CLI 命令）。

1. 在响应中，如果代码位于 Amazon S3 存储桶中，则 `RepositoryType` 参数为 `S3`；如果代码位于 Amazon ECR 存储库中，则该参数为 `ECR`。

1. 在响应中，`Location` 参数包含一个预签名 URL，您可以用其下载部署包 10 分钟。下载代码。

1. 将代码上传到 Amazon S3 存储桶。

1. 使用生成的模板运行导入操作，并提供桶名称和密钥作为参数值。

# 使用动态引用获取存储在其他服务中的值
<a name="dynamic-references"></a>

动态引用是一种十分便捷的方法，让您可以轻松指定在其他服务中存储和管理的外部值，并将敏感信息与基础设施即代码模板分离。在堆栈和更改集操作期间，CloudFormation 会在必要时检索指定引用的值。

借助动态引用，您可以：
+ **使用安全字符串** – 对于敏感数据，始终应使用 Amazon Systems Manager Parameter Store 中的安全字符串参数或 Amazon Secrets Manager 中的密钥来保证数据的静态加密。
+ **限制访问权限** – 仅允许获得授权的主体和角色访问 Parameter Store 参数或 Secrets Manager 密钥。
+ **轮换凭证** – 定期轮换存储在 Parameter Store 或 Secrets Manager 中的敏感数据，以确保高度的安全性。
+ **自动轮换** – 利用 Secrets Manager 的自动轮换功能定期更新和分配各种应用程序和环境中的敏感数据。

## 一般注意事项
<a name="dynamic-references-considerations"></a>

以下是在 CloudFormation 模板中指定动态引用之前的一般注意事项：
+ 不要在资源主标识符所包含资源属性中包含动态引用或任何敏感数据。CloudFormation 可能会在主资源标识符中使用实际的纯文本值，这可能存在安全风险。此资源 ID 可能出现在任何派生输出或目标中。

  要确定哪些资源属性构成了资源类型的主标识符，请参阅 [Amazon 资源和属性类型参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-template-resource-type-ref.html)中该资源的资源参考文档。在 **Return values**（返回值）部分，`Ref` 函数返回值，表示构成资源类型主标识符的资源属性。
+ 您最多可以在堆栈模板中包含 60 个动态引用。
+ 如果您使用的是转换（如 `AWS::Include` 或 `AWS::Serverless`），则 CloudFormation 在应用转换之前不会解析动态引用，而是将动态引用的明文字符串传递给转换，并在使用模板执行更改集时解析引用。
+ 动态引用不能用于自定义资源中的安全值（例如存储在 Parameter Store 或 Secrets Manager 中的值）。
+ `AWS::CloudFormation::Init` 元数据和 Amazon EC2 `UserData` 属性也不支持动态引用。
+ 不要创建以反斜杠（\$1）结尾的动态引用。CloudFormation 无法解析此类引用，这将导致堆栈操作失败。

以下主题提供了有关使用动态引用的信息和其他注意事项。

**Topics**
+ [

## 一般注意事项
](#dynamic-references-considerations)
+ [

# 获取 Systems Manager Parameter Store 中的纯文本值
](dynamic-references-ssm.md)
+ [

# 获取 Systems Manager Parameter Store 中的安全字符串值
](dynamic-references-ssm-secure-strings.md)
+ [

# 获取 Secrets Manager 中的密钥或密钥值
](dynamic-references-secretsmanager.md)

# 获取 Systems Manager Parameter Store 中的纯文本值
<a name="dynamic-references-ssm"></a>

在创建 CloudFormation 模板时，可能需要使用存储在 Parameter Store 中的纯文本值。Parameter Store 是 Amazon Systems Manager 的一项功能。有关 Parameter Store 的介绍，请参阅《Amazon Systems Manager 用户指南》中的 [Amazon Systems Manager Parameter Store](https://docs.amazonaws.cn/systems-manager/latest/userguide/systems-manager-parameter-store.html)**。

要在模板中使用 Parameter Store 中的明文值，请使用 `ssm` 动态引用。此引用让您能够访问 Parameter Store 中 `String` 或 `StringList` 类型的参数的值。

要验证堆栈操作中将使用哪个版本的 `ssm` 动态引用，请为堆栈操作创建更改集。然后，在**模板**选项卡上查看已处理的模板。有关更多信息，请参阅 [创建 CloudFormation 堆栈的更改集](using-cfn-updating-stacks-changesets-create.md)。

使用 `ssm` 动态引用时，需要注意几个重要的事项：
+ CloudFormation 不支持对动态引用进行偏差检测。对于尚未指定参数版本的 `ssm` 动态引用，建议在 Systems Manager 中更新参数版本时，还要对包含 `ssm` 动态引用的任何堆栈执行堆栈更新操作，以获取最新的参数版本。
+ 要在 CloudFormation 模板的 `Parameters` 部分中使用 `ssm` 动态引用，必须包含版本号。CloudFormation 不允许在这一部分中引用没有版本号的 Parameter Store 值。您也可以在模板中将您的参数定义为某个 Systems Manager 参数类型。执行此操作时，您可以将某个 Systems Manager 参数键指定为参数的默认值。然后，CloudFormation 将从 Parameter Store 中检索最新版本的参数值，而无需您指定版本号。这可以使您的模板更简洁、更易于维护。有关更多信息，请参阅 [使用 CloudFormation 提供的参数类型在运行时指定现有资源](cloudformation-supplied-parameter-types.md)。
+ 对于自定义资源，CloudFormation 在将请求发送到自定义资源之前解析 `ssm` 动态引用。
+ CloudFormation 不支持使用动态引用来引用另一个 Amazon Web Services 账户共享的参数。
+ CloudFormation 不支持在动态引用中使用 Systems Manager 参数标签。

## 权限
<a name="dynamic-references-ssm-permissions"></a>

要指定存储在 Systems Manager Parameter Store 中的参数，您必须有权为指定的参数调用 [https://docs.amazonaws.cn/systems-manager/latest/APIReference/API_GetParameter.html](https://docs.amazonaws.cn/systems-manager/latest/APIReference/API_GetParameter.html)。要了解如何创建提供对特定 Systems Manager 参数的访问权限的 IAM 策略，请参阅《*Amazon Systems Manager 用户指南*》中的[使用 IAM 策略限制对 Parameter Store 参数的访问](https://docs.amazonaws.cn/systems-manager/latest/userguide/sysman-paramstore-access.html)。

## 引用模式
<a name="dynamic-references-ssm-pattern"></a>

要在 CloudFormation 模板中引用 Systems Manager Parameter Store 中存储的明文值，请使用以下 `ssm` 引用模式。

```
{{resolve:ssm:parameter-name:version}}
```

您的引用必须遵循以下参数名称和版本的正则表达式模式：

```
{{resolve:ssm:[a-zA-Z0-9_.\-/]+(:\d+)?}}
```

`parameter-name`  
 Parameter Store 中的参数的名称。参数名称区分大小写。  
必需。

`version`  
一个整数，指定要使用的参数的版本。如果您没有指定确切的版本，CloudFormation 将在创建或更新堆栈时使用参数的最新版本。有关更多信息，请参阅《Amazon Systems Manager 用户指南》中的[使用参数版本](https://docs.amazonaws.cn/systems-manager/latest/userguide/sysman-paramstore-versions.html)**。  
可选。

## 示例
<a name="dynamic-references-ssm-examples"></a>

**Topics**
+ [

### 公用 AMI ID 参数
](#dynamic-references-ssm-public-ami-example)
+ [

### 自定义 AMI ID 参数
](#dynamic-references-ssm-custom-ami-example)

### 公用 AMI ID 参数
<a name="dynamic-references-ssm-public-ami-example"></a>

以下示例创建的 EC2 实例引用了一个公用 AMI 参数。动态引用从公有参数中检索最新版 Amazon Linux 2023 AMI ID。有关公有参数的更多信息，请参阅《Amazon Systems Manager 用户指南》**中的[发现 Parameter Store 中的公有参数](https://docs.amazonaws.cn/systems-manager/latest/userguide/parameter-store-finding-public-parameters.html)。

#### JSON
<a name="dynamic-references-ssm-public-ami-example.json"></a>

```
{
    "Resources": {
        "MyInstance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64}}",
                "InstanceType": "t2.micro"
            }
        }
    }
}
```

#### YAML
<a name="dynamic-references-ssm-public-ami-example.yaml"></a>

```
Resources:
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64}}'
      InstanceType: t2.micro
```

### 自定义 AMI ID 参数
<a name="dynamic-references-ssm-custom-ami-example"></a>

以下示例创建了一个 EC2 启动模板，其中引用了存储在 Parameter Store 中的自定义 AMI ID。每次从启动模板启动实例时，动态引用都会从 `golden-ami` 参数的版本 *`2`* 中检索 AMI ID。

#### JSON
<a name="dynamic-references-ssm-custom-ami-example.json"></a>

```
{
    "Resources": {
        "MyLaunchTemplate": {
            "Type": "AWS::EC2::LaunchTemplate",
            "Properties": {
                "LaunchTemplateName": {
                    "Fn::Sub": "${AWS::StackName}-launch-template"
                },
                "LaunchTemplateData": {
                    "ImageId": "{{resolve:ssm:golden-ami:2}}",
                    "InstanceType": "t2.micro"
                }
            }
        }
    }
}
```

#### YAML
<a name="dynamic-references-ssm-custom-ami-example.yaml"></a>

```
Resources:
  MyLaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties: 
      LaunchTemplateName: !Sub ${AWS::StackName}-launch-template
      LaunchTemplateData:
        ImageId: '{{resolve:ssm:golden-ami:2}}'
        InstanceType: t2.micro
```

# 获取 Systems Manager Parameter Store 中的安全字符串值
<a name="dynamic-references-ssm-secure-strings"></a>

在 CloudFormation 中，您可以将密码和许可证密钥等敏感数据作为“安全字符串”存储在 Amazon Systems Manager Parameter Store 中，从而在不直接在模板中直接公开的情况下使用这些数据。有关 Parameter Store 的介绍，请参阅《Amazon Systems Manager 用户指南》中的 [Amazon Systems Manager Parameter Store](https://docs.amazonaws.cn/systems-manager/latest/userguide/systems-manager-parameter-store.html)**。

要在模板中使用 Parameter Store 安全字符串，请使用 `ssm-secure` 动态引用。CloudFormation 永远不会存储实际的安全字符串值，而是仅存储包含安全字符串的纯文本参数名称的明文动态引用。

在创建或更新堆栈期间，CloudFormation 会根据需要访问安全字符串值，而不会暴露实际值。安全字符串只能用于支持 `ssm-secure` 动态引用模式的资源属性。有关更多信息，请参阅 [对安全字符串支持动态参数模式的资源](#template-parameters-dynamic-patterns-resources)。

CloudFormation 不会在任何 API 调用中返回安全字符串的实际参数值，而是仅返回明文动态引用。在使用更改集比较更改时，CloudFormation 仅会比较明文动态引用字符串，而不会解析并比较实际的安全字符串值。

使用 `ssm-secure` 动态引用时，需要注意几个重要的事项：
+ CloudFormation 无法访问来自其他 Amazon Web Services 账户的 Parameter Store 值。
+ CloudFormation 不支持在动态引用中使用 Systems Manager 参数标签或公有参数。
+ 在 `cn-north-1` 和 `cn-northwest-1` 区域，Systems Manager 不支持安全字符串。
+ 自定义资源中目前不支持对安全值的动态引用，例如 `ssm-secure`。
+ 如果 CloudFormation 需要回滚堆栈更新，同时先前指定的安全字符串参数版本不再可用，则回滚操作将会失败。在这种情况下，您有两个选择：
  + 使用 `CONTINUE_UPDATE_ROLLBACK` 跳过资源。
  + 在 Systems Manager Parameter Store 中重新创建安全字符串参数，并更新它，直到参数版本达到模板中使用的版本。然后使用 `CONTINUE_UPDATE_ROLLBACK` 而不跳过该资源。

## 对安全字符串支持动态参数模式的资源
<a name="template-parameters-dynamic-patterns-resources"></a>

支持 `ssm-secure` 动态引用模式的资源包括：


| 资源 | 属性类型 | 属性 | 
| --- | --- | --- | 
| [AWS::DirectoryService::MicrosoftAD](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-directoryservice-microsoftad.html) |  | `Password` | 
| [AWS::DirectoryService::SimpleAD](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-directoryservice-simplead.html) |  | `Password` | 
| [AWS::ElastiCache::ReplicationGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticache-replicationgroup.html) |  | `AuthToken` | 
| [AWS::IAM::User](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-user.html) | [LoginProfile](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-iam-user-loginprofile.html) | `Password` | 
| [AWS::KinesisFirehose::DeliveryStream](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-kinesisfirehose-deliverystream.html) | [RedshiftDestinationConfiguration](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-kinesisfirehose-deliverystream-redshiftdestinationconfiguration.html) | `Password` | 
| [AWS::OpsWorks::App](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-opsworks-app.html) | [源](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-opsworks-app-source.html) | `Password` | 
| [AWS::OpsWorks::Stack](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-opsworks-stack.html) | [CustomCookbooksSource](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-opsworks-stack-source.html) | `Password` | 
| [AWS::OpsWorks::Stack](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-opsworks-stack.html) | [RdsDbInstances](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-opsworks-stack-rdsdbinstance.html) | `DbPassword` | 
| [AWS::RDS::DBCluster](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbcluster.html) |  | `MasterUserPassword` | 
| [AWS::RDS::DBInstance](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbinstance.html) |  | `MasterUserPassword`  | 
| [AWS::Redshift::Cluster](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-redshift-cluster.html) |  | `MasterUserPassword` | 

## 引用模式
<a name="dynamic-references-ssm-secure-pattern"></a>

要在 CloudFormation 模板中引用 Systems Manager 参数存储中的安全字符串值，请使用以下 `ssm-secure` 引用模式。

```
{{resolve:ssm-secure:parameter-name:version}}
```

您的引用必须遵循以下参数名称和版本的正则表达式模式：

```
{{resolve:ssm-secure:[a-zA-Z0-9_.\-/]+(:\d+)?}}
```

`parameter-name`  
 Parameter Store 中的参数的名称。参数名称区分大小写。  
必需。

`version`  
一个整数，指定要使用的参数的版本。如果您没有指定确切的版本，CloudFormation 将在创建或更新堆栈时使用参数的最新版本。有关更多信息，请参阅《Amazon Systems Manager 用户指南》中的[使用参数版本](https://docs.amazonaws.cn/systems-manager/latest/userguide/sysman-paramstore-versions.html)**。  
可选。

## 示例
<a name="dynamic-references-ssm-secure-example"></a>

以下示例使用 `ssm-secure` 动态引用将 IAM 用户的密码设置为存储在 Parameter Store 中的安全字符串。如指定的那样，CloudFormation 将使用 `IAMUserPassword` 参数的版本 *`10`* 进行堆栈和更改集操作。

### JSON
<a name="dynamic-references-ssm-secure-example.json"></a>

```
  "MyIAMUser": {
    "Type": "AWS::IAM::User",
    "Properties": {
      "UserName": "MyUserName",
      "LoginProfile": {
        "Password": "{{resolve:ssm-secure:IAMUserPassword:10}}"
      }
    }
  }
```

### YAML
<a name="dynamic-references-ssm-secure-example.yaml"></a>

```
  MyIAMUser:
    Type: AWS::IAM::User
    Properties:
      UserName: 'MyUserName'
      LoginProfile:
        Password: '{{resolve:ssm-secure:IAMUserPassword:10}}'
```

# 获取 Secrets Manager 中的密钥或密钥值
<a name="dynamic-references-secretsmanager"></a>

Secrets Manager 是一项便于您安全存储和管理密钥的服务，例如数据库凭证、密码和第三方 API 密钥等。使用 Secrets Manager，您可以集中存储和控制对这些密钥的访问，以便使用对 Secrets Manager 的 API 调用来替换代码中的硬编码凭证（包括密码），以编程方式检索密钥。有关更多信息，请参阅《Amazon Secrets Manager 用户指南》中的[什么是 Amazon Secrets Manager？](https://docs.amazonaws.cn/secretsmanager/latest/userguide/intro.html)。

要在 CloudFormation 模板中使用 Secrets Manager 中存储的全部密钥或密钥值，请使用 `secretsmanager` 动态引用。

## 最佳实践
<a name="dynamic-references-secretsmanager-best-practices"></a>

在 CloudFormation 模板中使用 Secrets Manager 动态引用时，请遵循以下最佳实践：
+ **对 CloudFormation 模板使用无版本引用**：将凭证存储在 Secrets Manager 中并使用动态引用而不指定 `version-stage` 或 `version-id` 参数，以支持正确的密钥轮换工作流程。
+ **利用自动轮换**：使用 Secrets Manager 的自动轮换功能，结合无版本动态引用进行凭证管理。这可以确保您的凭证得到定期更新，而无需更改模板。有关更多信息，请参阅[轮换 Amazon Secrets Manager 密钥](https://docs.amazonaws.cn/secretsmanager/latest/userguide/rotating-secrets.html)。
+ **谨慎使用带版本引用**：仅为测试或回滚等特定场景指定显式的 `version-stage` 或 `version-id` 参数。

## 注意事项
<a name="dynamic-references-secretsmanager-considerations"></a>

使用 `secretsmanager` 动态引用时，需要记住以下重要注意事项：
+ CloudFormation 不会追踪之前的部署中使用了哪个版本的密钥。在实现动态引用之前，请认真规划您的密钥管理策略。尽量使用无版本引用，以利用自动密钥轮换功能。在更改动态引用配置时（例如从无版本动态引用改换为带版本动态引用，反之亦然）时，监控和验证资源更新。
+ 仅更新 Secrets Manager 中的密钥值不会自动触发 CloudFormation 检索新值。CloudFormation 仅在创建或更新资源修改包含动态引用的资源时检索密钥值。

  例如，假设您的模板包含 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbinstance.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbinstance.html) 资源，其中 `MasterPassword` 属性设置为 Secrets Manager 动态引用。使用此模板创建堆栈后，需要在 Secrets Manager 中更新密钥值。但是，`MasterPassword` 属性保留了旧密码值。

  要应用新密钥值，需修改 CloudFormation 模板中的 `AWS::RDS::DBInstance` 资源并执行堆栈更新。

  为避免将来执行这种手动过程，可考虑使用 Secrets Manager 自动轮换密钥。
+ 自定义资源中目前不支持对安全值的动态引用，例如 `secretsmanager`。
+ `secretsmanager` 动态引用可用于所有资源属性。使用 `secretsmanager` 动态引用表示 Secrets Manager 和 CloudFormation 日志均不应保留任何已解析的密钥值。但是，密钥值可能会显示在正在其资源中使用的服务中。检查您的使用情况，以避免泄露密钥数据。

## 权限
<a name="dynamic-references-secretsmanager-permissions"></a>

要指定存储在 Secrets Manager 中的密钥，您必须有权为该密钥调用 [https://docs.amazonaws.cn/secretsmanager/latest/apireference/API_GetSecretValue.html](https://docs.amazonaws.cn/secretsmanager/latest/apireference/API_GetSecretValue.html)。

## 引用模式
<a name="dynamic-references-secretsmanager-pattern"></a>

要在 CloudFormation 模板中引用 Secrets Manager 密钥，请使用以下 `secretsmanager` 引用模式。

```
{{resolve:secretsmanager:secret-id:secret-string:json-key:version-stage:version-id}}
```

`secret-id`  
密钥的名称或 ARN。  
要访问您的 Amazon Web Services 账户中的密钥，只需指定密钥名称即可。要访问其他 Amazon Web Services 账户中的密钥，请指定密钥的完整 ARN。  
必需。

`secret-string`  
`SecretString` 是唯一受支持的值。默认值为 `SecretString`。

`json-key`  
要检索其值的键值对的键名称。如果您不指定 `json-key`，CloudFormation 会检索整个密钥文本。  
此分段不得包含冒号字符 ( `:` )。

`version-stage`  
要使用的密钥版本的暂存标签。Secrets Manager 在轮换过程中使用暂存标注来跟踪不同的版本。如果您使用 `version-stage`，则不要指定 `version-id`。如果您既未指定 `version-stage`，也未指定 `version-id`，则原定设置将为 `AWSCURRENT` 版本。  
此分段不得包含冒号字符 ( `:` )。

`version-id`  
要使用的密钥版本的唯一标识符。如果指定 `version-id`，则不要指定 `version-stage`。如果您既未指定 `version-stage`，也未指定 `version-id`，则原定设置将为 `AWSCURRENT` 版本。  
此分段不得包含冒号字符 ( `:` )。

## 示例
<a name="dynamic-references-secretsmanager-examples"></a>

**Topics**
+ [

### 从密钥中检索用户名和密码值
](#dynamic-references-secretsmanager-examples-user-name-and-password)
+ [

### 检索整个 SecretString
](#dynamic-references-secretsmanager-examples-entire-secretstring)
+ [

### 从密钥的特定版本中检索值
](#dynamic-references-secretsmanager-examples-specific-version)
+ [

### 从另一个 Amazon Web Services 账户检索密钥
](#dynamic-references-secretsmanager-examples-secrets-from-another-account)

### 从密钥中检索用户名和密码值
<a name="dynamic-references-secretsmanager-examples-user-name-and-password"></a>

以下 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbinstance.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbinstance.html) 示例检索在 `MySecret` 密钥中存储的用户名和密码值。此示例展示了无版本动态引用的推荐模式，该模式自动使用 `AWSCURRENT` 版本且支持 Secrets Manager 轮换工作流程，而无需更改模板。

#### JSON
<a name="dynamic-references-secretsmanager-examples-user-name-and-password.json"></a>

```
{
    "MyRDSInstance": {
        "Type": "AWS::RDS::DBInstance",
        "Properties": {
            "DBName": "MyRDSInstance",
            "AllocatedStorage": "20",
            "DBInstanceClass": "db.t2.micro",
            "Engine": "mysql",
            "MasterUsername": "{{resolve:secretsmanager:MySecret:SecretString:username}}",
            "MasterUserPassword": "{{resolve:secretsmanager:MySecret:SecretString:password}}"
        }
    }
}
```

#### YAML
<a name="dynamic-references-secretsmanager-examples-user-name-and-password.yaml"></a>

```
  MyRDSInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBName: MyRDSInstance
      AllocatedStorage: '20'
      DBInstanceClass: db.t2.micro
      Engine: mysql
      MasterUsername: '{{resolve:secretsmanager:MySecret:SecretString:username}}'
      MasterUserPassword: '{{resolve:secretsmanager:MySecret:SecretString:password}}'
```

### 检索整个 SecretString
<a name="dynamic-references-secretsmanager-examples-entire-secretstring"></a>

以下动态引用检索 `MySecret` 的 `SecretString`。

```
{{resolve:secretsmanager:MySecret}}
```

或者：

```
{{resolve:secretsmanager:MySecret::::}}
```

### 从密钥的特定版本中检索值
<a name="dynamic-references-secretsmanager-examples-specific-version"></a>

以下动态引用检索 `MySecret` 的 `AWSPREVIOUS` 版本的 `password` 值。

```
{{resolve:secretsmanager:MySecret:SecretString:password:AWSPREVIOUS}}
```

### 从另一个 Amazon Web Services 账户检索密钥
<a name="dynamic-references-secretsmanager-examples-secrets-from-another-account"></a>

以下动态引用检索另一个 Amazon Web Services 账户中的 `MySecret` 的 `SecretString`。您必须指定完整的密钥 ARN 才能访问其他 Amazon Web Services 账户中的密钥。

```
{{resolve:secretsmanager:arn:aws:secretsmanager:us-west-2:123456789012:secret:MySecret}}
```

以下动态引用检索另一个 Amazon Web Services 账户中的 `MySecret` 的 `password` 值。您必须指定完整的密钥 ARN 才能访问其他 Amazon Web Services 账户中的密钥。

```
{{resolve:secretsmanager:arn:aws:secretsmanager:us-west-2:123456789012:secret:MySecret:SecretString:password}}
```

# 使用伪参数获取 Amazon 值
<a name="pseudo-parameter-reference"></a>

伪参数是内置变量，用于提供对重要 Amazon 环境信息的访问权限，例如可能因部署或环境的不同而发生变化的账户 ID、区域名称和堆栈详细信息等。

您可以使用伪参数代替硬编码值，以此确保模板更便于移植，更易于跨不同 Amazon Web Services 账户和区域重复使用。

## 语法
<a name="pseudo-parameter-syntax"></a>

您可以使用 `Ref` 内置函数或 `Fn::Sub` 内部函数来引用伪参数。

### Ref
<a name="pseudo-parameter-ref-syntax"></a>

`Ref` 内置函数使用以下常规语法。有关更多信息，请参阅 [Ref](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-ref.html)。

#### JSON
<a name="pseudo-parameter-ref-syntax.json"></a>

```
{ "Ref" : "AWS::PseudoParameter" }
```

#### YAML
<a name="pseudo-parameter-ref-syntax.yaml"></a>

```
!Ref AWS::PseudoParameter
```

### Fn::Sub
<a name="pseudo-parameter-sub-syntax"></a>

`Fn::Sub` 内置函数使用不同的格式，其中包括伪参数周围的 `${}` 语法。有关更多信息，请参阅 [Fn::Sub](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-sub.html)。

#### JSON
<a name="pseudo-parameter-sub-syntax.json"></a>

```
{ "Fn::Sub" : "${AWS::PseudoParameter}" }
```

#### YAML
<a name="pseudo-parameter-sub-syntax.yaml"></a>

```
!Sub '${AWS::PseudoParameter}'
```

## 可用伪参数
<a name="available-pseudo-parameters"></a>

### `AWS::AccountId`
<a name="cfn-pseudo-param-accountid"></a>

返回在其中创建堆栈的账户的 Amazon Web Services 账户 ID，如 `123456789012`。

此伪参数通常用于定义 IAM 角色、策略和其他涉及账户特定 ARN 的资源策略。

### `AWS::NotificationARNs`
<a name="cfn-pseudo-param-notificationarns"></a>

返回接收堆栈事件通知的 Amazon SNS 主题的 Amazon 资源名称（ARN）列表。在创建或更新堆栈时，您可以通过 Amazon CLI 中的 `--notification-arns` 选项或通过控制台指定这些 ARN。

与返回单个值的其他伪参数不同，`AWS::NotificationARNs` 会返回 ARN 列表。要访问列表中的特定 ARN，使用 `Fn::Select` 内置函数。有关更多信息，请参阅 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-select.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-select.html)。

### `AWS::NoValue`
<a name="cfn-pseudo-param-novalue"></a>

如果在 `Fn::If` 内部函数中指定为返回值，则删除相应的资源属性。有关更多信息，请参阅 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-if](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-if)。

如果需要创建只有在特定条件下才会被包含的条件资源属性，此伪参数特别有用。

### `AWS::Partition`
<a name="cfn-pseudo-param-partition"></a>

返回资源所处的分区。对于标准 Amazon Web Services 区域，分区是 `aws`。对于位于其他分区中的资源，则分区是 `aws-`*partitionname*。例如，中国（北京和宁夏）区域中的资源的分区为 `aws-cn`，Amazon GovCloud（US-West）区域中的资源的分区为 `aws-us-gov`。

分区是资源 ARN 的一部分。使用 `AWS::Partition` 可确保模板在不同的 Amazon 分区中正常运行。

### `AWS::Region`
<a name="cfn-pseudo-param-region"></a>

返回代表在其中创建包容性资源的区域的字符串，如 `us-west-2`。

这是最常用的伪参数之一，因为它能让模板适应不同的 Amazon Web Services 区域，无需另行修改。

### `AWS::StackId`
<a name="cfn-pseudo-param-stackid"></a>

返回堆栈 ID（ARN），例如 `arn:aws:cloudformation:us-west-2:123456789012:stack/teststack/51af3dc0-da77-11e4-872e-1234567db123`。

### `AWS::StackName`
<a name="cfn-pseudo-param-stackname"></a>

返回堆栈名称，例如 `teststack`。

堆栈名称通常用于创建唯一资源名称，方便轻松识别出相应堆栈。

### `AWS::URLSuffix`
<a name="cfn-pseudo-param-urlsuffix"></a>

返回堆栈部署所在的 Amazon Web Services 区域中的 Amazon 域后缀。后缀通常为 `amazonaws.com`，但中国（北京）区域的后缀为 `amazonaws.com.cn`。

在为 Amazon 服务端点构建 URL 时，此参数特别有用。

## 示例
<a name="pseudo-parameter-examples"></a>

**Topics**
+ [

### 基本用法
](#pseudo-parameter-basic-example)
+ [

### 使用 AWS::NotificationARNs
](#pseudo-parameter-notification-example)
+ [

### AWS::NoValue 条件属性
](#pseudo-parameter-novalue-example)

### 基本用法
<a name="pseudo-parameter-basic-example"></a>

以下示例创建了两个资源：一个 Amazon SNS 主题和一个向该主题发送通知的 CloudWatch 警报。它们使用 `AWS::StackName`、`AWS::Region` 和 `AWS::AccountId` 将堆栈名称、当前 Amazon Web Services 区域和账户 ID 动态插入到资源名称、描述和 ARN 中。

#### JSON
<a name="pseudo-parameter-basic-example.json"></a>

```
{
    "Resources": {
        "MyNotificationTopic": {
            "Type": "AWS::SNS::Topic",
            "Properties": {
                "DisplayName": { "Fn::Sub": "Notifications for ${AWS::StackName}" }
            }
        },
        "CPUAlarm": {
            "Type": "AWS::CloudWatch::Alarm",
            "Properties": {
                "AlarmDescription": { "Fn::Sub": "Alarm for high CPU in ${AWS::Region}" },
                "AlarmName": { "Fn::Sub": "${AWS::StackName}-HighCPUAlarm" },
                "MetricName": "CPUUtilization",
                "Namespace": "AWS/EC2",
                "Statistic": "Average",
                "Period": 300,
                "EvaluationPeriods": 1,
                "Threshold": 80,
                "ComparisonOperator": "GreaterThanThreshold",
                "AlarmActions": [{ "Fn::Sub": "arn:aws:sns:${AWS::Region}:${AWS::AccountId}:${MyNotificationTopic}" }]
            }
        }
    }
}
```

#### YAML
<a name="pseudo-parameter-basic-example.yaml"></a>

```
Resources:
  MyNotificationTopic:
    Type: AWS::SNS::Topic
    Properties:
      DisplayName: !Sub Notifications for ${AWS::StackName}
  CPUAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmDescription: !Sub Alarm for high CPU in ${AWS::Region}
      AlarmName: !Sub ${AWS::StackName}-HighCPUAlarm
      MetricName: CPUUtilization
      Namespace: AWS/EC2
      Statistic: Average
      Period: 300
      EvaluationPeriods: 1
      Threshold: 80
      ComparisonOperator: GreaterThanThreshold
      AlarmActions:
        - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:${MyNotificationTopic}
```

### 使用 AWS::NotificationARNs
<a name="pseudo-parameter-notification-example"></a>

以下示例配置了一个自动扩缩组来发送有关实例启动事件和启动错误的通知。该配置使用 `AWS::NotificationARNs` 伪参数，提供堆栈创建期间指定的 Amazon SNS 主题 ARN 的列表。`Fn::Select` 函数会从该列表中选择第一个 ARN。

#### JSON
<a name="pseudo-parameter-notification-example.json"></a>

```
"myASG": {
   "Type": "AWS::AutoScaling::AutoScalingGroup",
   "Properties": {
      "LaunchTemplate": {
         "LaunchTemplateId": { "Ref": "myLaunchTemplate" },
         "Version": { "Fn::GetAtt": [ "myLaunchTemplate", "LatestVersionNumber" ] }
       },
       "MaxSize": "1",
       "MinSize": "1",
       "VPCZoneIdentifier": [
          "subnetIdAz1",
          "subnetIdAz2",
          "subnetIdAz3"
      ],
      "NotificationConfigurations" : [{
         "TopicARN" : { "Fn::Select" : [ "0", { "Ref" : "AWS::NotificationARNs" } ] },
         "NotificationTypes" : [ "autoscaling:EC2_INSTANCE_LAUNCH", "autoscaling:EC2_INSTANCE_LAUNCH_ERROR" ]
      }]
   }
}
```

#### YAML
<a name="pseudo-parameter-notification-example.yaml"></a>

```
myASG:
  Type: AWS::AutoScaling::AutoScalingGroup
  Properties:
    LaunchTemplate:
      LaunchTemplateId: !Ref myLaunchTemplate
      Version: !GetAtt myLaunchTemplate.LatestVersionNumber
    MinSize: '1'
    MaxSize: '1'
    VPCZoneIdentifier:
      - subnetIdAz1
      - subnetIdAz2
      - subnetIdAz3
    NotificationConfigurations:
      - TopicARN:
          Fn::Select:
          - '0'
          - Ref: AWS::NotificationARNs
        NotificationTypes:
        - autoscaling:EC2_INSTANCE_LAUNCH
        - autoscaling:EC2_INSTANCE_LAUNCH_ERROR
```

### AWS::NoValue 条件属性
<a name="pseudo-parameter-novalue-example"></a>

以下示例创建了一个 Amazon RDS 数据库实例，仅当提供了快照 ID 时，该数据库实例才会使用快照。如果 `UseDBSnapshot` 条件计算为 true，则 CloudFormation 对 `DBSnapshotIdentifier` 属性使用 `DBSnapshotName` 参数值。如果条件计算为 false，则 CloudFormation 删除 `DBSnapshotIdentifier` 属性。

#### JSON
<a name="pseudo-parameter-novalue-example.json"></a>

```
"MyDB" : {
  "Type" : "AWS::RDS::DBInstance",
  "Properties" : {
    "AllocatedStorage" : "5",
    "DBInstanceClass" : "db.t2.small",
    "Engine" : "MySQL",
    "EngineVersion" : "5.5",
    "MasterUsername" : { "Ref" : "DBUser" },
    "MasterUserPassword" : { "Ref" : "DBPassword" },
    "DBParameterGroupName" : { "Ref" : "MyRDSParamGroup" },
    "DBSnapshotIdentifier" : {
      "Fn::If" : [
        "UseDBSnapshot",
        {"Ref" : "DBSnapshotName"},
        {"Ref" : "AWS::NoValue"}
      ]
    }
  }
}
```

#### YAML
<a name="pseudo-parameter-novalue-example.yaml"></a>

```
MyDB:
  Type: AWS::RDS::DBInstance
  Properties:
    AllocatedStorage: '5'
    DBInstanceClass: db.t2.small
    Engine: MySQL
    EngineVersion: '5.5'
    MasterUsername:
      Ref: DBUser
    MasterUserPassword:
      Ref: DBPassword
    DBParameterGroupName:
      Ref: MyRDSParamGroup
    DBSnapshotIdentifier:
      Fn::If:
        - UseDBSnapshot
        - Ref: DBSnapshotName
        - Ref: AWS::NoValue
```

# 获取从已部署的 CloudFormation 堆栈导出的输出
<a name="using-cfn-stack-exports"></a>

如果在同一 Amazon Web Services 账户和区域中有多个堆栈，您可能需要在这些堆栈之间共享信息。当一个堆栈需要使用另一个堆栈创建的资源时，此功能非常实用。

例如，您可能有一个堆栈为您的 Web 服务器创建子网和安全组等网络资源。然后，创建实际 Web 服务器的其他堆栈可以使用第一个堆栈创建的网络资源。您无需对堆栈的模板中的资源 ID 进行硬编码或将 ID 作为输入参数传递。

要在堆栈之间共享信息，请从一个堆栈中*导出*输出值，然后将这些值*导入*另一个堆栈。下面将介绍操作方式：

1. 在第一个堆栈的模板（例如，联网堆栈）中，您可以使用 `Outputs` 部分中的 `Export` 字段来定义要导出的特定值。有关更多信息，请参阅 [CloudFormation 模板 Outputs 语法](outputs-section-structure.md)。

1. 当您创建或更新该堆栈时，CloudFormation 会导出输出值，使其可供同一 Amazon Web Services 账户和区域中的其他堆栈使用。

1. 在另一个堆栈的模板中，您可以使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-importvalue.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-importvalue.html) 函数导入从第一个堆栈导出的值。

1. 创建或更新第二个堆栈（例如，Web 服务器堆栈）时，CloudFormation 会自动从第一个堆栈中检索并使用导出的值。

有关演练和示例模板，请参阅[引用其他 CloudFormation 堆栈中的资源输出](walkthrough-crossstackref.md)。

## 导出堆栈输出值与使用嵌套堆栈
<a name="output-vs-nested"></a>

嵌套堆栈是您使用 `AWS::CloudFormation::Stack` 资源在其他堆栈中创建的堆栈。利用嵌套堆栈，您可从一个堆栈部署和管理所有资源。您可将来自嵌套堆栈组中的一个堆栈的输出用作该组中的另一个堆栈的输入。这不同于导出值。

如果您要将信息共享隔离在嵌套堆栈组中，建议您使用嵌套堆栈。要与其他堆栈 (不只是在嵌套堆栈组中) 共享信息，请导出值。例如，您可使用某个子网创建一个堆栈，然后导出其 ID。其他堆栈可通过导入子网的 ID 来使用该子网。每个堆栈都不需要创建自己的子网。只要堆栈导入子网 ID，您就无法更改或删除它。

有关嵌套堆栈的更多信息，请参阅[使用嵌套堆栈将模板拆分为可重复使用的部分](using-cfn-nested-stacks.md)。

## 注意事项
<a name="using-cfn-stack-exports-considerations"></a>

以下限制适用于跨堆栈引用：
+ 对于每个 Amazon Web Services 账户，`Export` 名称在区域内必须是唯一的。
+ 不能跨区域创建跨堆栈引用。您可以使用内置函数 `Fn::ImportValue` 仅导入已在同一区域内导出的值。
+ 对于输出，`Export` 的 `Name` 属性值无法使用依赖于资源的 `Ref` 或 `GetAtt` 函数。

  同样，`ImportValue` 函数无法包含依赖于资源的 `Ref` 或 `GetAtt` 函数。
+ 在另一个堆栈导入输出值后，您将无法删除正在导出输出值的堆栈或修改已导出的输入值。必须先删除所有导入，然后才能删除导出堆栈或修改输出值。

## 列出导出的输出值
<a name="using-cfn-stack-exports-listing"></a>

如果您需要查看从堆栈导出的输出值，则请使用以下方法之一：

**列出已导出输出值（控制台）**

1. 通过以下网址打开 Amazon CloudFormation 控制台：[https://console.aws.amazon.com/cloudformation](https://console.amazonaws.cn/cloudformation/)。

1. 在屏幕顶部的导航栏中，选择您的 Amazon Web Services 区域。

1. 从左侧导航窗格中选择**导出**。

**列出已导出输出值 (Amazon CLI)**  
使用以下 [https://docs.amazonaws.cn/cli/latest/reference/cloudformation/list-exports.html](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/list-exports.html) 命令。将 *us-east-1* 替换为您的 Amazon Web Services 区域。

```
aws cloudformation list-exports --region us-east-1
```

下面是示例输出。

```
{
    "Exports": [
        {
            "ExportingStackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/private-vpc/99764070-b56c-xmpl-bee8-062a88d1d800",
            "Name": "private-vpc-subnet-a",
            "Value": "subnet-07b410xmplddcfa03"
        },
        {
            "ExportingStackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/private-vpc/99764070-b56c-xmpl-bee8-062a88d1d800",
            "Name": "private-vpc-subnet-b",
            "Value": "subnet-075ed3xmplebd2fb1"
        },
        {
            "ExportingStackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/private-vpc/99764070-b56c-xmpl-bee8-062a88d1d800",
            "Name": "private-vpc-vpcid",
            "Value": "vpc-011d7xmpl100e9841"
        }
    ]
}
```

CloudFormation 会显示当前区域已导出输出的名称和值，以及导出这些输出的来源堆栈。要在其他堆栈的模板中使用导出的输出值，请使用导出名称和 `Fn::ImportValue` 函数来引用该输出值。

## 列出导入已导出输出值的堆栈
<a name="using-cfn-stack-imports"></a>

要删除或更改导出的输出值，必须首先确定要导入这些输出值的堆栈。

要查看导入导出的输出值的堆栈，请使用以下方法之一：

**列出导入已导出的输出值的堆栈 (控制台)**

1. 通过以下网址打开 Amazon CloudFormation 控制台：[https://console.aws.amazon.com/cloudformation](https://console.amazonaws.cn/cloudformation/)。

1. 从左侧导航窗格中选择**导出**。

1. 要查看哪些堆栈导入给定的导出值，请选择该导出值的 **Export Name**（导出名称）。CloudFormation 会显示导出详细信息页面，其中列出了要导入值的所有堆栈。

**列出导入已导出的输出值的堆栈 (Amazon CLI)**  
使用 [https://docs.amazonaws.cn/cli/latest/reference/cloudformation/list-imports.html](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/list-imports.html) 命令。将 *us-east-1* 替换为您的 Amazon Web Services 区域，并将 `private-vpc-vpcid` 替换为所导出输出值的名称。

```
aws cloudformation list-imports --region us-east-1 \
    --export-name private-vpc-vpcid
```

CloudFormation 将返回正在导入该值的堆栈的列表。

```
{
    "Imports": [
        "my-app-stack"
    ]
}
```

确定要导入特定导出值的堆栈后，您需要修改这些堆栈以移除引用相关输出值的 `Fn::ImportValue` 函数。您必须先删除引用了已导出输出值的所有导入，然后才能删除或修改已导出的输出值。

# 使用 CloudFormation 提供的参数类型在运行时指定现有资源
<a name="cloudformation-supplied-parameter-types"></a>

创建模板时，您可以使用 CloudFormation 提供的专用参数类型创建要求用户输入现有 Amazon 资源标识符或 Systems Manager 参数的参数。

**Topics**
+ [

## 概述
](#cloudformation-supplied-parameter-types-overview)
+ [

## 示例
](#cloudformation-supplied-parameter-types-example)
+ [

## 注意事项
](#cloudformation-supplied-parameter-types-considerations)
+ [

## 支持的特定于 Amazon 的参数类型
](#aws-specific-parameter-types-supported)
+ [

## 支持的 Systems Manager 参数类型
](#systems-manager-parameter-types-supported)
+ [

## 不支持的 Systems Manager 参数类型
](#systems-manager-parameter-types-unsupported)

## 概述
<a name="cloudformation-supplied-parameter-types-overview"></a>

在 CloudFormation 中，您可以通过在堆栈创建或更新期间提供输入值，从而使用参数来自定义堆栈。此功能使您的模板可以在不同的场景中重复使用并提高灵活性。

参数是在 CloudFormation 模板的 `Parameters` 部分中定义的。每个参数都有一个名称和一个类型，此外还可以配置其他设置，例如默认值和允许值。有关更多信息，请参阅 [CloudFormation 模板 Parameters 语法](parameters-section-structure.md)。

参数类型决定了参数可以接受的输入值种类。例如，`Number` 只接受数值，而 `String` 可接受文本输入。

CloudFormation 提供了几种额外的参数类型，您可以在模板中使用这些参数类型来引用现有 Amazon 资源和 Systems Manager 参数。

这些参数类型分为两类：
+ **Amazon 特定参数类型**：CloudFormation 提供了一组参数类型，可帮助在创建或更新堆栈时捕获无效值。当您使用这些参数类型时，使用您模板的任何人都必须指定其创建堆栈的 Amazon Web Services 账户和区域中的有效值。

  如果他们使用 Amazon Web Services 管理控制台，则 CloudFormation 会预先填充其账户和区域现有值的列表。这样一来，用户便无需记住和正确键入特定的名称或 ID，相反，他们只需从下拉列表中选择值。在某些情况下，他们甚至还可以按 ID、名称或 `Name` 标签值来搜索值。
+ **Systems Manager 参数类型**：CloudFormation 还提供与 Systems Manager Parameter Store 中现有参数相对应的参数类型。当您使用这些参数类型时，使用您的模板的任何人都必须指定 Parameter Store 键作为 Systems Manager 参数类型的值，然后 CloudFormation 从 Parameter Store 中检索最新值以在其堆栈中使用。当您需要使用新亚马逊机器映像（AMI）ID 等新属性值来频繁更新应用程序时，这可能非常实用。有关 Parameter Store 的更多信息，请参阅 [Systems Manager Parameter Store](https://docs.amazonaws.cn/systems-manager/latest/userguide/systems-manager-parameter-store.html)。

在 `Parameters` 部分中定义参数后，您可以使用 `Ref` 函数在整个 CloudFormation 模板中引用这些参数值。

## 示例
<a name="cloudformation-supplied-parameter-types-example"></a>

以下示例展示一个使用以下参数类型的模板。
+ `AWS::EC2::VPC::Id`
+ `AWS::EC2::Subnet::Id`
+ `AWS::EC2::KeyPair::KeyName`
+ `AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>`

要通过此模板创建堆栈，您必须指定账户中的现有 VPC ID、子网 ID 和密钥对名称。您也可以指定引用所需 AMI ID 的现有 Parameter Store 键或保留 `/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2` 的默认值。此公有参数是最新 Amazon Linux 2 AMI 的区域 AMI ID 的别名。有关公有参数的更多信息，请参阅《Amazon Systems Manager 用户指南》**中的[发现 Parameter Store 中的公有参数](https://docs.amazonaws.cn/systems-manager/latest/userguide/parameter-store-finding-public-parameters.html)。

### JSON
<a name="cloudformation-supplied-parameter-types-example.json"></a>

```
{
    "Parameters": {
        "VpcId": {
            "Description": "ID of an existing Virtual Private Cloud (VPC).",
            "Type": "AWS::EC2::VPC::Id"
        },
        "PublicSubnetId": {
            "Description": "ID of an existing public subnet within the specified VPC.",
            "Type": "AWS::EC2::Subnet::Id"
        },
        "KeyName": {
            "Description": "Name of an existing EC2 key pair to enable SSH access to the instance.",
            "Type": "AWS::EC2::KeyPair::KeyName"
        },
        "AMIId": {
            "Description": "Name of a Parameter Store parameter that stores the ID of the Amazon Machine Image (AMI).",
            "Type": "AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>",
            "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
        }
    },
    "Resources": {
        "InstanceSecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": "Enable SSH access via port 22",
                "VpcId": { "Ref": "VpcId" },
                "SecurityGroupIngress": [
                    {
                        "IpProtocol": "tcp",
                        "FromPort": 22,
                        "ToPort": 22,
                        "CidrIp": "0.0.0.0/0"
                    }
                ]
            }
        },
        "Ec2Instance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "KeyName": { "Ref": "KeyName" },
                "ImageId": { "Ref": "AMIId" },
                "NetworkInterfaces": [
                    {
                        "AssociatePublicIpAddress": "true",
                        "DeviceIndex": "0",
                        "SubnetId": { "Ref": "PublicSubnetId" },
                        "GroupSet": [{ "Ref": "InstanceSecurityGroup" }]
                    }
                ]
            }
        }
    },
    "Outputs": {
        "InstanceId": {
            "Value": { "Ref": "Ec2Instance" }
        }
    }
}
```

### YAML
<a name="cloudformation-supplied-parameter-types-example.yaml"></a>

```
Parameters:
  VpcId:
    Description: ID of an existing Virtual Private Cloud (VPC).
    Type: AWS::EC2::VPC::Id
  PublicSubnetId:
    Description: ID of an existing public subnet within the specified VPC.
    Type: AWS::EC2::Subnet::Id
  KeyName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instance.
    Type: AWS::EC2::KeyPair::KeyName
  AMIId:
    Description: Name of a Parameter Store parameter that stores the ID of the Amazon Machine Image (AMI).
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
Resources:
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable SSH access via port 22
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
  Ec2Instance:
    Type: AWS::EC2::Instance
    Properties:
      KeyName: !Ref KeyName
      ImageId: !Ref AMIId
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnetId
          GroupSet:
            - !Ref InstanceSecurityGroup
Outputs:
  InstanceId:
    Value: !Ref Ec2Instance
```

### 用于创建堆栈的 Amazon CLI 命令
<a name="cloudformation-supplied-parameter-types-cli-command"></a>

以下 [https://docs.amazonaws.cn/cli/latest/reference/cloudformation/create-stack.html](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/create-stack.html) 命令基于示例模板创建堆栈。

```
aws cloudformation create-stack --stack-name MyStack \
  --template-body file://sampletemplate.json \
  --parameters \
ParameterKey="VpcId",ParameterValue="vpc-a123baa3" \
ParameterKey="PublicSubnetId",ParameterValue="subnet-123a351e" \
ParameterKey="KeyName",ParameterValue="MyKeyName" \
ParameterKey="AMIId",ParameterValue="MyParameterKey"
```

要使用接受字符串列表的参数类型（例如 `List<AWS::EC2::Subnet::Id>`），必须使用双反斜杠对 `ParameterValue` 中的逗号进行转义，如以下示例所示。

```
--parameters ParameterKey="SubnetIDs",ParameterValue="subnet-5ea0c127\\,subnet-6194ea3b\\,subnet-c87f2be0"
```

## 注意事项
<a name="cloudformation-supplied-parameter-types-considerations"></a>

强烈建议使用动态引用来限制对敏感配置定义（例如第三方凭证）的访问。有关更多信息，请参阅 [使用动态引用获取存储在其他服务中的值](dynamic-references.md)。

如果要允许模板用户指定不同 Amazon Web Services 账户的值，则请不要使用 Amazon 特定参数类型。而是应定义 `String` 或 `CommaDelimitedList` 类型的参数。

对于 Systems Manager 参数类型，需要注意以下几点：
+ 您可以在控制台中或通过运行 [https://docs.amazonaws.cn/cli/latest/reference/cloudformation/describe-stacks.html](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/describe-stacks.html) 或 [https://docs.amazonaws.cn/cli/latest/reference/cloudformation/describe-change-set.html](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/describe-change-set.html) 来查看堆栈的**参数**选项卡上的已解析参数值。请记住，这些值是在创建或更新堆栈时设置的，因此它们可能与 Parameter Store 中的最新值不同。
+ 对于堆栈更新，当您使用**使用现有值**选项（或将 `UsePreviousValue` 设置为 true）时，这意味着您要继续使用相同的 Parameter Store 键，而不是其值。CloudFormation 始终检索最新值。
+ 如果您指定了任何允许的值或其他约束，则 CloudFormation 会根据您指定的参数键对其进行验证，但不会验证其值。您应该在 Parameter Store 本身中验证这些值。
+ 创建或更新堆栈并创建更改集时，CloudFormation 会使用当时 Parameter Store 中存在的任何值。如果某个指定的参数在调用方的 Amazon Web Services 账户下的 Parameter Store 中不存在，CloudFormation 会返回验证错误。
+ 执行更改集时，CloudFormation 将使用在更改集中指定的值。您应在执行更改集前检查这些值，因为在您创建更改集和运行更改集之间的时间内，它们可能会在 Parameter Store 中发生更改。
+ 对于存储在同一 Amazon Web Services 账户中的 Parameter Store 参数，必须提供参数名称。对于由其他 Amazon Web Services 账户共享的 Parameter Store 参数，必须提供完整的参数 ARN。

## 支持的特定于 Amazon 的参数类型
<a name="aws-specific-parameter-types-supported"></a>

CloudFormation 支持以下 Amazon 特定的类型：

`AWS::EC2::AvailabilityZone::Name`  
可用区，如 `us-west-2a`。

`AWS::EC2::Image::Id`  
Amazon EC2 映像 ID，如 `ami-0ff8a91507f77f867`。请注意，CloudFormation 控制台不会显示此参数类型的值的下拉列表。

`AWS::EC2::Instance::Id`  
Amazon EC2 实例 ID，如 `i-1e731a32`。

`AWS::EC2::KeyPair::KeyName`  
Amazon EC2 密钥对名称。

`AWS::EC2::SecurityGroup::GroupName`  
默认 VPC 安全组名称，例如 `my-sg-abc`。

`AWS::EC2::SecurityGroup::Id`  
安全组 ID，如 `sg-a123fd85`。

`AWS::EC2::Subnet::Id`  
子网 ID，如 `subnet-123a351e`。

`AWS::EC2::Volume::Id`  
Amazon EBS 卷 ID，如 `vol-3cdd3f56`。

`AWS::EC2::VPC::Id`  
VPC ID，如 `vpc-a123baa3`。

`AWS::Route53::HostedZone::Id`  
Amazon Route 53 托管区域 ID，如 `Z23YXV4OVPL04A`。

`List<AWS::EC2::AvailabilityZone::Name>`  
针对某个区域的一组可用区，如 `us-west-2a, us-west-2b`。

`List<AWS::EC2::Image::Id>`  
一组 Amazon EC2 映像 ID，如 `ami-0ff8a91507f77f867, ami-0a584ac55a7631c0c`。请注意，CloudFormation 控制台不会显示此参数类型的值的下拉列表。

`List<AWS::EC2::Instance::Id>`  
一组 Amazon EC2 实例 ID，如 `i-1e731a32, i-1e731a34`。

`List<AWS::EC2::SecurityGroup::GroupName>`  
一组默认 VPC 安全组名称，例如 `my-sg-abc, my-sg-def`。

`List<AWS::EC2::SecurityGroup::Id>`  
一组安全组 ID，如 `sg-a123fd85, sg-b456fd85`。

`List<AWS::EC2::Subnet::Id>`  
一组子网 ID，如 `subnet-123a351e, subnet-456b351e`。

`List<AWS::EC2::Volume::Id>`  
一组 Amazon EBS 卷 ID，如 `vol-3cdd3f56, vol-4cdd3f56`。

`List<AWS::EC2::VPC::Id>`  
一组 VPC ID，如 `vpc-a123baa3, vpc-b456baa3`。

`List<AWS::Route53::HostedZone::Id>`  
一组 Amazon Route 53 托管区域 ID，如 `Z23YXV4OVPL04A, Z23YXV4OVPL04B`。

## 支持的 Systems Manager 参数类型
<a name="systems-manager-parameter-types-supported"></a>

CloudFormation 支持以下 Systems Manager 参数类型：

`AWS::SSM::Parameter::Name`  
Systems Manager 参数键的名称。仅使用此参数类型来检查所需的参数是否存在。CloudFormation 不会检索与该参数关联的实际值。

`AWS::SSM::Parameter::Value<String>`  
其值是字符串的 Systems Manager 参数。这与 Parameter Store 中的 `String` 参数对应。

`AWS::SSM::Parameter::Value<List<String>>` 或 `AWS::SSM::Parameter::Value<CommaDelimitedList>`  
其值是字符串列表的 Systems Manager 参数。这与 Parameter Store 中的 `StringList` 参数对应。

`AWS::SSM::Parameter::Value<AWS-specific parameter type>`  
其值是 Amazon 特定参数类型的 Systems Manager 参数。  
例如，下面指定了 `AWS::EC2::KeyPair::KeyName` 类型：  
+ `AWS::SSM::Parameter::Value<AWS::EC2::KeyPair::KeyName>`

`AWS::SSM::Parameter::Value<List<AWS-specific parameter type>>`  
其值是 Amazon 特定参数类型列表的 Systems Manager 参数。  
例如，下面指定了 `AWS::EC2::KeyPair::KeyName` 类型的列表：  
+ `AWS::SSM::Parameter::Value<List<AWS::EC2::KeyPair::KeyName>>`

## 不支持的 Systems Manager 参数类型
<a name="systems-manager-parameter-types-unsupported"></a>

CloudFormation 不支持以下 Systems Manager 参数类型：
+ Systems Manager 参数类型的列表，例如：`List<AWS::SSM::Parameter::Value<String>>`

此外，CloudFormation 不支持将模板参数定义为 `SecureString` Systems Manager 参数类型。不过对于某些资源，您可以将安全字符串指定为参数*值*。有关更多信息，请参阅 [使用动态引用获取存储在其他服务中的值](dynamic-references.md)。

# CloudFormation 演练
<a name="walkthroughs"></a>

本文档提供了旨在让您动手实践堆栈部署的一系列演练。
+ [引用其他 CloudFormation 堆栈中的资源输出](walkthrough-crossstackref.md) – 本演练演示了如何在一个堆栈中引用另一个 CloudFormation 堆栈的输出。您可以在单独的堆栈中创建相关的 Amazon 资源，从而创建更加模块化和可重复使用的模板，而不是在单个堆栈中包含所有资源。
+ [在 Amazon EC2 上部署应用程序](deploying.applications.md) – 了解如何使用 CloudFormation 在 Amazon EC2 实例上自动安装、配置和启动应用程序。这样能让您轻松复制部署和更新现有安装，而无需直接连接到实例。
+ [更新 CloudFormation 堆栈](updating.stacks.walkthrough.md) – 演示使用 CloudFormation 更新正在运行的堆栈的简单过程。
+ [创建已扩展且负载均衡的应用程序](walkthrough-autoscaling.md) – 了解如何使用 CloudFormation 创建可扩展的负载均衡应用程序。本演练介绍如何创建自动扩缩组、负载均衡器和其他相关资源，以确保应用程序能够处理不断变化的流量负载并保持高可用性。
+ [与其他 Amazon Web Services 账户中的 VPC 建立对等连接](peer-with-vpc-in-another-account.md) – 本演练将引导您在不同 Amazon Web Services 账户中的两个 VPC 之间，完成创建虚拟私有云（VPC）对等连接的过程。VPC 对等连接有助您在 VPC 之间路由流量，并像这些资源位于同一网络中一样访问资源。
+ [通过 CodeDeploy 使用 CloudFormation 执行 ECS 蓝/绿部署](blue-green.md)：了解如何使用 CloudFormation 在 Amazon ECS 上执行 Amazon CodeDeploy 蓝绿部署。蓝绿部署是一种在最短停机时间内更新应用程序或服务的方法。

# 引用其他 CloudFormation 堆栈中的资源输出
<a name="walkthrough-crossstackref"></a>

本演练演示了如何在一个堆栈中引用另一个 CloudFormation 堆栈的输出，以创建更多模块化和可重复使用的模板。

您可以在单独的堆栈中创建相关的 Amazon 资源，而不是在单个堆栈中包含所有资源。然后，您可以引用其他堆栈中的所需资源输出。通过限制对输出的跨堆栈引用，您可以控制由其他堆栈引用的堆栈部分。

例如，您可以将一个带 VPC、安全组和子网的网络堆栈用于公有 Web 应用程序，并且有一个单独的公有 Web 应用程序堆栈。为确保 Web 应用程序能使用网络堆栈中的安全组和子网，可以创建一个使 Web 应用程序堆栈能够引用网络堆栈中的资源输出的跨堆栈引用。借助跨堆栈引用，Web 应用程序堆栈的所有者无需创建或维护联网规则或资产。

要创建跨堆栈引用，可使用 `Export` 输出字段标记要导出的资源输出的值。然后，使用 `Fn::ImportValue` 内置函数导入该值。有关更多信息，请参阅 [获取从已部署的 CloudFormation 堆栈导出的输出](using-cfn-stack-exports.md)。

**注意**  
CloudFormation 是一项免费服务。但是，对于堆栈中包含的 Amazon 资源，您需要按各自的现有费率付费。有关 Amazon 定价的更多信息，请参阅[每种产品的详细信息页](https://www.amazonaws.cn/)。

**Topics**
+ [

## 使用示例模板创建网络堆栈
](#walkthrough-crossstackref-create-vpc-stack)
+ [

## 使用示例模板创建 Web 应用程序堆栈
](#walkthrough-crossstackref-create-ec2-stack)
+ [

## 验证堆栈的运行是否符合设计
](#walkthrough-crossstackref-verify)
+ [

## 排查 AMI 映射问题
](#walkthrough-crossstackref-troubleshooting-ami)
+ [

## 清除资源
](#walkthrough-crossstackref-clean-up)

## 使用示例模板创建网络堆栈
<a name="walkthrough-crossstackref-create-vpc-stack"></a>

在开始此演练之前，请确认您具有使用以下所有服务的 IAM 权限：Amazon VPC、Amazon EC2 和 CloudFormation。

网络堆栈包含您将在 Web 应用程序堆栈中使用的 VPC、安全组和子网。除了这些资源之外，网络堆栈还将创建互联网网关和路由表来实现公共访问。

您必须先创建此堆栈，然后才能创建 Web 应用程序堆栈。如果先创建 Web 应用程序堆栈，则它没有安全组或子网。

该堆栈模板可通过以下 URL 获取：[https://s3.amazonaws.com/cloudformation-examples/user-guide/cross-stack/SampleNetworkCrossStack.template](https://s3.amazonaws.com/cloudformation-examples/user-guide/cross-stack/SampleNetworkCrossStack.template)。要查看堆栈将创建的资源，请选择该链接，这将打开模板。在 `Outputs` 部分中，您可看到示例模板导出的联网资源。如果您从其他堆栈导出联网资源，则已导出资源的名称将以堆栈的名称为前缀。当用户导入联网资源时，他们可指定从中导入资源的堆栈。

**创建网络堆栈**

1. 登录到 Amazon Web Services 管理控制台 并打开 Amazon CloudFormation 控制台 [https://console.aws.amazon.com/cloudformation](https://console.amazonaws.cn/cloudformation/)。

1. 在**堆栈**页面，选择右上角的**堆栈**，然后选择**使用新资源（标准）**。

1. 选择**模板已准备就绪**，然后在**指定模板**部分选择 **Amazon S3 URL**。

1. 在 **Amazon S3 URL** 中，粘贴以下 URL：**https://s3.amazonaws.com/cloudformation-examples/user-guide/cross-stack/SampleNetworkCrossStack.template**。

1. 选择**下一步**。

1. 对于 **Stack name (堆栈名称)**，键入 **SampleNetworkCrossStack**，然后选择 **Next (下一步)**。
**注意**  
记录此堆栈的名称。您在启动 Web 应用程序堆栈时需要此堆栈名称。

1. 选择**下一步**。在本演练中，您无需添加标记或指定高级设置。

1. 确保堆栈名称和模板 URL 正确，然后选择 **Create stack (创建堆栈)**。

   CloudFormation 可能需要几分钟的时间创建堆栈。请耐心等待，直到成功创建所有资源，然后再继续创建 Web 应用程序堆栈。

1. 要监控进度，可查看堆栈事件。有关更多信息，请参阅 [监控堆栈进度](monitor-stack-progress.md)。

## 使用示例模板创建 Web 应用程序堆栈
<a name="walkthrough-crossstackref-create-ec2-stack"></a>

Web 应用程序堆栈将创建一个使用网络堆栈中的安全组和子网的 EC2 实例。

您必须在网络堆栈所在的同一 Amazon Web Services 区域中创建该堆栈。

该堆栈模板可通过以下 URL 获取：[https://s3.amazonaws.com/cloudformation-examples/user-guide/cross-stack/SampleWebAppCrossStack.template](https://s3.amazonaws.com/cloudformation-examples/user-guide/cross-stack/SampleWebAppCrossStack.template)。要查看堆栈将创建的资源，请选择该链接，这样会打开模板。在 `Resources` 部分中，查看 EC2 实例的属性。您可查看如何使用 `Fn::ImportValue` 函数从其他堆栈导入联网资源。

**创建 Web 应用程序堆栈**

1. 在**堆栈**页面，选择右上角的**创建堆栈**，然后选择**使用新资源（标准）**。

1. 选择**模板已准备就绪**，然后在**指定模板**部分选择 **Amazon S3 URL**。

1. 在 **Amazon S3 URL** 中，粘贴以下 URL：**https://s3.amazonaws.com/cloudformation-examples/user-guide/cross-stack/SampleWebAppCrossStack.template**。

1. 选择**下一步**。

1. 对于 **Stack name**，键入 **SampleWebAppCrossStack**。在 **Parameters** 部分中，让 **NetworkStackName** 参数使用默认值，然后选择 **Next**。

   示例模板使用参数值指定要从中导入值的堆栈。

1. 选择**下一步**。在本演练中，您无需添加标记或指定高级设置。

1. 确保堆栈名称和模板 URL 正确，然后选择 **Create stack (创建堆栈)**。

   CloudFormation 可能需要几分钟的时间创建堆栈。

## 验证堆栈的运行是否符合设计
<a name="walkthrough-crossstackref-verify"></a>

创建该堆栈后，查看其资源并记下实例 ID。有关查看堆栈资源的更多信息，请参阅[从 CloudFormation 控制台查看堆栈信息](cfn-console-view-stack-data-resources.md)。

要验证实例的安全组和子网，请在 [Amazon EC2 控制台](https://console.amazonaws.cn/ec2/)中查看实例的属性。如果实例使用 `SampleNetworkCrossStack` 堆栈中的安全组和子网，则表示您已成功创建跨堆栈引用。

使用控制台可查看堆栈输出和示例网站 URL 以验证 Web 应用程序是否正在运行。有关更多信息，请参阅 [从 CloudFormation 控制台查看堆栈信息](cfn-console-view-stack-data-resources.md)。

## 排查 AMI 映射问题
<a name="walkthrough-crossstackref-troubleshooting-ami"></a>

如果您收到 `Template error: Unable to get mapping for AWSRegionArch2AMI::[region]::HVM64` 错误，则该模板不包含您在 Amazon Web Services 区域的 AMI 映射。我们建议不要更新映射，而是使用 Systems Manager 公共参数动态引用最新的 AMI：

1. 将 `SampleWebAppCrossStack` 模板下载到您的本地计算机，下载网址为：[https://s3.amazonaws.com/cloudformation-examples/user-guide/cross-stack/SampleWebAppCrossStack.template](https://s3.amazonaws.com/cloudformation-examples/user-guide/cross-stack/SampleWebAppCrossStack.template)。

1. 删除整个 `AWSRegionArch2AMI` 映射部分。

1. 添加以下 Systems Manager 参数：

   ```
   "LatestAmiId": {
     "Description": "The latest Amazon Linux 2 AMI from the Parameter Store",
       "Type": "AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>",
       "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
     }
   ```

1. 替换现有的 `ImageId` 引用：

   ```
   "ImageId": { "Fn::FindInMap": [ "AWSRegionArch2AMI", { "Ref": "AWS::Region" } , "HVM64" ] }, 
   ```

   借助:

   ```
   "ImageId": { "Ref": "LatestAmiId" },
   ```

   此参数会自动解析为堆栈部署区域的最新 Amazon Linux 2 AMI。

   对于其他 Linux 发行版，请使用相应的参数路径。有关公共参数的更多信息，请参阅《Amazon Systems Manager 用户指南》**中的[发现 Parameter Store 中的公有参数](https://docs.amazonaws.cn/systems-manager/latest/userguide/parameter-store-finding-public-parameters.html)。

1. 将修改后的模板上传到您账户中的 S3 存储桶：

   ```
   aws s3 cp SampleWebAppCrossStack.template s3://amzn-s3-demo-bucket/
   ```

1. 创建堆栈时，请指定您的 S3 模板 URL，不要使用示例 URL。

## 清除资源
<a name="walkthrough-crossstackref-clean-up"></a>

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

**删除堆栈**

1. 在 CloudFormation 控制台中，选择 `SampleWebAppCrossStack` 堆栈。

1. 选择 **Actions**)（操作），然后选择 **Delete Stack**（删除堆栈）。

1. 在确认消息中，选择 **Delete (删除)**。

1. 在删除堆栈后，对 `SampleNetworkCrossStack` 堆栈重复相同的步骤。
**注意**  
等到 CloudFormation 完全删除 `SampleWebAppCrossStack` 堆栈。如果 EC2 实例仍在 VPC 中运行，则 CloudFormation 不会删除 `SampleNetworkCrossStack` 堆栈中的 VPC。

# 在 Amazon EC2 上部署应用程序
<a name="deploying.applications"></a>

您可以使用 CloudFormation 在 Amazon EC2 实例上自动安装、配置和启动应用程序。这样能让您轻松复制部署和更新现有安装而无需直接连接到该实例，从而为您节省大量时间和工作量。

CloudFormation 包括一组基于 `cloud-init` 的帮助程序脚本（`cfn-init`、`cfn-signal`、`cfn-get-metadata` 和 `cfn-hup`）。您可从 CloudFormation 模板中调用这些帮助程序脚本来在使用相同模板的 Amazon EC2 实例上安装、配置和更新应用程序。有关更多信息，请参阅《Amazon CloudFormation 模板参考指南**》中的 [CloudFormation 帮助程序脚本参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/cfn-helper-scripts-reference.html)。

在[入门教程](gettingstarted.walkthrough.md)中，您使用 `UserData` 和基础 bash 脚本创建了一个简单的 Web 服务器。虽然顺利创建了“Hello World”这样的简单页面，但实际应用程序通常需要更复杂的配置，包括：
+ 按照正确的顺序安装多个软件包。
+ 使用特定内容创建复杂的配置文件。
+ 启动服务并将其配置为自动运行。
+ 错误处理和验证设置过程。

与 `UserData` 中的基础 bash 脚本相比，CloudFormation 的帮助程序脚本提供了一种更稳健、更易于维护的方式来配置 EC2 实例。`cfn-init` 帮助程序脚本可以从模板的元数据中读取配置数据，并将其系统地应用于您的实例。

在本教程中，您将学习如何使用 `cfn-init` 帮助程序脚本以及如何监控引导过程。

**注意**  
CloudFormation 使用免费，但您需要为自己创建的 Amazon EC2 资源付费。如果您不熟悉 Amazon，可以利用[免费套餐](https://www.amazonaws.cn/free/)来最大限度地降低或避免在学习过程产生费用。

**Topics**
+ [

## 先决条件
](#bootstrapping-tutorial-prerequisites)
+ [

## 了解引导的概念
](#bootstrapping-tutorial-understand-concepts)
+ [

## 从简单的引导示例开始
](#bootstrapping-tutorial-simple-example)
+ [

## 添加文件和命令
](#bootstrapping-tutorial-add-complexity)
+ [

## 增强网络安全
](#bootstrapping-tutorial-security-group)
+ [

## 完整的引导模板
](#bootstrapping-tutorial-complete-template)
+ [

## 使用控制台创建堆栈。
](#bootstrapping-tutorial-create-stack)
+ [

## 监控引导过程
](#bootstrapping-tutorial-validate-bootstrap)
+ [

## 测试引导的 Web 服务器
](#bootstrapping-tutorial-test-web-server)
+ [

## 引导问题排查
](#bootstrapping-tutorial-troubleshooting)
+ [

## 清理 资源
](#bootstrapping-tutorial-clean-up)
+ [

## 后续步骤
](#bootstrapping-tutorial-next-steps)

## 先决条件
<a name="bootstrapping-tutorial-prerequisites"></a>
+ 您必须已完成 [创建第一个堆栈](gettingstarted.walkthrough.md) 教程或具有 CloudFormation 基础知识的同等经验。
+ 您必须具有对 Amazon Web Services 账户的访问权限，且该账户需要拥有有权使用 Amazon EC2 和 CloudFormation 的 IAM 用户或角色，或者拥有管理用户访问权限。
+ 必须拥有可访问互联网的虚拟私有云（VPC）。本教程模板需要默认 VPC，新版本 Amazon Web Services 账户自动附带该默认 VPC。如果您没有默认 VPC，或者已将其删除，请参阅“[创建第一个堆栈](gettingstarted.walkthrough.md)”教程中的疑难解答部分，了解其他解决方案。

## 了解引导的概念
<a name="bootstrapping-tutorial-understand-concepts"></a>

在创建模板之前，我们先了解一下有助于引导顺利完成的关键概念。

### `cfn-init` 帮助程序脚本
<a name="bootstrapping-tutorial-cfn-init-overview"></a>

CloudFormation 提供 Python 帮助程序脚本，可用于在 Amazon EC2 实例中安装软件和启动服务。`cfn-init` 脚本可以从模板的元数据中读取配置数据，并将其应用于实例。

过程如下所述：

1. 在 EC2 资源的 `Metadata` 部分中定义配置。

1. 从 `UserData` 脚本中调用 `cfn-init`。

1. `cfn-init` 读取元数据并应用配置。

1. 根据规范配置实例。

### 元数据结构
<a name="bootstrapping-tutorial-metadata-structure"></a>

该配置是在 EC2 实例中的特定结构中进行定义。

```
Resources:
  EC2Instance:
    Type: AWS::EC2::Instance
    Metadata:                       # Metadata section for the resource
      AWS::CloudFormation::Init:    # Required key that cfn-init looks for
        config:                     # Configuration name (you can have multiple)
          packages:                 # Install packages
          files:                    # Create files
          commands:                 # Run commands
          services:                 # Start/stop services
```

`cfn-init` 脚本将以特定顺序处理这些部分：packages、groups、users、sources、files、commands，然后是 services。

## 从简单的引导示例开始
<a name="bootstrapping-tutorial-simple-example"></a>

我们先从最简单的引导示例开始，该示例仅安装和启动 Apache。

```
Resources:
  EC2Instance:
    Type: AWS::EC2::Instance
    Metadata:
      AWS::CloudFormation::Init:
        config:
          packages:                 # Install Apache web server
            yum:
              httpd: []
          services:                 # Start Apache and enable it to start on boot
            systemd:
              httpd:
                enabled: true
                ensureRunning: true
    Properties:
      ImageId: !Ref LatestAmiId
      InstanceType: !Ref InstanceType
      UserData: !Base64             # Script that runs when instance starts
        Fn::Sub: |
          #!/bin/bash
          yum install -y aws-cfn-bootstrap
          /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource EC2Instance --region ${AWS::Region}
```

这个简单的示例演示了核心概念：
+ `packages` 部分使用 yum 安装 `httpd` 软件包。这也适用于 Amazon Linux 和其他使用 yum 的 Linux 发行版。
+ `services` 部分用于确保 `httpd` 自动启动和运行。
+ `UserData` 会安装最新的引导工具并调用 `cfn-init`。

## 添加文件和命令
<a name="bootstrapping-tutorial-add-complexity"></a>

现在，我们来改进示例，在 EC2 实例的 `/var/log` 目录中添加自定义网页和日志文件。

### 创建文件
<a name="bootstrapping-tutorial-files-section"></a>

`files` 部分可让您在实例上创建包含特定内容的文件。直竖线 (`|`) 允许您将文字文本块（HTML 代码）作为文件内容 (`/var/www/html/index.html`) 传递。

```
files:
  /var/www/html/index.html:
    content: |
      <body>
        <h1>Congratulations, you have successfully launched the AWS CloudFormation sample.</h1>
      </body>
```

### 运行命令
<a name="bootstrapping-tutorial-commands-section"></a>

`commands` 部分可让您在引导过程中运行 shell 命令。此命令会在 EC2 实例的 `/var/log/welcome.txt` 位置创建日志文件。要查看该文件，您需要 Amazon EC2 密钥对以进行 SSH 访问，以及 IP 地址范围以便以 SSH 方式连接实例（此处未介绍）。

```
commands:
  createWelcomeLog:
    command: "echo 'cfn-init ran successfully!' > /var/log/welcome.txt"
```

## 增强网络安全
<a name="bootstrapping-tutorial-security-group"></a>

由于我们正在设置 Web 服务器，因此需要允许 Web 流量（HTTP）传输到 EC2 实例。为此，我们将创建一个安全组，以便来自您的 IP 地址的入站流量通过端口 80。EC2 实例还需要将流量发送到互联网，以便实现软件包更新安装等目的。默认情况下，安全组会允许所有出站流量。然后，我们使用 `SecurityGroupIds` 属性将此安全组与 EC2 实例关联。

```
WebServerSecurityGroup:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupDescription: Allow HTTP access from my IP address
    SecurityGroupIngress:
      - IpProtocol: tcp
        Description: HTTP
        FromPort: 80
        ToPort: 80
        CidrIp: !Ref MyIP
```

## 完整的引导模板
<a name="bootstrapping-tutorial-complete-template"></a>

现在，我们把所有部分合在一起。这就是之前介绍的所有概念整合而成的完整模板。

```
AWSTemplateFormatVersion: 2010-09-09
Description: Bootstrap an EC2 instance with Apache web server using cfn-init

Parameters:
  LatestAmiId:
    Description: The latest Amazon Linux 2 AMI from the Parameter Store
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'

  InstanceType:
    Description: EC2 instance type
    Type: String
    Default: t2.micro
    AllowedValues:
      - t3.micro
      - t2.micro
    ConstraintDescription: must be a valid EC2 instance type.

  MyIP:
    Description: Your IP address in CIDR format (e.g. 203.0.113.1/32)
    Type: String
    MinLength: 9
    MaxLength: 18
    Default: 0.0.0.0/0
    AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$'
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.

Resources:
  WebServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow HTTP access from my IP address
      SecurityGroupIngress:
        - IpProtocol: tcp
          Description: HTTP
          FromPort: 80
          ToPort: 80
          CidrIp: !Ref MyIP

  WebServer:
    Type: AWS::EC2::Instance
    Metadata:
      AWS::CloudFormation::Init:
        config:
          packages:
            yum:
              httpd: []
          files:
            /var/www/html/index.html:
              content: |
                <body>
                  <h1>Congratulations, you have successfully launched the AWS CloudFormation sample.</h1>
                </body>
          commands:
            createWelcomeLog:
              command: "echo 'cfn-init ran successfully!' > /var/log/welcome.txt"
          services:
            systemd:
              httpd:
                enabled: true
                ensureRunning: true
    Properties:
      ImageId: !Ref LatestAmiId
      InstanceType: !Ref InstanceType
      SecurityGroupIds:
        - !Ref WebServerSecurityGroup
      UserData: !Base64
        Fn::Sub: |
          #!/bin/bash
          yum install -y aws-cfn-bootstrap
          /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServer --region ${AWS::Region}
      Tags:
        - Key: Name
          Value: Bootstrap Tutorial Web Server

Outputs:
  WebsiteURL:
    Value: !Sub 'http://${WebServer.PublicDnsName}'
    Description: EC2 instance public DNS name
```

## 使用控制台创建堆栈。
<a name="bootstrapping-tutorial-create-stack"></a>

以下过程涉及从文件上传示例堆栈模板。在本地计算机上打开文本编辑器并添加模板。使用文件名 `samplelinux2stack.template` 保存该文件。

**启动堆栈模板**

1. 登录到 Amazon Web Services 管理控制台 并打开 Amazon CloudFormation 控制台 [https://console.aws.amazon.com/cloudformation](https://console.amazonaws.cn/cloudformation/)。

1. 依次选择**创建堆栈**和**使用新资源（标准）**。

1. 在**指定模板**下，选择**上传模板文件**，然后选择**选择文件**，上传 `samplelinux2stack.template` 文件。

1. 选择**下一步**。

1. 在**指定堆栈详细信息**页面上，将堆栈命名为 **BootstrapTutorialStack**。

1. 在**参数**下，执行以下操作。
   + **LatestAmiId**：保留默认值。
   + **InstanceType**：选择 **t2.micro** 或 **t3.micro** 作为 EC2 实例类型。
   + **MyIP**：输入带 `/32` 后缀的公有 IP 地址。

1. 选择两次**下一步**，然后选择**提交**即可创建堆栈。

## 监控引导过程
<a name="bootstrapping-tutorial-validate-bootstrap"></a>

引导过程比简单的 EC2 启动需要更长的时间，因为引导过程中需要安装和配置其他软件。

**监控引导进度**

1. 在 CloudFormation 控制台中，选择堆栈并打开**事件**选项卡。

1. 注意 `WebServer CREATE_IN_PROGRESS` 事件。引导过程在实例启动后开始。

1. 引导过程通常需要花费几分钟的时间。完成时，您可以看到 `WebServer CREATE_COMPLETE`。

如果想知道引导过程中发生了什么，可以查看实例日志。

**查看引导日志（可选）**

1. 打开 [EC2 控制台](https://console.amazonaws.cn/ec2/)，找到您的实例。

1. 选择实例，然后依次选择**操作**、**监控和故障排除**、**获取系统日志**，即可查看引导过程。

1. 如果日志没有即刻出现，请稍等片刻，然后刷新页面。

## 测试引导的 Web 服务器
<a name="bootstrapping-tutorial-test-web-server"></a>

当堆栈显示 `CREATE_COMPLETE` 时，请测试 Web 服务器。

**测试 Web 服务器**

1. 在 CloudFormation 控制台中，转到您堆栈的**输出**选项卡。

1. 单击 **WebsiteURL** 值，在新选项卡中打开 Web 服务器。

1. 您应看到自定义网页和消息 `Congratulations, you have successfully launched the AWS CloudFormation sample`。

**注意**  
如果页面没有立即加载，请稍等片刻，然后重试。即使堆栈已显示 `CREATE_COMPLETE`，引导过程可能仍在完成。

## 引导问题排查
<a name="bootstrapping-tutorial-troubleshooting"></a>

如果引导过程失败或您的 Web 服务器无法运行，以下是常见问题和解决方案。

### 常见问题
<a name="bootstrapping-tutorial-common-issues"></a>
+ **堆栈创建失败**：查看**事件**选项卡以获取相应的错误消息。
+ **无法访问 Web 服务器**：验证 `MyIP` 参数中您的 IP 地址是否正确。别忘了在末尾加上 `/32`。
+ **引导过程失败**：实例可能会启动但 `cfn-init` 失败。按照“监控”章节所述查看系统日志。

## 清理 资源
<a name="bootstrapping-tutorial-clean-up"></a>

为了避免持续产生费用，您可以删除堆栈及其资源来进行清除。

**想要删除堆栈和它的资源**

1. 打开 [ CloudFormation 控制台](https://console.amazonaws.cn/cloudformation/)。

1. 在**堆栈**页面上，选择您创建的堆栈名称旁的选项（**BootstrapTutorialStack**），然后选择**删除**。

1. 当系统提示进行确认时，选择 **Delete（删除）**。

1. 在**事件**选项卡上监控堆栈删除过程的进度。**BootstrapTutorialStack** 的状态更改为 `DELETE_IN_PROGRESS`。当 CloudFormation 完成删除堆栈后，它会将从列表中移堆栈除。

## 后续步骤
<a name="bootstrapping-tutorial-next-steps"></a>

恭喜您！现在您已经成功地学会如何使用 CloudFormation 引导 EC2 实例。您现在已经知道：
+ 如何使用 `cfn-init` 帮助程序脚本
+ 如何构建用于引导的元数据
+ 如何安装软件包、创建文件、运行命令和管理服务
+ 如何监控引导问题

继续学习：
+ 了解如何更新正在运行的堆栈并使用 `cfn-hup` 帮助程序脚本。有关更多信息，请参阅 [更新 CloudFormation 堆栈](updating.stacks.walkthrough.md)。
+ 了解如何引导 Windows 堆栈。有关更多信息，请参阅 [引导基于 Windows 的 CloudFormation 堆栈](cfn-windows-stacks-bootstrapping.md)。
+ 使用多个配置集探索更复杂的引导情境。有关更多信息，请参阅**《Amazon CloudFormation 模板参考指南》中的 [cfn-init](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/cfn-init.html) 和 [AWS::CloudFormation::Init](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-init.html)。
+ 了解如何使用 `cfn-signal` 报告引导完成状态。有关更多信息，请参阅《Amazon CloudFormation 模板参考指南》**中的 [cfn-signal](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/cfn-signal.html)。

# 更新 CloudFormation 堆栈
<a name="updating.stacks.walkthrough"></a>

**注意**  
本教程基于 [在 Amazon EC2 上部署应用程序](deploying.applications.md) 教程中的概念生成。如果您尚未完成该教程，我们建议您先完成该教程，以了解使用 CloudFormation 进行的 EC2 引导的过程。

本主题演示了正在运行的堆栈的简单更新进展。我们将带您逐步了解以下步骤：

1. **创建起始堆栈**：使用基础 Amazon Linux 2 AMI 创建堆栈，从而使用 CloudFormation 帮助程序脚本安装 Apache Web Server 和简单的 PHP 应用程序。

1. **更新应用程序**：使用 CloudFormation 更新应用程序中的一个文件并部署软件。

1. **添加密钥对**：向实例中添加 Amazon EC2 密钥对，然后更新安全组以允许 SSH 访问实例。

1. **更新实例类型**：更改底层 Amazon EC2 实例的实例类型。

1. **更新 AMI**：在您的堆栈中更改 Amazon EC2 实例的亚马逊机器映像（AMI）。

**注意**  
CloudFormation 使用免费，但您需要为自己创建的 Amazon EC2 资源付费。如果您不熟悉 Amazon，可以利用[免费套餐](https://www.amazonaws.cn/free/)来最大限度地降低或避免在学习过程产生费用。

**Topics**
+ [

## 第 1 步：创建起始堆栈
](#update-stack-initial-stack)
+ [

## 第 2 步：更新应用程序
](#update-stack-update-application)
+ [

## 第 3 步：添加使用密钥对的 SSH 访问权限
](#update-stack-add-key-pair)
+ [

## 第 4 步：更新实例类型
](#update-stack-update-instance-type)
+ [

## 第 5 步：更新 AMI
](#update-stack-update-ami)
+ [

## 可用性和影响注意事项
](#update.walkthrough.impact)
+ [

## 相关资源
](#update.walkthrough.related)

## 第 1 步：创建起始堆栈
<a name="update-stack-initial-stack"></a>

我们将从创建可在本主题剩下的所有内容中使用的堆栈开始。我们已提供了一个简单的模板来启动在 Apache Web Server 中托管并在 Amazon Linux 2 AMI 上运行的简单实例 PHP Web 应用程序。

Apache Web Server、PHP 和简单的 PHP 应用程序全部都由默认安装在 Amazon Linux 2 AMI 上的 CloudFormation 帮助程序脚本进行安装。以下模板代码段显示描述待安装软件包和文件的元数据，此情况下为 Amazon Linux 2 AMI 的 Yum 存储库中的 Apache Web Server 和 PHP 基础设施。代码段还显示 `Services` 部分，以确保 Apache Web Server 处于运行状态。

```
WebServerInstance:
  Type: AWS::EC2::Instance
  Metadata:
    AWS::CloudFormation::Init:
      config:
        packages:
          yum:
            httpd: []
            php: []
        files:
          /var/www/html/index.php:
            content: |
              <?php
              echo '<h1>Hello World!</h1>';
              ?>
            mode: '000644'
            owner: apache
            group: apache
        services:
          systemd:
            httpd:
              enabled: true
              ensureRunning: true
```

应用程序本身是“Hello World”示例，在模板中进行了完整定义。对于现实工作中的应用程序，文件可存储在 Amazon S3、GitHub 或另一个存储库中，并通过模板进行参考。CloudFormation 可下载软件包（如 RPM 或 RubyGem），并能引用单个的文件以及展开 `.zip` 和 `.tar` 文件，以在 Amazon EC2 实例上创建应用程序项目。

模板用于启用和配置 `cfn-hup` 进程守护程序以侦听 Amazon EC2 实例元数据中所定义配置的更改。您可以使用 `cfn-hup` 进程守护程序更新应用程序软件，如 Apache 或 PHP 的版本，也可通过 CloudFormation 更新 PHP 应用程序文件。来自该模板中同一 Amazon EC2 资源的以下代码片段展示了配置 `cfn-hup` 所需的必要部分，即每两分钟调用 `cfn-init` 一次以通知并应用元数据的更新。否则，`cfn-init` 只能在启动时运行一次。

```
files:
  /etc/cfn/cfn-hup.conf:
    content: !Sub |
      [main]
      stack=${AWS::StackId}
      region=${AWS::Region}
      # The interval used to check for changes to the resource metadata in minutes. Default is 15
      interval=2
    mode: '000400'
    owner: root
    group: root
  /etc/cfn/hooks.d/cfn-auto-reloader.conf:
    content: !Sub |
      [cfn-auto-reloader-hook]
      triggers=post.update
      path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init
      action=/opt/aws/bin/cfn-init -s ${AWS::StackId} -r WebServerInstance --region ${AWS::Region}
      runas=root
services:
  systemd:
    cfn-hup:
      enabled: true
      ensureRunning: true
      files:
        - /etc/cfn/cfn-hup.conf
        - /etc/cfn/hooks.d/cfn-auto-reloader.conf
```

为了完成堆栈，在 Amazon EC2 实例定义中的 `Properties` 部分，`UserData` 属性包含调用 `cfn-init` 以安装软件包和文件的 `cloud-init` 脚本。有关更多信息，请参阅《Amazon CloudFormation 模板参考指南**》中的 [CloudFormation 帮助程序脚本参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/cfn-helper-scripts-reference.html)。该模板还创建了一个 Amazon EC2 安全组。

```
AWSTemplateFormatVersion: 2010-09-09

Parameters:
  LatestAmiId:
    Description: The latest Amazon Linux 2 AMI from the Parameter Store
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'

  InstanceType:
    Description: WebServer EC2 instance type
    Type: String
    Default: t3.micro
    AllowedValues:
      - t3.nano
      - t3.micro
      - t3.small
      - t3.medium
      - t3a.nano
      - t3a.micro
      - t3a.small
      - t3a.medium
      - m5.large
      - m5.xlarge
      - m5.2xlarge
      - m5a.large
      - m5a.xlarge
      - m5a.2xlarge
      - c5.large
      - c5.xlarge
      - c5.2xlarge
      - r5.large
      - r5.xlarge
      - r5.2xlarge
      - r5a.large
      - r5a.xlarge
      - r5a.2xlarge
    ConstraintDescription: must be a valid EC2 instance type.
    
Resources:
  WebServerInstance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref LatestAmiId
      InstanceType: !Ref InstanceType
      SecurityGroupIds:
        - !Ref WebServerSecurityGroup
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash -xe
          # Get the latest CloudFormation package
          yum update -y aws-cfn-bootstrap
          # Run cfn-init
          /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region} || error_exit 'Failed to run cfn-init'        
          # Start up the cfn-hup daemon to listen for changes to the EC2 instance metadata
          /opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup'
          # Signal success or failure
          /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region}
    Metadata:
      AWS::CloudFormation::Init:
        config:
          packages:
            yum:
              httpd: []
              php: []
          files:
            /var/www/html/index.php:
              content: |
                <?php
                echo "<h1>Hello World!</h1>";
                ?>
              mode: '000644'
              owner: apache
              group: apache
            /etc/cfn/cfn-hup.conf:
              content: !Sub |
                [main]
                stack=${AWS::StackId}
                region=${AWS::Region}
                # The interval used to check for changes to the resource metadata in minutes. Default is 15
                interval=2
              mode: '000400'
              owner: root
              group: root
            /etc/cfn/hooks.d/cfn-auto-reloader.conf:
              content: !Sub |
                [cfn-auto-reloader-hook]
                triggers=post.update
                path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init
                action=/opt/aws/bin/cfn-init -s ${AWS::StackId} -r WebServerInstance --region ${AWS::Region}
                runas=root
          services:
            systemd:
              httpd:
                enabled: true
                ensureRunning: true
              cfn-hup:
                enabled: true
                ensureRunning: true
                files:
                  - /etc/cfn/cfn-hup.conf
                  - /etc/cfn/hooks.d/cfn-auto-reloader.conf
    CreationPolicy:
      ResourceSignal:
        Timeout: PT5M

  WebServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable HTTP access via port 80
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0

Outputs:
  WebsiteURL:
    Value: !Sub 'http://${WebServerInstance.PublicDnsName}'
    Description: URL of the web application
```

**要使用此模板启动堆栈**

1. 复制该模板并将其作为文本文件本地保存到您的系统中。注意保存位置，因为您需要在后续步骤中使用此文件。

1. 登录到 Amazon Web Services 管理控制台 并打开 Amazon CloudFormation 控制台 [https://console.aws.amazon.com/cloudformation](https://console.amazonaws.cn/cloudformation/)。

1. 依次选择**创建堆栈、使用新资源（标准）**。

1. 选择**选择现有模板**。

1. 在**指定模板**下，选择**上传模板文件**，浏览到您在第一步中创建的文件，然后选择**下一步**。

1. 在**指定堆栈详细信息**页面上，输入 **UpdateTutorial** 作为堆栈名称。

1. 在**参数**下，保持所有参数不变，然后选择两次**下一步**。

1. 在**审核并创建**屏幕上，选择**提交**。

当您的堆栈状态变成 `CREATE_COMPLETE` 后，**输出**选项卡会显示网站的 URL。如果您选择 `WebsiteURL` 的输出值，您将看到新 PHP 应用程序在工作。

## 第 2 步：更新应用程序
<a name="update-stack-update-application"></a>

现在您已部署好堆栈，接下来更新应用程序吧。我们将对应用程序所打印出的文本进行简单更改。要执行此操作，我们将添加回显命令至 index.php 文件，如此模板代码段所示：

```
files:
  /var/www/html/index.php:
    content: |
      <?php
      echo "<h1>Hello World!</h1>";
      echo "<p>This is an updated version of our application.</p>";
      ?>
    mode: '000644'
    owner: apache
    group: apache
```

使用文本编辑器手动编辑您保存在本地的模板文件。

现在，更新堆栈。

**要使用更新后的模板更新堆栈**

1. 在 CloudFormation 控制台中，选择您的 **UpdateTutorial** 堆栈。

1. 选择**更新、直接更新**。

1. 选择**替换现有模板**。

1. 在**指定模板**下，选择**上传模板文件**，上传修改的模板文件模板，然后选择**下一步**。

1. 在**指定堆栈详细信息**页面上，保持所有参数相同，然后选择两次**下一步**。

1. 在**审核**页面上，审核您的更改。在**更改**下，您应该会看到 CloudFormation 将更新 `WebServerInstance` 资源。

1. 选择**提交**。

当您的堆栈处于 `UPDATE_COMPLETE` 状态时，您可以再次选择 `WebsiteURL` 输出值以验证应用程序的更改已生效。`cfn-hup` 进程守护程序每 2 分钟运行一次，因此最多能花 2 分钟在堆栈更新后更改应用程序。

要查看已更新资源集，请转至 CloudFormation 控制台。在**事件**选项卡上，查看堆栈事件。在此特别示例中，Amazon EC2 实例 `WebServerInstance` 的元数据已更新，这导致 CloudFormation 也会重新评估其他资源（`WebServerSecurityGroup`）以确保没有其他更改。其他堆栈资源都未修改。CloudFormation 将只更新堆栈中受堆栈的任何更改影响的资源。此类更改可直接进行，如属性或元数据更改，也可由依赖项或 `Ref`、`GetAtt` 中的数据流或其他内部模板函数导致。有关更多信息，请参阅[内置函数参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference.html)。

这一简单更新对此过程进行了阐述。但是，您可以对您的 Amazon EC2 实例中所部署文件和软件包进行更复杂的更改。例如，您可能会确定需要将 MySQL 与 MySQL 的 PHP 支持一起添加到实例中。要执行此操作，只需要将附加软件包和文件与任何附加服务一起添加到配置中，然后更新堆栈以部署更改。

```
packages:
  yum:
    httpd: []
    php: []
    mysql: []
    php-mysql: []
    mysql-server: []
    mysql-libs: []

  ...

services:
  systemd:
    httpd:
      enabled: true
      ensureRunning: true
    cfn-hup:
      enabled: true
      ensureRunning: true
      files:
        - /etc/cfn/cfn-hup.conf
        - /etc/cfn/hooks.d/cfn-auto-reloader.conf
    mysqld:
      enabled: true
      ensureRunning: true
```

您可以更新 CloudFormation 元数据，将应用程序所使用的软件包更新到新版本。前述示例中，每个软件包的版本属性都为空，这表示 `cfn-init` 应安装最新版的软件包。

```
packages:
  yum:
    httpd: []
    php: []
```

您可以视需要指定软件包的版本字符串。如果您在后续更新堆栈调用中更改版本字符串，则会部署新版软件包。此处显示 RubyGems 软件包版本号的使用示例。支持版本化的任何软件包都可以有特定版本。

```
packages:
  rubygems:
    mysql: []
    rubygems-update:
      - "1.6.2"
    rake:
      - "0.8.7"
    rails:
      - "2.3.11"
```

## 第 3 步：添加使用密钥对的 SSH 访问权限
<a name="update-stack-add-key-pair"></a>

您还可以更新模板中的资源，以添加原先未在模板中指定的属性。为了阐明上述操作，我们将会添加 Amazon EC2 密钥对到现有 EC2 实例中，然后在 Amazon EC2 安全组中打开端口 22，从而使您可以使用 Secure Shell（SSH）访问实例。

**向现有 Amazon EC2 实例添加 SSH 访问权限**

1. 向模板额外添加两个参数，从而以现有 Amazon EC2 密钥对和 SSH 位置的名称进行传递。

   ```
   Parameters:
     KeyName:
       Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
       Type: AWS::EC2::KeyPair::KeyName
       ConstraintDescription: must be the name of an existing EC2 KeyPair.
   
     SSHLocation:
       Description: The IP address that can be used to SSH to the EC2 instances in CIDR format (e.g. 203.0.113.1/32)
       Type: String
       MinLength: 9
       MaxLength: 18
       Default: 0.0.0.0/0
       AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$'
       ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
   ```

1. 将 `KeyName` 属性添加到 Amazon EC2 实例。

   ```
   WebServerInstance:
     Type: AWS::EC2::Instance
     Properties:
       ImageId: !Ref LatestAmiId
       InstanceType: !Ref InstanceType
       KeyName: !Ref KeyName
       SecurityGroupIds:
         - !Ref WebServerSecurityGroup
   ```

1. 将端口 22 和 SSH 位置添加到 Amazon EC2 安全组的入口规则。

   ```
   WebServerSecurityGroup:
     Type: AWS::EC2::SecurityGroup
     Properties:
       GroupDescription: Enable HTTP access via port 80 and SSH access via port 22
       SecurityGroupIngress:
         - IpProtocol: tcp
           FromPort: 80
           ToPort: 80
           CidrIp: 0.0.0.0/0
         - IpProtocol: tcp
           FromPort: 22
           ToPort: 22
           CidrIp: !Ref SSHLocation
   ```

1. 使用与 [第 2 步：更新应用程序](#update-stack-update-application) 中所述的相同步骤更新堆栈。

## 第 4 步：更新实例类型
<a name="update-stack-update-instance-type"></a>

现在，让我们演示一下如何通过更改实例类型来更新底层基础设施。

我们到目前为止所建立的堆栈使用 t3.micro Amazon EC2 实例。假设您新建的网站获取的流量比 t3.micro 实例能处理的流量多，且您现在想移动到 m5.large Amazon EC2 实例类型中。如果实例类型的架构发生变化，则必须使用不同的 AMI 创建实例。但是，t3.micro 和 m5.large 都使用相同的 CPU 架构并运行 Amazon Linux 2（x86\$164）AMI。有关更多信息，请参阅《Amazon EC2 用户指南》**中的[更改实例类型的兼容性](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/resize-limitations.html)。

让我们使用在上一步中进行修改的模板更改实例类型。由于 `InstanceType` 是模板的输入参数，我们不需要修改模板；我们能在**指定堆栈详细信息**页面上更改参数值。

**要使用新的参数值更新堆栈**

1. 在 CloudFormation 控制台中，选择您的 **UpdateTutorial** 堆栈。

1. 选择**更新、直接更新**。

1. 选择**使用当前模板**，然后选择**下一步**。

1. 在**指定堆栈详细信息**页面上，将文本框中 **InstanceType** 的值从 `t3.micro` 更改为 `m5.large`。然后，选择两次**下一步**。

1. 在**审核**页面上，审核您的更改。在**更改**下，您应该会看到 CloudFormation 将更新 `WebServerInstance` 资源。

1. 选择**提交**。

对于 EBS 支持的 Amazon EC2 实例，可以通过启动和停止实例来动态更改实例类型。CloudFormation 会尝试通过更新实例类型并重启实例来优化更改，因此实例 ID 不会更改。但是，实例重启时，实例的公用 IP 地址会更改。为了确保在更改后正确绑定弹性 IP 地址，CloudFormation 还会更新弹性 IP 地址。您可以在**事件**选项卡上的 CloudFormation 控制台中看到更改。

要通过 Amazon Web Services 管理控制台 检查实例类型，请打开 Amazon EC2 控制台并在其中查找您的实例。

## 第 5 步：更新 AMI
<a name="update-stack-update-ami"></a>

现在，让我们更新堆栈以使用下一代 Amazon Linux，即 Amazon Linux 2023。

更新 AMI 是一项重大更改，需要更换实例。我们不能只通过启动和停止实例来修改 AMI；CloudFormation 会将此视为对资源不可变属性的更改。要更改不可变属性进，CloudFormation 必须启动替代资源，在此例中是运行新 AMI 的新 Amazon EC2 实例。

让我们来看看如何更新堆栈模板以使用 Amazon Linux 2023。关键更改包括更新 AMI 参数和从 `yum` 更改为 `dnf` 程序包管理器。

```
AWSTemplateFormatVersion: 2010-09-09

Parameters:
  LatestAmiId:
    Description: The latest Amazon Linux 2023 AMI from the Parameter Store
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64'

  InstanceType:
    Description: WebServer EC2 instance type
    Type: String
    Default: t3.micro
    AllowedValues:
      - t3.nano
      - t3.micro
      - t3.small
      - t3.medium
      - t3a.nano
      - t3a.micro
      - t3a.small
      - t3a.medium
      - m5.large
      - m5.xlarge
      - m5.2xlarge
      - m5a.large
      - m5a.xlarge
      - m5a.2xlarge
      - c5.large
      - c5.xlarge
      - c5.2xlarge
      - r5.large
      - r5.xlarge
      - r5.2xlarge
      - r5a.large
      - r5a.xlarge
      - r5a.2xlarge
    ConstraintDescription: must be a valid EC2 instance type.

  KeyName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription: must be the name of an existing EC2 KeyPair.

  SSHLocation:
    Description: The IP address that can be used to SSH to the EC2 instances in CIDR format (e.g. 203.0.113.1/32)
    Type: String
    MinLength: 9
    MaxLength: 18
    Default: 0.0.0.0/0
    AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$'
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
    
Resources:
  WebServerInstance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref LatestAmiId
      InstanceType: !Ref InstanceType
      KeyName: !Ref KeyName
      SecurityGroupIds:
        - !Ref WebServerSecurityGroup
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash -xe
          # Get the latest CloudFormation package
          dnf update -y aws-cfn-bootstrap
          # Run cfn-init
          /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region} || error_exit 'Failed to run cfn-init'        
          # Start up the cfn-hup daemon to listen for changes to the EC2 instance metadata
          /opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup'
          # Signal success or failure
          /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region}
    Metadata:
      AWS::CloudFormation::Init:
        config:
          packages:
            dnf:
              httpd: []
              php: []
          files:
            /var/www/html/index.php:
              content: |
                <?php
                echo "<h1>Hello World!</h1>";
                echo "<p>This is an updated version of our application.</p>";
                echo "<p>Running on Amazon Linux 2023!</p>";
                ?>
              mode: '000644'
              owner: apache
              group: apache
            /etc/cfn/cfn-hup.conf:
              content: !Sub |
                [main]
                stack=${AWS::StackId}
                region=${AWS::Region}
                # The interval used to check for changes to the resource metadata in minutes. Default is 15
                interval=2
              mode: '000400'
              owner: root
              group: root
            /etc/cfn/hooks.d/cfn-auto-reloader.conf:
              content: !Sub |
                [cfn-auto-reloader-hook]
                triggers=post.update
                path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init
                action=/opt/aws/bin/cfn-init -s ${AWS::StackId} -r WebServerInstance --region ${AWS::Region}
                runas=root
          services:
            systemd:
              httpd:
                enabled: true
                ensureRunning: true
              cfn-hup:
                enabled: true
                ensureRunning: true
                files:
                  - /etc/cfn/cfn-hup.conf
                  - /etc/cfn/hooks.d/cfn-auto-reloader.conf
    CreationPolicy:
      ResourceSignal:
        Timeout: PT5M

  WebServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable HTTP access via port 80 and SSH access via port 22
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref SSHLocation

Outputs:
  WebsiteURL:
    Value: !Sub 'http://${WebServerInstance.PublicDnsName}'
    Description: URL of the web application
```

使用与 [第 2 步：更新应用程序](#update-stack-update-application) 中所述的相同步骤更新堆栈。

在新实例运行之后，CloudFormation 将更新堆栈中的其他资源以指向新资源。创建所有新资源并删除旧资源的过程称为 `UPDATE_CLEANUP`。此时，您将注意到堆栈中实例的实例 ID 和应用程序 URL 已随着更新而更改。**事件**表中的事件包含描述“Requested update has a change to an immutable property and hence creating a new physical resource”，以指示资源已被替代。

或者：如果您已将应用程序代码写入您想更新的 AMI 中，您可以使用同一堆栈更新机制更新 AMI 以加载您的新应用程序。

**要使用自定义应用程序代码更新 AMI**

1. 创建含有应用程序或操作系统更改的新 AMI。有关更多信息，请参阅《Amazon EC2 用户指南》**中的[创建 Amazon EBS-backed AMI](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/creating-an-ami-ebs.html)。

1. 更新您的模板以合并新 AMI ID。

1. 使用与 [第 2 步：更新应用程序](#update-stack-update-application) 中所述的相同步骤更新堆栈。

在您更新堆栈时，CloudFormation 检测到 AMI ID 已更改，然后用我们启动前一个更新所使用的方法触发堆栈更新。

## 可用性和影响注意事项
<a name="update.walkthrough.impact"></a>

不同的属性会对堆栈中的资源造成不同的影响。您可以使用 CloudFormation 更新任何属性，但是您应该在进行任何更改之前考虑以下问题：

1. 更新会如何影响资源本身？ 例如，更新警报阈值会使警报在更新期间处于非活动状态。正如我们所见，更改实例类型时需要停止并重启实例。CloudFormation 使用底层资源的更新或修改操作来对资源进行更改。要了解更改的影响，您应该查看特定资源的文档。

1. 更改可变还是不可变？ 对资源属性的某些更改，如更改 Amazon EC2 实例上的 AMI，不受基础服务的支持。如果更改可变，CloudFormation 将使用适用于基础资源的“Update”或“Modify”类型 API。对于不可变的属性更改，CloudFormation 将用更新后的属性创建新资源，然后再删除旧资源之前将此资源链接至堆栈。虽然 CloudFormation 尝试减少堆栈资源的停机时间，但替代资源是一个多步骤过程，需要时间。重新配置堆栈期间，您的应用程序不能全面运行。例如，它可能不能为请求提供服务或访问数据库。

## 相关资源
<a name="update.walkthrough.related"></a>

有关使用 CloudFormation 启动应用程序的更多信息以及集成其他配置与 Puppet 和 Opscode Chef 等部署服务的更多信息，请参阅以下白皮书：
+ [通过 CloudFormation 启动应用程序](https://s3.amazonaws.com/cloudformation-examples/BoostrappingApplicationsWithAWSCloudFormation.pdf)
+ [将 CloudFormation 与 Opscode Chef 集成](https://s3.amazonaws.com/cloudformation-examples/IntegratingAWSCloudFormationWithOpscodeChef.pdf)
+ [将 CloudFormation 与 Puppet 集成](https://s3.amazonaws.com/cloudformation-examples/IntegratingAWSCloudFormationWithPuppet.pdf)

# 创建已扩展且负载均衡的应用程序
<a name="walkthrough-autoscaling"></a>

在本演练中，您将创建一个堆栈，该堆栈可帮助您设置已扩展且负载平衡的应用程序。此演练为您提供将用于创建堆栈的示例模板。此示例模板预置了自动扩缩组、应用程序负载均衡器、控制负载均衡器和自动扩缩组流量的安全组，以及用于发布有关扩展活动的通知的 Amazon SNS 通知配置。

本模板将创建一个或多个 Amazon EC2 实例和一个应用程序负载均衡器。如果您通过本模板创建堆栈，则需为使用的 Amazon 资源支付相应费用。

## 完整堆栈模板
<a name="example-templates-autoscaling-full-stack-template"></a>

我们从使用模板开始。

**YAML**

```
AWSTemplateFormatVersion: 2010-09-09
Parameters:
  InstanceType:
    Description: The EC2 instance type
    Type: String
    Default: t3.micro
    AllowedValues:
      - t3.micro
      - t3.small
      - t3.medium
  KeyName:
    Description: Name of an existing EC2 key pair to allow SSH access to the instances
    Type: AWS::EC2::KeyPair::KeyName
  LatestAmiId:
    Description: The latest Amazon Linux 2 AMI from the Parameter Store
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
  OperatorEmail:
    Description: The email address to notify when there are any scaling activities
    Type: String
  SSHLocation:
    Description: The IP address range that can be used to SSH to the EC2 instances
    Type: String
    MinLength: 9
    MaxLength: 18
    Default: 0.0.0.0/0
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
  Subnets:
    Type: 'List<AWS::EC2::Subnet::Id>'
    Description: At least two public subnets in different Availability Zones in the selected VPC
  VPC:
    Type: AWS::EC2::VPC::Id
    Description: A virtual private cloud (VPC) that enables resources in public subnets to connect to the internet
Resources:
  ELBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: ELB Security Group
      VpcId: !Ref VPC
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 80
        ToPort: 80
        CidrIp: 0.0.0.0/0
  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: EC2 Security Group
      VpcId: !Ref VPC
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 80
        ToPort: 80
        SourceSecurityGroupId:
          Fn::GetAtt:
          - ELBSecurityGroup
          - GroupId
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: !Ref SSHLocation
  EC2TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 30
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 15
      HealthyThresholdCount: 5
      Matcher:
        HttpCode: '200'
      Name: EC2TargetGroup
      Port: 80
      Protocol: HTTP
      TargetGroupAttributes:
      - Key: deregistration_delay.timeout_seconds
        Value: '20'
      UnhealthyThresholdCount: 3
      VpcId: !Ref VPC
  ALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref EC2TargetGroup
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: 80
      Protocol: HTTP
  ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      Subnets: !Ref Subnets
      SecurityGroups:
        - !GetAtt ELBSecurityGroup.GroupId
  LaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties: 
      LaunchTemplateName: !Sub ${AWS::StackName}-launch-template
      LaunchTemplateData:
        ImageId: !Ref LatestAmiId
        InstanceType: !Ref InstanceType
        KeyName: !Ref KeyName
        SecurityGroupIds: 
          - !Ref EC2SecurityGroup
        UserData:
          Fn::Base64: !Sub |
            #!/bin/bash
            yum update -y
            yum install -y httpd
            systemctl start httpd
            systemctl enable httpd
            echo "<h1>Hello World!</h1>" > /var/www/html/index.html
  NotificationTopic:
    Type: AWS::SNS::Topic
    Properties:
      Subscription:
        - Endpoint: !Ref OperatorEmail
          Protocol: email
  WebServerGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      LaunchTemplate:
        LaunchTemplateId: !Ref LaunchTemplate
        Version: !GetAtt LaunchTemplate.LatestVersionNumber
      MaxSize: '3'
      MinSize: '1'
      NotificationConfigurations:
        - TopicARN: !Ref NotificationTopic
          NotificationTypes: ['autoscaling:EC2_INSTANCE_LAUNCH', 'autoscaling:EC2_INSTANCE_LAUNCH_ERROR', 'autoscaling:EC2_INSTANCE_TERMINATE', 'autoscaling:EC2_INSTANCE_TERMINATE_ERROR']
      TargetGroupARNs:
        - !Ref EC2TargetGroup
      VPCZoneIdentifier: !Ref Subnets
```

**JSON**

```
{
  "AWSTemplateFormatVersion":"2010-09-09",
  "Parameters":{
    "InstanceType":{
      "Description":"The EC2 instance type",
      "Type":"String",
      "Default":"t3.micro",
      "AllowedValues":[
        "t3.micro",
        "t3.small",
        "t3.medium"
      ]
    },
    "KeyName":{
      "Description":"Name of an existing EC2 key pair to allow SSH access to the instances",
      "Type":"AWS::EC2::KeyPair::KeyName"
    },
    "LatestAmiId":{
      "Description":"The latest Amazon Linux 2 AMI from the Parameter Store",
      "Type":"AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>",
      "Default":"/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
    },
    "OperatorEmail":{
      "Description":"The email address to notify when there are any scaling activities",
      "Type":"String"
    },
    "SSHLocation":{
      "Description":"The IP address range that can be used to SSH to the EC2 instances",
      "Type":"String",
      "MinLength":9,
      "MaxLength":18,
      "Default":"0.0.0.0/0",
      "ConstraintDescription":"Must be a valid IP CIDR range of the form x.x.x.x/x."
    },
    "Subnets":{
      "Type":"List<AWS::EC2::Subnet::Id>",
      "Description":"At least two public subnets in different Availability Zones in the selected VPC"
    },
    "VPC":{
      "Type":"AWS::EC2::VPC::Id",
      "Description":"A virtual private cloud (VPC) that enables resources in public subnets to connect to the internet"
    }
  },
  "Resources":{
    "ELBSecurityGroup":{
      "Type":"AWS::EC2::SecurityGroup",
      "Properties":{
        "GroupDescription":"ELB Security Group",
        "VpcId":{
          "Ref":"VPC"
        },
        "SecurityGroupIngress":[
          {
            "IpProtocol":"tcp",
            "FromPort":80,
            "ToPort":80,
            "CidrIp":"0.0.0.0/0"
          }
        ]
      }
    },
    "EC2SecurityGroup":{
      "Type":"AWS::EC2::SecurityGroup",
      "Properties":{
        "GroupDescription":"EC2 Security Group",
        "VpcId":{
          "Ref":"VPC"
        },
        "SecurityGroupIngress":[
          {
            "IpProtocol":"tcp",
            "FromPort":80,
            "ToPort":80,
            "SourceSecurityGroupId":{
              "Fn::GetAtt":[
                "ELBSecurityGroup",
                "GroupId"
              ]
            }
          },
          {
            "IpProtocol":"tcp",
            "FromPort":22,
            "ToPort":22,
            "CidrIp":{
              "Ref":"SSHLocation"
            }
          }
        ]
      }
    },
    "EC2TargetGroup":{
      "Type":"AWS::ElasticLoadBalancingV2::TargetGroup",
      "Properties":{
        "HealthCheckIntervalSeconds":30,
        "HealthCheckProtocol":"HTTP",
        "HealthCheckTimeoutSeconds":15,
        "HealthyThresholdCount":5,
        "Matcher":{
          "HttpCode":"200"
        },
        "Name":"EC2TargetGroup",
        "Port":80,
        "Protocol":"HTTP",
        "TargetGroupAttributes":[
          {
            "Key":"deregistration_delay.timeout_seconds",
            "Value":"20"
          }
        ],
        "UnhealthyThresholdCount":3,
        "VpcId":{
          "Ref":"VPC"
        }
      }
    },
    "ALBListener":{
      "Type":"AWS::ElasticLoadBalancingV2::Listener",
      "Properties":{
        "DefaultActions":[
          {
            "Type":"forward",
            "TargetGroupArn":{
              "Ref":"EC2TargetGroup"
            }
          }
        ],
        "LoadBalancerArn":{
          "Ref":"ApplicationLoadBalancer"
        },
        "Port":80,
        "Protocol":"HTTP"
      }
    },
    "ApplicationLoadBalancer":{
      "Type":"AWS::ElasticLoadBalancingV2::LoadBalancer",
      "Properties":{
        "Scheme":"internet-facing",
        "Subnets":{
          "Ref":"Subnets"
        },
        "SecurityGroups":[
          {
            "Fn::GetAtt":[
              "ELBSecurityGroup",
              "GroupId"
            ]
          }
        ]
      }
    },
    "LaunchTemplate":{
      "Type":"AWS::EC2::LaunchTemplate",
      "Properties":{
        "LaunchTemplateName":{
          "Fn::Sub":"${AWS::StackName}-launch-template"
        },
        "LaunchTemplateData":{
          "ImageId":{
            "Ref":"LatestAmiId"
          },
          "InstanceType":{
            "Ref":"InstanceType"
          },
          "KeyName":{
            "Ref":"KeyName"
          },
          "SecurityGroupIds":[
            {
              "Ref":"EC2SecurityGroup"
            }
          ],
          "UserData":{
            "Fn::Base64":{
              "Fn::Join":[
                "",
                [
                  "#!/bin/bash\n",
                  "yum update -y\n",
                  "yum install -y httpd\n",
                  "systemctl start httpd\n",
                  "systemctl enable httpd\n",
                  "echo \"<h1>Hello World!</h1>\" > /var/www/html/index.html"
                ]
              ]
            }
          }
        }
      }
    },
    "NotificationTopic":{
      "Type":"AWS::SNS::Topic",
      "Properties":{
        "Subscription":[
          {
            "Endpoint":{
              "Ref":"OperatorEmail"
            },
            "Protocol":"email"
          }
        ]
      }
    },
    "WebServerGroup":{
      "Type":"AWS::AutoScaling::AutoScalingGroup",
      "Properties":{
        "LaunchTemplate":{
          "LaunchTemplateId":{
            "Ref":"LaunchTemplate"
          },
          "Version":{
            "Fn::GetAtt":[
              "LaunchTemplate",
              "LatestVersionNumber"
            ]
          }
        },
        "MaxSize":"3",
        "MinSize":"1",
        "NotificationConfigurations":[
          {
            "TopicARN":{
              "Ref":"NotificationTopic"
            },
            "NotificationTypes":[
              "autoscaling:EC2_INSTANCE_LAUNCH",
              "autoscaling:EC2_INSTANCE_LAUNCH_ERROR",
              "autoscaling:EC2_INSTANCE_TERMINATE",
              "autoscaling:EC2_INSTANCE_TERMINATE_ERROR"
            ]
          }
        ],
        "TargetGroupARNs":[
          {
            "Ref":"EC2TargetGroup"
          }
        ],
        "VPCZoneIdentifier":{
          "Ref":"Subnets"
        }
      }
    }
  }
}
```

## 模板演练
<a name="example-templates-autoscaling-description"></a>

此模板的第一部分指定了 `Parameters`。必须向每个参数分配一个运行时的值，使 Amazon CloudFormation 能够成功预置堆栈。稍后在模板中指定的资源会引用这些值并使用这些数据。
+ `InstanceType`：Amazon EC2 Auto Scaling 预置的 EC2 实例类型。如果未指定，则默认使用 `t3.micro`。
+ `KeyName`：用于允许 SSH 访问实例的现有 EC2 密钥对。
+ `LatestAmiId`：实例的亚马逊机器映像（AMI）。如果未指定，则您的实例将使用由 Amazon 维护的 Amazon Systems Manager 公有参数，通过 Amazon Linux 2 AMI 启动。有关更多信息，请参阅 *Amazon Systems Manager User Guide* 中的 [Finding public parameters](https://docs.amazonaws.cn/systems-manager/latest/userguide/parameter-store-finding-public-parameters.html)。
+ `OperatorEmail`：您要发送扩展活动通知的电子邮件地址。
+ `SSHLocation`：可用于通过 SSH 连接到实例的 IP 地址范围。
+ `Subnets`：位于不同可用区的至少两个公有子网。
+ `VPC`：您账户中的虚拟私有云（VPC），其允许公有子网中的资源连接到互联网。
**注意**  
您可以使用默认 VPC 和默认子网来允许实例访问互联网。如果使用您自己的 VPC，请确保它拥有映射到您工作时所在区域的每个可用区的子网。您至少必须具有两个公有子网，且这些子网可用于创建负载均衡器。

此模板的下一个部分指定了 `Resources`。本部分指定堆栈资源及其属性。

[https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html) 资源 `ELBSecurityGroup` 
+ `SecurityGroupIngress` 包含一个 TCP 入口规则，该规则允许来自端口 80 上的*所有 IP 地址*（"CidrIp" : "0.0.0.0/0"）的访问。

[https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html) 资源 `EC2SecurityGroup` 
+ `SecurityGroupIngress` 包含两个入口规则：1) 允许来自您为 `SSHLocation` 输入参数提供的 IP 地址范围内的 SSH 访问（端口 22）的 TCP 入口规则；2) 允许通过指定负载均衡器的安全组实现的来自负载均衡器的访问的 TCP 入口规则。[GetAtt](resources-section-structure.md#resource-properties-getatt) 函数用于获取具有逻辑名称 `ELBSecurityGroup` 的安全组 ID。

[AWS::ElasticLoadBalancingV2::TargetGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-targetgroup.html) 资源 `EC2TargetGroup`
+ `Port`、`Protocol` 和 `HealthCheckProtocol` 指定 `ApplicationLoadBalancer` 要向其中路由流量以及 Elastic Load Balancing 用于检查 EC2 实例运行状况的 EC2 实例端口（80）和协议（HTTP）。
+ `HealthCheckIntervalSeconds` 指定 EC2 实例的每次运行状况检查之间有 30 秒的时间间隔。`HealthCheckTimeoutSeconds` 定义为 Elastic Load Balancing 等待来自运行状况检查目标响应的时间（本示例中为 15 秒）。超时时间超过之后，Elastic Load Balancing 将标记 EC2 实例运行状况检查为“运行状况不佳”。当 EC2 实例连续三次未通过运行状况检查 (`UnhealthyThresholdCount`) 时，Elastic Load Balancing 会停止将流量路由到该 EC2 实例，直到该实例连续五次运行状况检查均正常 (`HealthyThresholdCount`)。此时，Elastic Load Balancing 认为实例运行状况良好，并再次开始将流量路由到该实例。
+ `TargetGroupAttributes` 将目标组的取消注册延迟值更新为 20 秒。默认情况下，Elastic Load Balancing 会等待 300 秒，才会完成注销过程。

[AWS::ElasticLoadBalancingV2::Listener](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-listener.html) 资源 `ALBListener`
+ `DefaultActions` 指定负载均衡器侦听的端口、负载均衡器转发请求的目标组以及用于路由请求的协议。

[AWS::ElasticLoadBalancingV2::LoadBalancer](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-loadbalancer.html) 资源 `ApplicationLoadBalancer`
+ `Subnets` 将 `Subnets` 输入参数的值作为要在其中创建负载均衡器节点的公有子网列表。
+ `SecurityGroup` 获取安全组的 ID，该安全组充当虚拟防火墙，以便负载均衡器节点控制传入流量。[GetAtt](resources-section-structure.md#resource-properties-getatt) 函数用于获取具有逻辑名称 `ELBSecurityGroup` 的安全组 ID。

[AWS::EC2::LaunchTemplate](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html) 资源 `LaunchTemplate`
+ `ImageId` 将 `LatestAmiId` 输入参数的值作为要使用的 AMI。
+ `KeyName` 将 `KeyName` 输入参数的值作为要使用的 EC2 密钥对。
+ `SecurityGroupIds` 获取逻辑名称为 `EC2SecurityGroup` 的安全组的 ID，该安全组充当虚拟防火墙，以便 EC2 实例控制传入流量。
+ `UserData` 是在实例启动并运行之后运行的配置脚本。在此示例中，脚本安装 Apache 并创建 index.html 文件。

[AWS::SNS::Topic](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sns-topic.html) 资源 `NotificationTopic`
+ 当有任何扩展活动时，`Subscription` 将 `OperatorEmail` 输入参数的值作为通知收件人的电子邮件地址。

[AWS::AutoScaling::AutoScalingGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html) 资源 `WebServerGroup`
+ `MinSize` 和 `MaxSize` 设置自动扩缩组中的 EC2 实例的最小和最大数量。
+ `TargetGroupARNs` 使用逻辑名称为 `EC2TargetGroup` 的目标组的 ARN。随着此自动扩缩组的扩展，它会自动向该目标组注册和注销实例。
+ `VPCZoneIdentifier` 将 `Subnets` 输入参数的值作为要在其中创建 EC2 实例的公有子网列表。

## 步骤 1：启动堆栈
<a name="example-templates-autoscaling-launch-stack"></a>

在启动堆栈之前，请检查您是否拥有可以使用以下所有服务的 Amazon Identity and Access Management（IAM）权限：Amazon EC2、Amazon EC2 Auto Scaling、Amazon Systems Manager、Elastic Load Balancing、Amazon SNS 和 Amazon CloudFormation。

以下过程涉及从文件上传示例堆栈模板。在本地计算机上打开文本编辑器并添加其中一个模板。使用文件名 `sampleloadbalancedappstack.template` 保存该文件。

**启动堆栈模板**

1. 登录到 Amazon Web Services 管理控制台 并打开 Amazon CloudFormation 控制台 [https://console.aws.amazon.com/cloudformation](https://console.amazonaws.cn/cloudformation/)。

1. 依次选择**创建堆栈**和**使用新资源（标准）**。

1. 在**指定模板**下，选择**上传模板文件**，然后选择**选择文件**，上传 `sampleloadbalancedappstack.template` 文件。

1. 选择**下一步**。

1. 在**指定堆栈详细信息**页面上，键入堆栈的名称（例如 **SampleLoadBalancedAppStack**）。

1. 在**参数**下，查看堆栈的参数并为没有默认值的所有参数提供值，包括 **OperatorEmail**、**SSHLocation**、**KeyName**、**VPC** 和 **Subnets**。

1. 选择**下一步**两次。

1. 在**审核**页面上，审核并确认设置。

1. 选择**提交**。

   您可以在 Amazon CloudFormation 控制台的**状态**列中查看堆栈的状态。Amazon CloudFormation 成功创建堆栈后，您将收到 **CREATE\$1COMPLETE** 状态。
**注意**  
创建堆栈后，必须先确认订阅，电子邮件地址才能开始接收通知。有关更多信息，请参阅《Amazon EC2 Auto Scaling 用户指南》中的[自动扩缩组扩展时获取 Amazon SNS 通知](https://docs.amazonaws.cn/autoscaling/ec2/userguide/ec2-auto-scaling-sns-notifications.html)。

## 步骤 2：清除示例资源
<a name="example-templates-autoscaling-clean-up"></a>

为确保您无需为未使用的示例资源付费，请删除堆栈。

**删除堆栈**

1. 在 Amazon CloudFormation 控制台中，选择 **SampleLoadBalancedAppStack** 堆栈。

1. 选择**删除**。

1. 在确认消息中，选择**删除堆栈**。

   **SampleLoadBalancedAppStack** 的状态更改为 **DELETE\$1IN\$1PROGRESS**。当 Amazon CloudFormation 完成删除堆栈后，它会将从列表中移堆栈除。

使用本演练中的示例模板构建您自己的堆栈模板。有关更多信息，请参阅 *Amazon EC2 Auto Scaling User Guide* 中的 [Tutorial: Set up a scaled and load-balanced application](https://docs.amazonaws.cn/autoscaling/ec2/userguide/tutorial-ec2-auto-scaling-load-balancer.html)。

# 与其他 Amazon Web Services 账户中的 VPC 建立对等连接
<a name="peer-with-vpc-in-another-account"></a>

您可以使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-vpcpeeringconnection.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-vpcpeeringconnection.html) 与其他 Amazon Web Services 账户中的虚拟私有云（VPC）建立对等连接。这会在两个 VPC 之间创建网络连接，使您能够在它们之间路由流量，它们可以像在同一网络中那样进行通信。VPC 对等连接有助于简化数据访问和数据传输。

要建立 VPC 对等连接，您需要为单个 CloudFormation 堆栈中的两个单独 Amazon Web Services 账户 授权。

有关 VPC 对等连接及其限制的更多信息，请参阅 [Amazon VPC 对等连接指南](https://docs.amazonaws.cn/vpc/latest/peering/)。

## 先决条件
<a name="peer-with-vpc-in-another-account-prerequisites"></a>

1. 您需要为对等连接提供对等 VPC ID、对等 Amazon Web Services 账户 ID 以及[跨账户访问角色](https://docs.amazonaws.cn/IAM/latest/UserGuide/id_roles_common-scenarios_aws-accounts.html)。
**注意**  
本演练涉及两个账户：第一个是允许跨账户对等的账户 (*接受方账户*)。第二个是请求对等连接的账户 (*请求者账户*)。

1. 要接受 VPC 对等连接，您必须能够担任跨账户访问角色。该资源的行为方式与同一账户中的 VPC 对等连接资源相同。要了解 IAM 管理员如何授予代入跨账户角色的权限，请参阅 *IAM 用户指南*中的[向用户授予切换角色的权限](https://docs.amazonaws.cn/IAM/latest/UserGuide/id_roles_use_permissions-to-switch.html)。

## 步骤 1：创建 VPC 和跨账户角色
<a name="step-1-create-vpc-and-cross-account-role"></a>

在该步骤中，您需要在*接受方账户* 中创建 VPC 和角色。

**创建 VPC 和跨账户访问角色**

1. 登录到 Amazon Web Services 管理控制台 并打开 Amazon CloudFormation 控制台 [https://console.aws.amazon.com/cloudformation](https://console.amazonaws.cn/cloudformation/)。

1. 在**堆栈**页面，选择右上角的**创建堆栈**，然后选择**使用新资源（标准）**。

1. 在**先决条件 – 准备模板**中，选择**选择现有模板**，然后依次选择**上传模板文件** > **选择文件**。

1. 在本地计算机上打开文本编辑器并添加以下模板之一。保存文件并返回控制台，将其选择为模板文件。  
**Example JSON**  

   ```
   {
     "AWSTemplateFormatVersion": "2010-09-09",
     "Description": "Create a VPC and an assumable role for cross account VPC peering.",
     "Parameters": {
       "PeerRequesterAccountId": {
         "Type": "String"
       }
     },
     "Resources": {
       "vpc": {
         "Type": "AWS::EC2::VPC",
         "Properties": {
           "CidrBlock": "10.1.0.0/16",
           "EnableDnsSupport": false,
           "EnableDnsHostnames": false,
           "InstanceTenancy": "default"
         }
       },
       "peerRole": {
         "Type": "AWS::IAM::Role",
         "Properties": {
           "AssumeRolePolicyDocument": {
             "Statement": [
               {
                 "Principal": {
                   "AWS": {
                     "Ref": "PeerRequesterAccountId"
                   }
                 },
                 "Action": [
                   "sts:AssumeRole"
                 ],
                 "Effect": "Allow"
               }
             ]
           },
           "Path": "/",
           "Policies": [
             {
               "PolicyName": "root",
               "PolicyDocument": {
                 "Version": "2012-10-17",		 	 	 
                 "Statement": [
                   {
                     "Effect": "Allow",
                     "Action": "ec2:AcceptVpcPeeringConnection",
                     "Resource": "*"
                   }
                 ]
               }
             }
           ]
         }
       }
     },
     "Outputs": {
       "VPCId": {
         "Value": {
           "Ref": "vpc"
         }
       },
       "RoleARN": {
         "Value": {
           "Fn::GetAtt": [
             "peerRole",
             "Arn"
           ]
         }
       }
     }
   }
   ```  
**Example YAML**  

   ```
   AWSTemplateFormatVersion: 2010-09-09
   Description: Create a VPC and an assumable role for cross account VPC peering.
   Parameters:
     PeerRequesterAccountId:
       Type: String
   Resources:
     vpc:
       Type: AWS::EC2::VPC
       Properties:
         CidrBlock: 10.1.0.0/16
         EnableDnsSupport: false
         EnableDnsHostnames: false
         InstanceTenancy: default
     peerRole:
       Type: AWS::IAM::Role
       Properties:
         AssumeRolePolicyDocument:
           Statement:
             - Principal:
                 AWS: !Ref PeerRequesterAccountId
               Action:
                 - 'sts:AssumeRole'
               Effect: Allow
         Path: /
         Policies:
           - PolicyName: root
             PolicyDocument:
               Version: 2012-10-17 		 	 	 
               Statement:
                 - Effect: Allow
                   Action: 'ec2:AcceptVpcPeeringConnection'
                   Resource: '*'
   Outputs:
     VPCId:
       Value: !Ref vpc
     RoleARN:
       Value: !GetAtt 
         - peerRole
         - Arn
   ```

1. 选择**下一步**。

1. 为堆栈提供一个名称（例如 **VPC-owner**），然后在 **PeerRequesterAccountId** 字段中输入*请求者账户*的 Amazon Web Services 账户 ID。

1. 接受默认值，然后选择 **Next**。

1. 选择**我确认 Amazon CloudFormation 可能创建 IAM 资源**，然后选择**创建堆栈**。

## 步骤 2：创建包含 `AWS::EC2::VPCPeeringConnection` 的模板
<a name="step-2-create-template-for-vpc-peering-connection-owner"></a>

现在，您已创建 VPC 和跨账户角色，您可以与使用另一个 Amazon Web Services 账户（*请求者账户*）的 VPC 进行对等。

**创建包含 [AWS::EC2::VPCPeeringConnection](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-vpcpeeringconnection.html) 资源的模板**

1. 返回 Amazon CloudFormation 控制台主页。

1. 在**堆栈**页面，选择右上角的**创建堆栈**，然后选择**使用新资源（标准）**。

1. 在**先决条件 – 准备模板**中，选择**选择现有模板**，然后依次选择**上传模板文件** > **选择文件**。

1. 在本地计算机上打开文本编辑器并添加以下模板之一。保存文件并返回控制台，将其选择为模板文件。  
**Example JSON**  

   ```
   {
     "AWSTemplateFormatVersion": "2010-09-09",
     "Description": "Create a VPC and a VPC Peering connection using the PeerRole to accept.",
     "Parameters": {
       "PeerVPCAccountId": {
         "Type": "String"
       },
       "PeerVPCId": {
         "Type": "String"
       },
       "PeerRoleArn": {
         "Type": "String"
       }
     },
     "Resources": {
       "vpc": {
         "Type": "AWS::EC2::VPC",
         "Properties": {
           "CidrBlock": "10.2.0.0/16",
           "EnableDnsSupport": false,
           "EnableDnsHostnames": false,
           "InstanceTenancy": "default"
         }
       },
       "vpcPeeringConnection": {
         "Type": "AWS::EC2::VPCPeeringConnection",
         "Properties": {
           "VpcId": {
             "Ref": "vpc"
           },
           "PeerVpcId": {
             "Ref": "PeerVPCId"
           },
           "PeerOwnerId": {
             "Ref": "PeerVPCAccountId"
           },
           "PeerRoleArn": {
             "Ref": "PeerRoleArn"
           }
         }
       }
     },
     "Outputs": {
       "VPCId": {
         "Value": {
           "Ref": "vpc"
         }
       },
       "VPCPeeringConnectionId": {
         "Value": {
           "Ref": "vpcPeeringConnection"
         }
       }
     }
   }
   ```  
**Example YAML**  

   ```
   AWSTemplateFormatVersion: 2010-09-09
   Description: Create a VPC and a VPC Peering connection using the PeerRole to accept.
   Parameters:
     PeerVPCAccountId:
       Type: String
     PeerVPCId:
       Type: String
     PeerRoleArn:
       Type: String
   Resources:
     vpc:
       Type: AWS::EC2::VPC
       Properties:
         CidrBlock: 10.2.0.0/16
         EnableDnsSupport: false
         EnableDnsHostnames: false
         InstanceTenancy: default
     vpcPeeringConnection:
       Type: AWS::EC2::VPCPeeringConnection
       Properties:
         VpcId: !Ref vpc
         PeerVpcId: !Ref PeerVPCId
         PeerOwnerId: !Ref PeerVPCAccountId
         PeerRoleArn: !Ref PeerRoleArn
   Outputs:
     VPCId:
       Value: !Ref vpc
     VPCPeeringConnectionId:
       Value: !Ref vpcPeeringConnection
   ```

1. 选择**下一步**。

1. 为堆栈提供一个名称（例如，**VPC-peering-connection**）。

1. 接受默认值，然后选择 **Next**。

1. 选择**我确认 Amazon CloudFormation 可能创建 IAM 资源**，然后选择**创建堆栈**。

## 创建具有高度限制策略的模板
<a name="create-template-with-highly-restrictive-policy"></a>

在将您的 VPC 与另一个 Amazon Web Services 账户 对等时，您可能需要创建一个高度限制的策略。

以下示例模板显示如何更改 VPC 对等所有者模板 (上面步骤 1 中创建的*接受方账户*)，以加强对它的限制。

**Example JSON**  

```
{
  "AWSTemplateFormatVersion":"2010-09-09",
  "Description":"Create a VPC and an assumable role for cross account VPC peering.",
  "Parameters":{
    "PeerRequesterAccountId":{
      "Type":"String"
    }
  },
  "Resources":{
    "peerRole":{
      "Type":"AWS::IAM::Role",
      "Properties":{
        "AssumeRolePolicyDocument":{
          "Statement":[
            {
              "Action":[
                "sts:AssumeRole"
              ],
              "Effect":"Allow",
              "Principal":{
                "AWS":{
                  "Ref":"PeerRequesterAccountId"
                }
              }
            }
          ]
        },
        "Path":"/",
        "Policies":[
          {
            "PolicyDocument":{
              "Statement":[
                {
                  "Action":"ec2:acceptVpcPeeringConnection",
                  "Effect":"Allow",
                  "Resource":{
                    "Fn::Sub":"arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:vpc/${vpc}"
                  }
                },
                {
                  "Action":"ec2:acceptVpcPeeringConnection",
                  "Condition":{
                    "StringEquals":{
                      "ec2:AccepterVpc":{
                        "Fn::Sub":"arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:vpc/${vpc}"
                      }
                    }
                  },
                  "Effect":"Allow",
                  "Resource":{
                    "Fn::Sub":"arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:vpc-peering-connection/*"
                  }
                }
              ],
              "Version":"2012-10-17" 		 	 	 
            },
            "PolicyName":"root"
          }
        ]
      }
    },
    "vpc":{
      "Type":"AWS::EC2::VPC",
      "Properties":{
        "CidrBlock":"10.1.0.0/16",
        "EnableDnsHostnames":false,
        "EnableDnsSupport":false,
        "InstanceTenancy":"default"
      }
    }
  },
  "Outputs":{
    "RoleARN":{
      "Value":{
        "Fn::GetAtt":[
          "peerRole",
          "Arn"
        ]
      }
    },
    "VPCId":{
      "Value":{
        "Ref":"vpc"
      }
    }
  }
}
```

**Example YAML**  

```
AWSTemplateFormatVersion: 2010-09-09
Description: Create a VPC and an assumable role for cross account VPC peering.
Parameters:
  PeerRequesterAccountId:
    Type: String
Resources:
  peerRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action:
              - 'sts:AssumeRole'
            Effect: Allow
            Principal:
              AWS:
                Ref: PeerRequesterAccountId
      Path: /
      Policies:
        - PolicyDocument:
            Statement:
              - Action: 'ec2:acceptVpcPeeringConnection'
                Effect: Allow
                Resource:
                  'Fn::Sub': 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:vpc/${vpc}'
              - Action: 'ec2:acceptVpcPeeringConnection'
                Condition:
                  StringEquals:
                    'ec2:AccepterVpc':
                      'Fn::Sub': 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:vpc/${vpc}'
                Effect: Allow
                Resource:
                  'Fn::Sub': >-
                    arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:vpc-peering-connection/*
            Version: 2012-10-17 		 	 	 
          PolicyName: root
  vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.1.0.0/16
      EnableDnsHostnames: false
      EnableDnsSupport: false
      InstanceTenancy: default
Outputs:
  RoleARN:
    Value:
      'Fn::GetAtt':
        - peerRole
        - Arn
  VPCId:
    Value:
      Ref: vpc
```

要访问 VPC，您可以使用上面步骤 2 中使用的请求者模板。

有关更多信息，请参阅*《Amazon VPC 对等连接指南》*中的[VPC 对等连接的身份和访问权限管理](https://docs.amazonaws.cn/vpc/latest/peering/security-iam.html)。

# 通过 CodeDeploy 使用 CloudFormation 执行 ECS 蓝/绿部署
<a name="blue-green"></a>

要更新在 Amazon Elastic Container Service（Amazon ECS）上运行的应用程序，您可以使用 CodeDeploy 蓝绿部署策略。此策略有助于尽可能减少因更改应用程序版本造成的中断。

在蓝绿部署中，您可以在当前的实时环境（称为*蓝色*）之外创建一个新的应用程序环境（称为*绿色*）。这使您可以先监控和测试绿色环境，然后再将实时流量从蓝色环境路由到绿色环境。在绿色环境开始为实时流量提供服务后，您可以安全地终止蓝色环境。

要使用 CloudFormation 在 ECS 上执行 CodeDeploy 蓝绿部署，请在堆栈模板中包括以下信息：
+ 描述 `AWS::CodeDeploy::BlueGreen` 钩子的 `Hooks` 部分。
+  指定 `AWS::CodeDeployBlueGreen` 变换的 `Transform` 部分。

以下主题提供了有关为 ECS 上的蓝绿部署设置 CloudFormation 模板的指导。

**Topics**
+ [

# 关于蓝绿部署
](about-blue-green-deployments.md)
+ [

# 使用 CloudFormation 管理 ECS 蓝/绿部署时的注意事项
](blue-green-considerations.md)
+ [

# `AWS::CodeDeploy::BlueGreen` 钩子语法
](blue-green-hook-syntax.md)
+ [

# 蓝绿部署模板示例
](blue-green-template-example.md)

# 关于蓝绿部署
<a name="about-blue-green-deployments"></a>

本主题概述了如何使用 CloudFormation 执行蓝绿部署。此外还介绍了如何准备用于蓝绿部署的 CloudFormation 模板。

**Topics**
+ [

## 工作原理
](#blue-green-how-it-works)
+ [会启动绿色部署的资源更新](#blue-green-resources)
+ [准备 模板](#blue-green-setup)
+ [为蓝绿部署建模](#blue-green-required)
+ [更改集](#blue-green-changesets)
+ [监控堆栈事件](#blue-green-events)
+ [IAM 权限](#blue-green-iam)

## 工作原理
<a name="blue-green-how-it-works"></a>

使用 CloudFormation 通过 CodeDeploy 执行 ECS 蓝绿部署时，首先创建一个堆栈模板，用于定义蓝色和绿色应用程序环境的资源，包括指定要使用的流量路由和稳定设置。然后基于该模板创建一个堆栈。这会生成蓝色（当前）应用程序。CloudFormation 仅在堆栈创建过程中创建蓝色资源。绿色部署的资源仅在需要时才会创建。

然后，如果在将来的堆栈更新中更新蓝色应用程序中的任务定义或任务集资源，CloudFormation 会执行以下操作：
+ 生成所有必需的绿色应用程序环境资源
+ 根据指定的流量路由参数转移流量
+ 删除蓝色资源

如果在绿色部署成功和完成之前的任何时刻发生错误，CloudFormation 会将堆栈回滚到启动整个绿色部署之前的状态。

## 会启动绿色部署的资源更新
<a name="blue-green-resources"></a>

执行将会更新特定 ECS 资源的特定属性的堆栈更新时，CloudFormation 将会启动绿色部署过程。将会启动此过程的资源有：
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskdefinition.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskdefinition.html)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskset.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskset.html) 

但是，如果对这些资源的更新不涉及需要替换的属性更改，则不会启动绿色部署。有关更多信息，请参阅 [理解堆栈资源的更新行为](using-cfn-updating-stacks-update-behaviors.md)。

请注意，不能在同一堆栈更新操作中同时包括对上述资源的更新以及对其他资源的更新。如果需要更新列出的资源以及同一堆栈中的其他资源，则有两种选择：
+ 执行两个单独的堆栈更新操作：一个仅包括对上述资源的更新，另一个单独的堆栈更新包括对任何其他资源的更改。
+ 从模板中删除 `Transform` 和 `Hooks` 部分，然后执行堆栈更新。在这种情况下，CloudFormation 不会执行绿色部署。

## 准备模板以执行 ECS 蓝/绿部署
<a name="blue-green-setup"></a>

要在堆栈上启用蓝/绿部署，请在执行堆栈更新之前在堆栈模板中包含以下部分。
+ 将 `AWS::CodeDeployBlueGreen` 转换的引用添加到模板中：

  ```
  "Transform": [
    "AWS::CodeDeployBlueGreen"
  ],
  ```
+ 添加调用 `AWS::CodeDeploy::BlueGreen` 挂钩并指定部署属性的 `Hooks` 部分。有关更多信息，请参阅 [`AWS::CodeDeploy::BlueGreen` 钩子语法](blue-green-hook-syntax.md)。
+ 在 `Resources` 部分中，定义部署的蓝色和绿色资源。

您可以在第一次创建模板时（即创建堆栈本身之前）添加这些部分，也可以在执行堆栈更新之前将它们添加到现有模板中。如果是为新堆栈指定蓝/绿部署，则 CloudFormation 只在堆栈创建期间创建蓝色资源 - 仅当在堆栈更新期间需要绿色部署的资源时才会创建它们。

## 使用 CloudFormation 资源对蓝/绿部署建模
<a name="blue-green-required"></a>

要在 ECS 上执行 CodeDeploy 蓝绿部署，CloudFormation 模板需要包含为部署建模的资源，例如 Amazon ECS 服务和负载均衡器。如需更详细地了解这些资源代表了什么，请参阅《Amazon CodeDeploy 用户指南》中的[开始 Amazon ECS 部署之前](https://docs.amazonaws.cn/codedeploy/latest/userguide/deployment-steps-ecs.html#deployment-steps-prerequisites-ecs)。


| 要求 | 资源 | 必需/可选 | 如果替换则会启动蓝绿部署？ | 
| --- | --- | --- | --- | 
| Amazon ECS 集群 | [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-cluster.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-cluster.html) | 可选。可以使用默认集群。 | 否 | 
| Amazon ECS 服务 | [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-service.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-service.html) | 必需。 | 否 | 
| 应用程序或网络负载均衡器 | [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-ecs-service-loadbalancer.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-ecs-service-loadbalancer.html) | 必需。 | 否 | 
| 生产侦听器 | [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-listener.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-listener.html) | 必需。 | 否 | 
| 测试侦听器  | [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-listener.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-listener.html) | 可选。 | 否 | 
| 两个目标组 | [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-targetgroup.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-targetgroup.html) | 必需。 | 否 | 
| Amazon ECS 任务定义  | [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskdefinition.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskdefinition.html) | 必需。 | 是 | 
| 您的 Amazon ECS 应用程序的容器 | [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-ecs-taskdefinition-containerdefinition.html#cfn-ecs-taskdefinition-containerdefinition-name](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-ecs-taskdefinition-containerdefinition.html#cfn-ecs-taskdefinition-containerdefinition-name) | 必需。 | 否 | 
| 您的替换任务集的端口 | [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-ecs-taskdefinition-portmapping.html#cfn-ecs-taskdefinition-portmapping-containerport](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-ecs-taskdefinition-portmapping.html#cfn-ecs-taskdefinition-portmapping-containerport) | 必需。 | 否 | 

## 更改集
<a name="blue-green-changesets"></a>

我们强烈建议您在执行会启动绿色部署的堆栈更新之前创建更改集。这样便于您在执行堆栈更新之前查看对堆栈作出的实际更改。请注意，资源更改可能不会按堆栈更新期间的执行顺序列出。有关更多信息，请参阅 [使用更改集更新 CloudFormation 堆栈](using-cfn-updating-stacks-changesets.md)。

## 监控堆栈事件
<a name="blue-green-events"></a>

您可以在 **Stack**（堆栈）页面的 **Events**（事件）选项卡上，使用 Amazon CLI 查看 ECS 部署的每个步骤生成的堆栈事件。有关更多信息，请参阅 [监控堆栈进度](monitor-stack-progress.md)。

## 蓝绿部署所需的 IAM 权限
<a name="blue-green-iam"></a>

为了使 CloudFormation 成功执行蓝绿部署，您必须具有以下 CodeDeploy 权限：
+ `codedeploy:Get*`
+ `codedeploy:CreateCloudFormationDeployment`

有关更多信息，请参阅《服务授权参考》中的 [Actions, resources, and condition keys for CodeDeploy](https://docs.amazonaws.cn/service-authorization/latest/reference/list_awscodedeploy.html)**。

# 使用 CloudFormation 管理 ECS 蓝/绿部署时的注意事项
<a name="blue-green-considerations"></a>

使用 CloudFormation 来通过 CodeDeploy 执行 ECS 蓝绿部署的过程，不同于仅使用 CodeDeploy 的标准 Amazon ECS 部署过程。要详细了解这些区别，请参阅《Amazon CodeDeploy 用户指南》中的[通过 CodeDeploy 和 Amazon CloudFormation 进行的 Amazon ECS 蓝绿部署的区别](https://docs.amazonaws.cn/codedeploy/latest/userguide/deployments-create-ecs-cfn.html#differences-ecs-bg-cfn)**。

使用 CloudFormation 管理蓝绿部署时，需要记住某些限制和注意事项：
+ 只有对特定资源的更新才会启动绿色部署。有关更多信息，请参阅 [会启动绿色部署的资源更新](about-blue-green-deployments.md#blue-green-resources)。
+ 不能在同一堆栈更新中包括启动绿色部署的资源更新和对其他资源的更新。有关更多信息，请参阅 [会启动绿色部署的资源更新](about-blue-green-deployments.md#blue-green-resources)。
+ 您只能将单个 ECS 服务指定为部署目标。
+ 如果参数的值由 CloudFormation 模糊处理，则 CodeDeploy 无法在绿色部署期间更新该参数，并且会导致错误和堆栈更新失败。这些方法包括：
  + 使用 `NoEcho` 属性定义的参数。
  + 使用动态引用从外部服务检索其值的参数。有关动态引用的更多信息，请参阅[使用动态引用获取存储在其他服务中的值](dynamic-references.md)。
+ 要取消仍在进行的绿色部署，请取消 CloudFormation 中的堆栈更新，而不是 CodeDeploy 或 ECS。有关更多信息，请参阅 [取消堆栈更新](using-cfn-stack-update-cancel.md)。更新完成之后，将无法取消它。但是，您可以利用任何先前的设置再次更新堆栈。
+ 定义 ECS 蓝绿部署的模板目前不支持以下 CloudFormation 功能：
  + 声明 [outputs](outputs-section-structure.md) 或使用 [Fn::ImportValue](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-importvalue.html) 导入其他堆栈中的值。
  + 导入资源。有关资源导入的更多信息，请参阅[将 Amazon 资源导入 CloudFormation 堆栈](import-resources.md)。
  + 您不能在包含嵌套堆栈资源的模板中使用 `AWS::CodeDeploy::BlueGreen` 钩子。有关嵌套堆栈的更多信息，请参阅[使用嵌套堆栈将模板拆分为可重复使用的部分](using-cfn-nested-stacks.md)。
  + 在嵌套堆栈中使用 `AWS::CodeDeploy::BlueGreen` 钩子。

# `AWS::CodeDeploy::BlueGreen` 钩子语法
<a name="blue-green-hook-syntax"></a>

以下语法描述了 ECS 蓝绿部署的 `AWS::CodeDeploy::BlueGreen` 钩子结构。

## 语法
<a name="cfn-blue-green-hook-syntax"></a>

```
"Hooks": {
  "Logical ID": {
    "Type": "AWS::CodeDeploy::BlueGreen",
    "Properties": {
      "TrafficRoutingConfig": {
        "Type": "Traffic routing type",
        "TimeBasedCanary": {
          "StepPercentage": Integer,
          "BakeTimeMins": Integer
        },
        "TimeBasedLinear": {
          "StepPercentage": Integer,
          "BakeTimeMins": Integer
        }
      },
      "AdditionalOptions": {"TerminationWaitTimeInMinutes": Integer},
      "LifecycleEventHooks": {
        "BeforeInstall": "FunctionName",
        "AfterInstall": "FunctionName",
        "AfterAllowTestTraffic": "FunctionName",
        "BeforeAllowTraffic": "FunctionName",
        "AfterAllowTraffic": "FunctionName"
      },
      "ServiceRole": "CodeDeployServiceRoleName",
      "Applications": [
        {
          "Target": {
            "Type": "AWS::ECS::Service",
            "LogicalID": "Logical ID of AWS::ECS::Service"
          },
          "ECSAttributes": {
            "TaskDefinitions": [
              "Logical ID of AWS::ECS::TaskDefinition (Blue)",
              "Logical ID of AWS::ECS::TaskDefinition (Green)"
            ],
            "TaskSets": [
              "Logical ID of AWS::ECS::TaskSet (Blue)",
              "Logical ID of AWS::ECS::TaskSet (Green)"
            ],
            "TrafficRouting": {
              "ProdTrafficRoute": {
                "Type": "AWS::ElasticLoadBalancingV2::Listener",
                "LogicalID": "Logical ID of AWS::ElasticLoadBalancingV2::Listener (Production)"
              },
              "TestTrafficRoute": {
                "Type": "AWS::ElasticLoadBalancingV2::Listener",
                "LogicalID": "Logical ID of AWS::ElasticLoadBalancingV2::Listener (Test)"
              },
              "TargetGroups": [
                "Logical ID of AWS::ElasticLoadBalancingV2::TargetGroup (Blue)",
                "Logical ID of AWS::ElasticLoadBalancingV2::TargetGroup (Green)"
              ]
            }
          }
        }
      ]
    }
  }
}
```

## 属性
<a name="cfn-blue-green-hook-properties"></a>

逻辑 ID（也称为*逻辑名称*）  
在模板的 `Hooks` 部分中声明的钩子。逻辑 ID 必须为字母数字 (A-Za-z0-9)，并且在模板中具有唯一性。  
*是否必需*：是    
`Type`  
挂钩的类型。`AWS::CodeDeploy::BlueGreen`  
*是否必需*：是  
`Properties`  
挂钩的属性。  
*是否必需*：是    
`TrafficRoutingConfig`  
流量路由配置设置。  
*必需*：否  
默认配置为基于时间的 canary 流量转移，具有 15% 的步骤百分比和五分钟的稳定时间。    
`Type`  
部署配置使用的流量转移类型。  
有效值：AllAtOnce \$1 TimeBasedCanary \$1 TimeBasedLinear  
*是否必需*：是    
`TimeBasedCanary`  
指定一个配置，以两个增量将流量从部署的一个版本转移到另一个版本。  
*必需*：如果指定 `TimeBasedCanary` 作为流量路由类型，则必须包含 `TimeBasedCanary` 参数。    
`StepPercentage`  
在 `TimeBasedCanary` 部署的第一个增量中要转移的流量百分比。步骤百分比必须为 14% 或更大。  
*必需*：否  
`BakeTimeMins`  
`TimeBasedCanary` 部署的第一次和第二次流量转移之间的分钟数。  
*必需*：否  
`TimeBasedLinear`  
指定一个配置，以相等的增量将流量从部署的一个版本转移到另一个版本，每个增量之间的分钟数相等。  
*必需*：如果指定 `TimeBasedLinear` 作为流量路由类型，则必须包含 `TimeBasedLinear` 参数。    
`StepPercentage`  
在 `TimeBasedLinear` 部署的每个增量开始时转移的流量百分比。步骤百分比必须为 14% 或更大。  
*必需*：否  
`BakeTimeMins`  
`TimeBasedLinear` 部署的每次增量流量转移之间的分钟数。  
*必需*：否  
`AdditionalOptions`  
蓝/绿部署的其他选项。  
*必需*：否    
`TerminationWaitTimeInMinutes`  
指定终止蓝色资源之前等待的时间（以分钟为单位）。  
*必需*：否  
`LifecycleEventHooks`  
使用生命周期事件挂钩指定 CodeDeploy 可以调用的用于验证部署的 Lambda 函数。对于部署生命周期事件，您可以使用相同函数或不同函数。验证测试完成后，Lambda `AfterAllowTraffic` 函数会回调 CodeDeploy 并提供 `Succeeded` 或 `Failed` 结果。有关更多信息，请参阅《Amazon CodeDeploy 用户指南》中的 [AppSpec 的“hooks”部分](https://docs.amazonaws.cn/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html)。  
*必需*：否    
`BeforeInstall`  
用于在创建替换任务集之前运行任务的函数。  
*必需*：否  
`AfterInstall`  
用于在创建替换任务集并且其中一个目标组与之关联后运行任务的函数。  
*必需*：否  
`AfterAllowTestTraffic`  
用于在测试侦听器为替换任务集提供流量后运行任务的函数。  
*必需*：否  
`BeforeAllowTraffic`  
用于在第二个目标组与替换任务集关联之后但在流量转移到替换任务集之前运行任务的函数。  
*必需*：否  
`AfterAllowTraffic`  
用于在第二个目标组为替换任务集提供流量后运行任务的函数。  
*必需*：否  
`ServiceRole`  
CloudFormation 用于执行蓝绿部署的执行角色。有关必要权限的列表，请参阅 [蓝绿部署所需的 IAM 权限](about-blue-green-deployments.md#blue-green-iam)。  
*必需*：否  
`Applications`  
指定 Amazon ECS 应用程序的属性。  
*是否必需*：是    
`Target`  
  
*是否必需*：是    
`Type`  
资源的类型。  
*是否必需*：是  
`LogicalID`  
资源的逻辑 ID。  
*是否必需*：是  
`ECSAttributes`  
代表 Amazon ECS 应用程序部署的各种需求的资源。  
*是否必需*：是    
`TaskDefinitions`  
运行包含 Amazon ECS 应用程序的 Docker 容器所用的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskdefinition.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskdefinition.html) 资源的逻辑 ID。  
*是否必需*：是  
`TaskSets`  
用作应用程序任务集的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskset.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskset.html) 资源的逻辑 ID。  
*是否必需*：是  
`TrafficRouting`  
指定用于流量路由的资源。  
*是否必需*：是    
`ProdTrafficRoute`  
负载均衡器将流量定向到目标组所用的侦听器。  
*是否必需*：是    
`Type`  
资源的类型。`AWS::ElasticLoadBalancingV2::Listener`  
*是否必需*：是  
`LogicalID`  
资源的逻辑 ID。  
*是否必需*：是  
`TestTrafficRoute`  
负载均衡器将流量定向到目标组所用的侦听器。  
*是否必需*：是    
`Type`  
资源的类型。`AWS::ElasticLoadBalancingV2::Listener`  
*是否必需*：是  
`LogicalID`  
资源的逻辑 ID。  
*必需*：否  
`TargetGroups`  
用作目标组以将流量传送到注册目标的资源的逻辑 ID。  
*是否必需*：是

# 蓝绿部署模板示例
<a name="blue-green-template-example"></a>

以下示例模板设置了 ECS 上的 CodeDeploy 蓝绿部署，流量路由进度为每个步骤 15%，每个步骤之间的稳定期为 5 分钟。

使用模板创建堆栈将会预置部署的初始配置。如果您随后对 `BlueTaskSet` 资源中需要替换的属性进行了任何更改，则 CloudFormation 会在堆栈更新过程中启动绿色部署。

## JSON
<a name="blue-green-template-example.json"></a>

```
{
  "AWSTemplateFormatVersion":"2010-09-09",
  "Parameters":{
    "Vpc":{ "Type":"AWS::EC2::VPC::Id" },
    "Subnet1":{ "Type":"AWS::EC2::Subnet::Id" },
    "Subnet2":{ "Type":"AWS::EC2::Subnet::Id" }
  },
  "Transform":[ "AWS::CodeDeployBlueGreen" ],
  "Hooks":{
    "CodeDeployBlueGreenHook":{
      "Type":"AWS::CodeDeploy::BlueGreen",
      "Properties":{
        "TrafficRoutingConfig":{
          "Type":"TimeBasedCanary",
          "TimeBasedCanary":{
            "StepPercentage":15,
            "BakeTimeMins":5
          }
        },
        "Applications":[
          {
            "Target":{
              "Type":"AWS::ECS::Service",
              "LogicalID":"ECSDemoService"
            },
            "ECSAttributes":{
              "TaskDefinitions":[ "BlueTaskDefinition","GreenTaskDefinition" ],
              "TaskSets":[ "BlueTaskSet","GreenTaskSet" ],
              "TrafficRouting":{
                "ProdTrafficRoute":{
                  "Type":"AWS::ElasticLoadBalancingV2::Listener",
                  "LogicalID":"ALBListenerProdTraffic"
                },
                "TargetGroups":[ "ALBTargetGroupBlue","ALBTargetGroupGreen" ]
              }
            }
          }
        ]
      }
    }
  },
  "Resources":{
    "ExampleSecurityGroup":{
      "Type":"AWS::EC2::SecurityGroup",
      "Properties":{
        "GroupDescription":"Security group for ec2 access",
        "VpcId":{ "Ref":"Vpc" },
        "SecurityGroupIngress":[
          {
            "IpProtocol":"tcp",
            "FromPort":80,
            "ToPort":80,
            "CidrIp":"0.0.0.0/0"
          },
          {
            "IpProtocol":"tcp",
            "FromPort":8080,
            "ToPort":8080,
            "CidrIp":"0.0.0.0/0"
          },
          {
            "IpProtocol":"tcp",
            "FromPort":22,
            "ToPort":22,
            "CidrIp":"0.0.0.0/0"
          }
        ]
      }
    },
    "ALBTargetGroupBlue":{
      "Type":"AWS::ElasticLoadBalancingV2::TargetGroup",
      "Properties":{
        "HealthCheckIntervalSeconds":5,
        "HealthCheckPath":"/",
        "HealthCheckPort":"80",
        "HealthCheckProtocol":"HTTP",
        "HealthCheckTimeoutSeconds":2,
        "HealthyThresholdCount":2,
        "Matcher":{ "HttpCode":"200" },
        "Port":80,
        "Protocol":"HTTP",
        "Tags":[{ "Key":"Group","Value":"Example" }],
        "TargetType":"ip",
        "UnhealthyThresholdCount":4,
        "VpcId":{ "Ref":"Vpc" }
      }
    },
    "ALBTargetGroupGreen":{
      "Type":"AWS::ElasticLoadBalancingV2::TargetGroup",
      "Properties":{
        "HealthCheckIntervalSeconds":5,
        "HealthCheckPath":"/",
        "HealthCheckPort":"80",
        "HealthCheckProtocol":"HTTP",
        "HealthCheckTimeoutSeconds":2,
        "HealthyThresholdCount":2,
        "Matcher":{ "HttpCode":"200" },
        "Port":80,
        "Protocol":"HTTP",
        "Tags":[{ "Key":"Group","Value":"Example" }],
        "TargetType":"ip",
        "UnhealthyThresholdCount":4,
        "VpcId":{ "Ref":"Vpc" }
      }
    },
    "ExampleALB":{
      "Type":"AWS::ElasticLoadBalancingV2::LoadBalancer",
      "Properties":{
        "Scheme":"internet-facing",
        "SecurityGroups":[{ "Ref":"ExampleSecurityGroup" }],
        "Subnets":[{ "Ref":"Subnet1" },{ "Ref":"Subnet2" }],
        "Tags":[{ "Key":"Group","Value":"Example" }],
        "Type":"application",
        "IpAddressType":"ipv4"
      }
    },
    "ALBListenerProdTraffic":{
      "Type":"AWS::ElasticLoadBalancingV2::Listener",
      "Properties":{
        "DefaultActions":[
          {
            "Type":"forward",
            "ForwardConfig":{
              "TargetGroups":[
                {
                  "TargetGroupArn":{ "Ref":"ALBTargetGroupBlue" },
                  "Weight":1
                }
              ]
            }
          }
        ],
        "LoadBalancerArn":{ "Ref":"ExampleALB" },
        "Port":80,
        "Protocol":"HTTP"
      }
    },
    "ALBListenerProdRule":{
      "Type":"AWS::ElasticLoadBalancingV2::ListenerRule",
      "Properties":{
        "Actions":[
          {
            "Type":"forward",
            "ForwardConfig":{
              "TargetGroups":[
                {
                  "TargetGroupArn":{ "Ref":"ALBTargetGroupBlue" },
                  "Weight":1
                }
              ]
            }
          }
        ],
        "Conditions":[
          {
            "Field":"http-header",
            "HttpHeaderConfig":{
              "HttpHeaderName":"User-Agent",
              "Values":[ "Mozilla" ]
            }
          }
        ],
        "ListenerArn":{ "Ref":"ALBListenerProdTraffic" },
        "Priority":1
      }
    },
    "ECSTaskExecutionRole":{
      "Type":"AWS::IAM::Role",
      "Properties":{
        "AssumeRolePolicyDocument":{
          "Version": "2012-10-17",		 	 	 
          "Statement":[
            {
              "Sid":"",
              "Effect":"Allow",
              "Principal":{
                "Service":"ecs-tasks.amazonaws.com"
              },
              "Action":"sts:AssumeRole"
            }
          ]
        },
        "ManagedPolicyArns":[ "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" ]
      }
    },
    "BlueTaskDefinition":{
      "Type":"AWS::ECS::TaskDefinition",
      "Properties":{
        "ExecutionRoleArn":{
          "Fn::GetAtt":[ "ECSTaskExecutionRole","Arn" ]
        },
        "ContainerDefinitions":[
          {
            "Name":"DemoApp",
            "Image":"nginxdemos/hello:latest",
            "Essential":true,
            "PortMappings":[
              {
                "HostPort":80,
                "Protocol":"tcp",
                "ContainerPort":80
              }
            ]
          }
        ],
        "RequiresCompatibilities":[ "FARGATE" ],
        "NetworkMode":"awsvpc",
        "Cpu":"256",
        "Memory":"512",
        "Family":"ecs-demo"
      }
    },
    "ECSDemoCluster":{
      "Type":"AWS::ECS::Cluster",
      "Properties":{}
    },
    "ECSDemoService":{
      "Type":"AWS::ECS::Service",
      "Properties":{
        "Cluster":{ "Ref":"ECSDemoCluster" },
        "DesiredCount":1,
        "DeploymentController":{ "Type":"EXTERNAL" }
      }
    },
    "BlueTaskSet":{
      "Type":"AWS::ECS::TaskSet",
      "Properties":{
        "Cluster":{ "Ref":"ECSDemoCluster" },
        "LaunchType":"FARGATE",
        "NetworkConfiguration":{
          "AwsVpcConfiguration":{
            "AssignPublicIp":"ENABLED",
            "SecurityGroups":[{ "Ref":"ExampleSecurityGroup" }],
            "Subnets":[{ "Ref":"Subnet1" },{ "Ref":"Subnet2" }]
          }
        },
        "PlatformVersion":"1.4.0",
        "Scale":{
          "Unit":"PERCENT",
          "Value":100
        },
        "Service":{ "Ref":"ECSDemoService"},
        "TaskDefinition":{ "Ref":"BlueTaskDefinition" },
        "LoadBalancers":[
          {
            "ContainerName":"DemoApp",
            "ContainerPort":80,
            "TargetGroupArn":{ "Ref":"ALBTargetGroupBlue" }
          }
        ]
      }
    },
    "PrimaryTaskSet":{
      "Type":"AWS::ECS::PrimaryTaskSet",
      "Properties":{
        "Cluster":{ "Ref":"ECSDemoCluster" },
        "Service":{ "Ref":"ECSDemoService" },
        "TaskSetId":{ "Fn::GetAtt":[ "BlueTaskSet","Id" ]
        }
      }
    }
  }
}
```

## YAML
<a name="blue-green-template-example.yaml"></a>

```
AWSTemplateFormatVersion: 2010-09-09
Parameters:
  Vpc:
    Type: AWS::EC2::VPC::Id
  Subnet1:
    Type: AWS::EC2::Subnet::Id
  Subnet2:
    Type: AWS::EC2::Subnet::Id
Transform:
  - 'AWS::CodeDeployBlueGreen'
Hooks:
  CodeDeployBlueGreenHook:
    Type: AWS::CodeDeploy::BlueGreen
    Properties:
      TrafficRoutingConfig:
        Type: TimeBasedCanary
        TimeBasedCanary:
          StepPercentage: 15
          BakeTimeMins: 5
      Applications:
        - Target:
            Type: AWS::ECS::Service
            LogicalID: ECSDemoService
          ECSAttributes:
            TaskDefinitions:
              - BlueTaskDefinition
              - GreenTaskDefinition
            TaskSets:
              - BlueTaskSet
              - GreenTaskSet
            TrafficRouting:
              ProdTrafficRoute:
                Type: AWS::ElasticLoadBalancingV2::Listener
                LogicalID: ALBListenerProdTraffic
              TargetGroups:
                - ALBTargetGroupBlue
                - ALBTargetGroupGreen
Resources:
  ExampleSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for ec2 access
      VpcId: !Ref Vpc
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 8080
          ToPort: 8080
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
  ALBTargetGroupBlue:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 5
      HealthCheckPath: /
      HealthCheckPort: '80'
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 2
      HealthyThresholdCount: 2
      Matcher:
        HttpCode: '200'
      Port: 80
      Protocol: HTTP
      Tags:
        - Key: Group
          Value: Example
      TargetType: ip
      UnhealthyThresholdCount: 4
      VpcId: !Ref Vpc
  ALBTargetGroupGreen:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 5
      HealthCheckPath: /
      HealthCheckPort: '80'
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 2
      HealthyThresholdCount: 2
      Matcher:
        HttpCode: '200'
      Port: 80
      Protocol: HTTP
      Tags:
        - Key: Group
          Value: Example
      TargetType: ip
      UnhealthyThresholdCount: 4
      VpcId: !Ref Vpc
  ExampleALB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      SecurityGroups:
        - !Ref ExampleSecurityGroup
      Subnets:
        - !Ref Subnet1
        - !Ref Subnet2
      Tags:
        - Key: Group
          Value: Example
      Type: application
      IpAddressType: ipv4
  ALBListenerProdTraffic:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          ForwardConfig:
            TargetGroups:
              - TargetGroupArn: !Ref ALBTargetGroupBlue
                Weight: 1
      LoadBalancerArn: !Ref ExampleALB
      Port: 80
      Protocol: HTTP
  ALBListenerProdRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - Type: forward
          ForwardConfig:
            TargetGroups:
              - TargetGroupArn: !Ref ALBTargetGroupBlue
                Weight: 1
      Conditions:
        - Field: http-header
          HttpHeaderConfig:
            HttpHeaderName: User-Agent
            Values:
              - Mozilla
      ListenerArn: !Ref ALBListenerProdTraffic
      Priority: 1
  ECSTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: ''
            Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'
  BlueTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      ExecutionRoleArn: !GetAtt 
        - ECSTaskExecutionRole
        - Arn
      ContainerDefinitions:
        - Name: DemoApp
          Image: 'nginxdemos/hello:latest'
          Essential: true
          PortMappings:
            - HostPort: 80
              Protocol: tcp
              ContainerPort: 80
      RequiresCompatibilities:
        - FARGATE
      NetworkMode: awsvpc
      Cpu: '256'
      Memory: '512'
      Family: ecs-demo
  ECSDemoCluster:
    Type: AWS::ECS::Cluster
    Properties: {}
  ECSDemoService:
    Type: AWS::ECS::Service
    Properties:
      Cluster: !Ref ECSDemoCluster
      DesiredCount: 1
      DeploymentController:
        Type: EXTERNAL
  BlueTaskSet:
    Type: AWS::ECS::TaskSet
    Properties:
      Cluster: !Ref ECSDemoCluster
      LaunchType: FARGATE
      NetworkConfiguration:
        AwsVpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
            - !Ref ExampleSecurityGroup
          Subnets:
            - !Ref Subnet1
            - !Ref Subnet2
      PlatformVersion: 1.4.0
      Scale:
        Unit: PERCENT
        Value: 100
      Service: !Ref ECSDemoService
      TaskDefinition: !Ref BlueTaskDefinition
      LoadBalancers:
        - ContainerName: DemoApp
          ContainerPort: 80
          TargetGroupArn: !Ref ALBTargetGroupBlue
  PrimaryTaskSet:
    Type: AWS::ECS::PrimaryTaskSet
    Properties:
      Cluster: !Ref ECSDemoCluster
      Service: !Ref ECSDemoService
      TaskSetId: !GetAtt 
        - BlueTaskSet
        - Id
```

# CloudFormation 模板代码段
<a name="template-snippets"></a>

本部分提供了很多示例应用场景，您可以用其了解如何声明多种 Amazon CloudFormation 模板部件。您还可以将代码段用作您的自定义模板的起始部分。

**Topics**
+ [

# 通用模板代码段
](quickref-general.md)
+ [

# 自动扩缩 CloudFormation 模板代码段
](quickref-autoscaling.md)
+ [

# Amazon 账单控制台模板代码段
](quickref-billingconductor.md)
+ [

# Amazon CloudFormation 模板代码段
](quickref-cloudformation.md)
+ [

# Amazon CloudFront 模板代码段
](quickref-cloudfront.md)
+ [

# Amazon CloudWatch 模板代码段
](quickref-cloudwatch.md)
+ [

# Amazon CloudWatch Logs 模板代码段
](quickref-cloudwatchlogs.md)
+ [

# Amazon DynamoDB 模板代码段
](quickref-dynamodb.md)
+ [

# Amazon EC2 CloudFormation 模板代码段
](quickref-ec2.md)
+ [

# Amazon Elastic Container Service 示例模板
](quickref-ecs.md)
+ [

# Amazon Elastic File System 示例模板
](quickref-efs.md)
+ [

# Elastic Beanstalk 模板代码段
](quickref-elasticbeanstalk.md)
+ [

# Elastic Load Balancing 模板代码段
](quickref-elb.md)
+ [

# Amazon Identity and Access Management 模板代码段
](quickref-iam.md)
+ [

# Amazon Lambda 模板
](quickref-lambda.md)
+ [

# Amazon Redshift 模板代码段
](quickref-redshift.md)
+ [

# Amazon RDS 模板代码段
](quickref-rds.md)
+ [

# Route 53 模板代码段
](quickref-route53.md)
+ [

# Amazon S3 模板代码段
](quickref-s3.md)
+ [

# Amazon SNS 模板代码段
](quickref-sns.md)
+ [

# Amazon SQS 模板代码段
](scenario-sqs-queue.md)
+ [

# Amazon Timestream 模板代码片段
](scenario-timestream-queue.md)

# 通用模板代码段
<a name="quickref-general"></a>

以下示例介绍了并非特定于某个 Amazon 服务的不同 CloudFormation 模板功能。

**Topics**
+ [

## Base64 编码的 UserData 属性
](#scenario-userdata-base64)
+ [

## 使用 Base64 编码的 UserData 属性，具有 AccessKey 和 SecretKey
](#scenario-userdata-base64-with-keys)
+ [

## 含一个文字字符串参数的 Parameters 部分
](#scenario-one-string-parameter)
+ [

## 含有带正则表达式约束的字符串参数的 Parameters 部分
](#scenario-constraint-string-parameter)
+ [

## 含有数字参数的 Parameters 部分，带有 MinValue 和 MaxValue 约束
](#scenario-one-number-min-parameter)
+ [

## 含有数字参数的 Parameters 部分，带有 AllowedValues 约束
](#scenario-one-number-parameter)
+ [

## 含一个文字 CommaDelimitedList 参数的 Parameters 部分
](#scenario-one-list-parameter)
+ [

## 包含基于伪参数的参数值的 Parameters 部分
](#scenario-one-pseudo-parameter)
+ [

## 带有三个映射的 Mapping 部分
](#scenario-mapping-with-four-maps)
+ [

## 基于文字字符串的 Description
](#scenario-description-from-literal-string)
+ [

## 带有一个文件字符串输出的 Outputs 部分
](#scenario-output-with-literal-string)
+ [

## 包含一个资源引用和一个伪参数输出的 Outputs 部分
](#scenario-output-with-ref-and-pseudo-ref)
+ [

## 包含一个基于函数的输出、一个文字字符串、一个引用和一个伪参数的 Outputs 部分
](#scenario-output-with-complex-spec)
+ [

## 模板格式版本
](#scenario-format-version)
+ [

## Amazon Tags 属性
](#scenario-format-aws-tag)

## Base64 编码的 UserData 属性
<a name="scenario-userdata-base64"></a>

此示例演示了使用 `Fn::Base64` 和 `Fn::Join` 函数的 `UserData` 属性集合。引用 `MyValue` 和 `MyName` 是必须要在模板的 `Parameters` 部分定义的参数。文字字符串 `Hello World` 只是此示例传输作为 `UserData` 的一部分的另一个值。

### JSON
<a name="quickref-general-example-1.json"></a>

```
1. "UserData" : {
2.     "Fn::Base64" : {
3.         "Fn::Join" : [ ",", [
4.             { "Ref" : "MyValue" },
5.             { "Ref" : "MyName" },
6.             "Hello World" ] ]
7.     }
8. }
```

### YAML
<a name="quickref-general-example-1.yaml"></a>

```
1. UserData:
2.   Fn::Base64: !Sub |
3.      Ref: MyValue
4.      Ref: MyName
5.      Hello World
```

## 使用 Base64 编码的 UserData 属性，具有 AccessKey 和 SecretKey
<a name="scenario-userdata-base64-with-keys"></a>

此示例演示了使用 `Fn::Base64` 和 `Fn::Join` 函数的 `UserData` 属性集合。它包含 `AccessKey` 和 `SecretKey` 信息。参考 `AccessKey` 和 `SecretKey` 是必须要在模板的 Parameters 部分中定义的参数。

### JSON
<a name="quickref-general-example-2.json"></a>

```
1. "UserData" : {
2.     "Fn::Base64" : {
3.         "Fn::Join" : [ "", [
4.             "ACCESS_KEY=", { "Ref" : "AccessKey" },
5.             "SECRET_KEY=", { "Ref" : "SecretKey" } ]
6.         ]
7.     }
8. }
```

### YAML
<a name="quickref-general-example-2.yaml"></a>

```
1. UserData:
2.   Fn::Base64: !Sub |
3.      ACCESS_KEY=${AccessKey}
4.      SECRET_KEY=${SecretKey}
```

## 含一个文字字符串参数的 Parameters 部分
<a name="scenario-one-string-parameter"></a>

以下示例描述了有效的 Parameters 部分声明，其中声明有单个 `String` 类型参数。

### JSON
<a name="quickref-general-example-3.json"></a>

```
1. "Parameters" : {
2.     "UserName" : {
3.         "Type" : "String",
4.         "Default" : "nonadmin",
5.         "Description" : "Assume a vanilla user if no command-line spec provided"
6.     }
7. }
```

### YAML
<a name="quickref-general-example-3.yaml"></a>

```
1. Parameters:
2.   UserName:
3.     Type: String
4.     Default: nonadmin
5.     Description: Assume a vanilla user if no command-line spec provided
```

## 含有带正则表达式约束的字符串参数的 Parameters 部分
<a name="scenario-constraint-string-parameter"></a>

以下示例描述了有效的 Parameters 部分声明，其中声明有单个 `String` 类型参数。`AdminUserAccount` 参数的默认值为 `admin`。参数值的最小长度必须为 1，最大长度必须为 16，且其中包含字母字符和数字，但必须以字母字符开头。

### JSON
<a name="quickref-general-example-4.json"></a>

```
 1. "Parameters" : {
 2.     "AdminUserAccount": {
 3.       "Default": "admin",
 4.       "NoEcho": "true",
 5.       "Description" : "The admin account user name",
 6.       "Type": "String",
 7.       "MinLength": "1",
 8.       "MaxLength": "16",
 9.       "AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*"
10.     }
11. }
```

### YAML
<a name="quickref-general-example-4.yaml"></a>

```
1. Parameters:
2.   AdminUserAccount:
3.     Default: admin
4.     NoEcho: true
5.     Description: The admin account user name
6.     Type: String
7.     MinLength: 1
8.     MaxLength: 16
9.     AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*'
```

## 含有数字参数的 Parameters 部分，带有 MinValue 和 MaxValue 约束
<a name="scenario-one-number-min-parameter"></a>

以下示例描述了有效的 Parameters 部分声明，其中声明有单个 `Number` 类型参数。`WebServerPort` 参数的默认值为 80，最小值为 1，最大值为 65535。

### JSON
<a name="quickref-general-example-5.json"></a>

```
1. "Parameters" : {
2.     "WebServerPort": {
3.       "Default": "80",
4.       "Description" : "TCP/IP port for the web server",
5.       "Type": "Number",
6.       "MinValue": "1",
7.       "MaxValue": "65535"
8.     }
9. }
```

### YAML
<a name="quickref-general-example-5.yaml"></a>

```
1. Parameters:
2.   WebServerPort:
3.     Default: 80
4.     Description: TCP/IP port for the web server
5.     Type: Number
6.     MinValue: 1
7.     MaxValue: 65535
```

## 含有数字参数的 Parameters 部分，带有 AllowedValues 约束
<a name="scenario-one-number-parameter"></a>

以下示例描述了有效的 Parameters 部分声明，其中声明有单个 `Number` 类型参数。`WebServerPort` 参数的默认值为 80，且只允许值 80 和 8888。

### JSON
<a name="quickref-general-example-6.json"></a>

```
1. "Parameters" : {
2.     "WebServerPortLimited": {
3.       "Default": "80",
4.       "Description" : "TCP/IP port for the web server",
5.       "Type": "Number",
6.       "AllowedValues" : ["80", "8888"]
7.     }
8. }
```

### YAML
<a name="quickref-general-example-6.yaml"></a>

```
1. Parameters:
2.   WebServerPortLimited:
3.     Default: 80
4.     Description: TCP/IP port for the web server
5.     Type: Number
6.     AllowedValues:
7.     - 80
8.     - 8888
```

## 含一个文字 CommaDelimitedList 参数的 Parameters 部分
<a name="scenario-one-list-parameter"></a>

以下示例描述了有效的 `Parameters` 部分声明，其中声明了单个 `CommaDelimitedList` 类型参数。`NoEcho` 属性设置为 `TRUE`，该属性将使用 **describe-stacks** 输出中的星号（\$1\$1\$1\$1\$1）掩盖其值，但存储在下面指定位置的信息除外。

**重要**  
使用 `NoEcho` 属性不会遮蔽在以下各区段中存储的任何信息：  
`Metadata` 模板区段。CloudFormation 不会转换、修改或编辑您在 `Metadata` 部分中包含的任何信息。有关更多信息，请参阅 [Metadata](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html)。
`Outputs` 模板区段。有关更多信息，请参阅 [Outputs](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html)。
资源定义的 `Metadata` 属性。有关更多信息，请参阅 [`Metadata` 属性](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-attribute-metadata.html)。
强烈建议您不要使用这些机制来包含敏感信息，例如密码。

**重要**  
我们建议不要将敏感信息直接嵌入 CloudFormation 模板中，而应使用堆栈模板中的动态参数来引用在 CloudFormation 外部存储和管理的敏感信息，例如 Amazon Systems Manager Parameter Store 或 Amazon Secrets Manager 中的敏感信息。  
有关更多信息，请参阅[请勿将凭证嵌入您的模板](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/security-best-practices.html#creds)最佳实践。

### JSON
<a name="quickref-general-example-7.json"></a>

```
1. "Parameters" : {
2.     "UserRoles" : {
3.         "Type" : "CommaDelimitedList",
4.         "Default" : "guest,newhire",
5.         "NoEcho" : "TRUE"
6.     }
7. }
```

### YAML
<a name="quickref-general-example-7.yaml"></a>

```
1. Parameters:
2.   UserRoles:
3.     Type: CommaDelimitedList
4.     Default: "guest,newhire"
5.     NoEcho: true
```

## 包含基于伪参数的参数值的 Parameters 部分
<a name="scenario-one-pseudo-parameter"></a>

以下示例说明 EC2 用户数据中使用伪参数 `AWS::StackName` 和 `AWS::Region` 的命令。有关伪参数的更多信息，请参阅[使用伪参数获取 Amazon 值](pseudo-parameter-reference.md)。

### JSON
<a name="quickref-general-example-10.json"></a>

```
 1.           "UserData"       : { "Fn::Base64" : { "Fn::Join" : ["", [
 2.              "#!/bin/bash -xe\n",
 3.              "yum install -y aws-cfn-bootstrap\n",
 4. 
 5.              "/opt/aws/bin/cfn-init -v ",
 6.              "         --stack ", { "Ref" : "AWS::StackName" },
 7.              "         --resource LaunchConfig ",
 8.              "         --region ", { "Ref" : "AWS::Region" }, "\n",
 9. 
10.              "/opt/aws/bin/cfn-signal -e $? ",
11.              "         --stack ", { "Ref" : "AWS::StackName" },
12.              "         --resource WebServerGroup ",
13.              "         --region ", { "Ref" : "AWS::Region" }, "\n"
14.         ]]}}
15.       }
```

### YAML
<a name="quickref-general-example-10.yaml"></a>

```
1. UserData:
2.   Fn::Base64: !Sub |
3.      #!/bin/bash -xe
4.      yum update -y aws-cfn-bootstrap
5.      /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchConfig --region ${AWS::Region}
6.      /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerGroup --region ${AWS::Region}
```

## 带有三个映射的 Mapping 部分
<a name="scenario-mapping-with-four-maps"></a>

以下示例描述了其中包含三个映射的有效 `Mapping` 部分声明。映射在与 `Stop`、`SlowDown` 或 `Go` 映射密钥匹配时提供分配至相应 `RGBColor` 属性的 RGB 值。

### JSON
<a name="quickref-general-example-11.json"></a>

```
 1. "Mappings" : {
 2.     "LightColor" : {
 3.         "Stop" : {
 4.             "Description" : "red",
 5.             "RGBColor" : "RED 255 GREEN 0 BLUE 0"
 6.         },
 7.         "SlowDown" : {
 8.             "Description" : "yellow",
 9.             "RGBColor" : "RED 255 GREEN 255 BLUE 0"
10.         },
11.         "Go" : {
12.             "Description" : "green",
13.             "RGBColor" : "RED 0 GREEN 128 BLUE 0"
14.         }
15.     }
16. }
```

### YAML
<a name="quickref-general-example-11.yaml"></a>

```
 1. Mappings:
 2.   LightColor:
 3.     Stop:
 4.       Description: red
 5.       RGBColor: "RED 255 GREEN 0 BLUE 0"
 6.     SlowDown:
 7.       Description: yellow
 8.       RGBColor: "RED 255 GREEN 255 BLUE 0"
 9.     Go:
10.       Description: green
11.       RGBColor: "RED 0 GREEN 128 BLUE 0"
```

## 基于文字字符串的 Description
<a name="scenario-description-from-literal-string"></a>

以下示例描述了有效的 `Description` 部分声明，其中的值基于文字字符串。此代码段可用于模板、参数、资源、属性或输出。

### JSON
<a name="quickref-general-example-8.json"></a>

```
1. "Description" : "Replace this value"
```

### YAML
<a name="quickref-general-example-8.yaml"></a>

```
1. Description: "Replace this value"
```

## 带有一个文件字符串输出的 Outputs 部分
<a name="scenario-output-with-literal-string"></a>

此示例显示的是基于文字字符串的输出分配。

### JSON
<a name="quickref-general-example-12.json"></a>

```
1. "Outputs" : {
2.     "MyPhone" : {
3.         "Value" : "Please call 555-5555",
4.         "Description" : "A random message for aws cloudformation describe-stacks"
5.     }
6. }
```

### YAML
<a name="quickref-general-example-12.yaml"></a>

```
1. Outputs:
2.   MyPhone:
3.     Value: Please call 555-5555
4.     Description: A random message for aws cloudformation describe-stacks
```

## 包含一个资源引用和一个伪参数输出的 Outputs 部分
<a name="scenario-output-with-ref-and-pseudo-ref"></a>

此示例显示的是含有两个输出分配的 `Outputs` 部分。一个基于资源，另一个基于伪引用。

### JSON
<a name="quickref-general-example-13.json"></a>

```
1. "Outputs" : {
2.    "SNSTopic" : { "Value" : { "Ref" : "MyNotificationTopic" } },
3.    "StackName" : { "Value" : { "Ref" : "AWS::StackName" } }
4. }
```

### YAML
<a name="quickref-general-example-13.yaml"></a>

```
1. Outputs:
2.   SNSTopic:
3.     Value: !Ref MyNotificationTopic
4.   StackName:
5.     Value: !Ref AWS::StackName
```

## 包含一个基于函数的输出、一个文字字符串、一个引用和一个伪参数的 Outputs 部分
<a name="scenario-output-with-complex-spec"></a>

此示例显示的是带有一个输出分配的输出部分。Join 函数用于连接值，将百分比符号用作分隔符。

### JSON
<a name="quickref-general-example-14.json"></a>

```
1. "Outputs" : {
2.     "MyOutput" : {
3.         "Value" : { "Fn::Join" :
4.             [ "%", [ "A-string", {"Ref" : "AWS::StackName" } ] ]
5.         }
6.     }
7. }
```

### YAML
<a name="quickref-general-example-14.yaml"></a>

```
1. Outputs:
2.   MyOutput:
3.     Value: !Join [ %, [ 'A-string', !Ref 'AWS::StackName' ]]
```

## 模板格式版本
<a name="scenario-format-version"></a>

以下代码段描述了有效的 `AWSTemplateFormatVersion` 部分声明。

### JSON
<a name="quickref-general-example-9.json"></a>

```
1. "AWSTemplateFormatVersion" : "2010-09-09"
```

### YAML
<a name="quickref-general-example-9.yaml"></a>

```
1. AWSTemplateFormatVersion: '2010-09-09'
```

## Amazon Tags 属性
<a name="scenario-format-aws-tag"></a>

本示例将展示 Amazon `Tags` 属性。您将在资源的 Properties 部分中执行该属性。资源被创建后，会标上您声明的标签。

### JSON
<a name="quickref-general-example-15.json"></a>

```
 1. "Tags" : [
 2.       {
 3.         "Key" : "keyname1",
 4.         "Value" : "value1"
 5.       },
 6.       {
 7.         "Key" : "keyname2",
 8.         "Value" : "value2"
 9.       }
10.     ]
```

### YAML
<a name="quickref-general-example-15.yaml"></a>

```
1. Tags: 
2.   - 
3.     Key: "keyname1"
4.     Value: "value1"
5.   - 
6.     Key: "keyname2"
7.     Value: "value2"
```

# 自动扩缩 CloudFormation 模板代码段
<a name="quickref-autoscaling"></a>

凭借 Amazon EC2 Auto Scaling，您可以通过扩缩策略或计划扩缩自动扩缩 Amazon EC2 实例。自动扩缩组是 Amazon EC2 实例的集合，这些实例支持自动扩缩和实例集管理功能，例如例如扩缩策略、计划操作、运行状况检查、生命周期挂钩和负载平衡。

Application Auto Scaling 通过扩展策略或计划扩展，可以自动扩展 Amazon EC2 以外的其他资源。

您可以使用 Amazon CloudFormation 模板创建和配置自动扩缩组、扩缩策略、计划操作以及其他自动扩缩资源，将其作为基础架构的一部分。模板可以让您轻松地以可重复且一致的方式管理和自动部署自动扩缩资源。

以下示例模板代码段描述了 Amazon EC2 Auto Scaling 和 Application Auto Scaling 的 Amazon CloudFormation 资源或组件。这些代码段旨在集成到模板中，不打算独立运行。

**Topics**
+ [配置 Amazon EC2 Auto Scaling 资源](quickref-ec2-auto-scaling.md)
+ [配置 Application Auto Scaling 资源](quickref-application-auto-scaling.md)

# 使用 Amazon CloudFormation 配置 Amazon EC2 Auto Scaling 资源
<a name="quickref-ec2-auto-scaling"></a>

以下示例演示了要包含在模板中的不同代码段，以便与 Amazon EC2 Auto Scaling 一起使用。

**Topics**
+ [

## 创建单个实例自动扩缩组
](#scenario-single-instance-as-group)
+ [

## 创建具有附加负载均衡器的自动扩缩组
](#scenario-as-group)
+ [

## 创建具有通知的自动扩缩组
](#scenario-as-notification)
+ [

## 创建使用 `CreationPolicy` 和 `UpdatePolicy` 的自动扩缩组
](#scenario-as-updatepolicy)
+ [

## 创建分步扩缩策略
](#scenario-step-scaling-policy)
+ [

## 混合实例组示例
](#scenario-mixed-instances-group-template-examples)
+ [

## 启动配置示例
](#scenario-launch-config-template-examples)

## 创建单个实例自动扩缩组
<a name="scenario-single-instance-as-group"></a>

此示例显示具有单个实例的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html) 资源以帮助您开始使用。自动扩缩组的 `VPCZoneIdentifier` 属性指定三个不同可用区中的一系列现有子网。在创建堆栈之前，必须先从您的账户指定适用的子网 ID。`LaunchTemplate` 属性引用具有在模板其他位置中定义的逻辑名称 `myLaunchTemplate` 的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html) 资源。

**注意**  
有关启动模板的示例，请参阅 Amazon EC2 代码段部分中的 [使用 CloudFormation 创建启动模板](quickref-ec2-launch-templates.md) 和 `AWS::EC2::LaunchTemplate` 资源中的[示例](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html#aws-resource-ec2-launchtemplate--examples)部分。

### JSON
<a name="quickref-autoscaling-example-1.json"></a>

```
 1. "myASG" : {
 2.    "Type" : "AWS::AutoScaling::AutoScalingGroup",
 3.    "Properties" : {
 4.       "VPCZoneIdentifier" : [ "subnetIdAz1", "subnetIdAz2", "subnetIdAz3" ],
 5.       "LaunchTemplate" : {
 6.         "LaunchTemplateId" : {
 7.           "Ref" : "myLaunchTemplate"
 8.         },
 9.         "Version" : {
10.           "Fn::GetAtt" : [
11.             "myLaunchTemplate",
12.             "LatestVersionNumber"
13.           ]
14.         }
15.       },
16.       "MaxSize" : "1",
17.       "MinSize" : "1"
18.    }
19. }
```

### YAML
<a name="quickref-autoscaling-example-1.yaml"></a>

```
 1. myASG:
 2.   Type: AWS::AutoScaling::AutoScalingGroup
 3.   Properties:
 4.     VPCZoneIdentifier:
 5.       - subnetIdAz1
 6.       - subnetIdAz2
 7.       - subnetIdAz3
 8.     LaunchTemplate:
 9.       LaunchTemplateId: !Ref myLaunchTemplate
10.       Version: !GetAtt myLaunchTemplate.LatestVersionNumber
11.     MaxSize: '1'
12.     MinSize: '1'
```

## 创建具有附加负载均衡器的自动扩缩组
<a name="scenario-as-group"></a>

此示例显示了用于在多个服务器之间实现负载均衡的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html) 资源。它指定在同一模板中的其他位置声明的 Amazon 资源的逻辑名称。

1. `VPCZoneIdentifier` 属性指定将在其中创建自动扩缩组的 EC2 实例的两个 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-subnet.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-subnet.html) 资源的逻辑名称：`myPublicSubnet1` 和 `myPublicSubnet2`。

1. `LaunchTemplate` 属性指定具有逻辑名称 `myLaunchTemplate` 的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html) 资源。

1. `TargetGroupARNs` 属性列出用于将流量路由到自动扩缩组的应用程序负载均衡器或网络负载均衡器的目标组。在此示例中，指定了一个目标组，即具有逻辑名称 `myTargetGroup` 的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-targetgroup.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-targetgroup.html) 资源。

### JSON
<a name="quickref-autoscaling-example-2.json"></a>

```
 1. "myServerGroup" : {
 2.    "Type" : "AWS::AutoScaling::AutoScalingGroup",
 3.    "Properties" : {
 4.       "VPCZoneIdentifier" : [ { "Ref" : "myPublicSubnet1" }, { "Ref" : "myPublicSubnet2" } ],
 5.       "LaunchTemplate" : {
 6.         "LaunchTemplateId" : {
 7.           "Ref" : "myLaunchTemplate"
 8.         },
 9.         "Version" : {
10.           "Fn::GetAtt" : [
11.             "myLaunchTemplate",
12.             "LatestVersionNumber"
13.           ]
14.         }
15.       },
16.       "MaxSize" : "5",
17.       "MinSize" : "1",
18.       "TargetGroupARNs" : [ { "Ref" : "myTargetGroup" } ]
19.    }
20. }
```

### YAML
<a name="quickref-autoscaling-example-2.yaml"></a>

```
 1. myServerGroup:
 2.   Type: AWS::AutoScaling::AutoScalingGroup
 3.   Properties:
 4.     VPCZoneIdentifier:
 5.       - !Ref myPublicSubnet1
 6.       - !Ref myPublicSubnet2
 7.     LaunchTemplate:
 8.       LaunchTemplateId: !Ref myLaunchTemplate
 9.       Version: !GetAtt myLaunchTemplate.LatestVersionNumber
10.     MaxSize: '5'
11.     MinSize: '1'
12.     TargetGroupARNs:
13.       - !Ref myTargetGroup
```

### 另请参阅
<a name="scenario-as-group-see-also"></a>

有关根据 `ALBRequestCountPerTarget` 预定义指标为应用程序负载均衡器创建具有目标跟踪扩展策略的自动扩缩组的详细示例，请参阅 `AWS::AutoScaling::ScalingPolicy` 资源中的[示例](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-scalingpolicy.html#aws-resource-autoscaling-scalingpolicy--examples)部分。

## 创建具有通知的自动扩缩组
<a name="scenario-as-notification"></a>

此示例显示的是在指定事件发生时发送 Amazon SNS 通知的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html) 资源。`NotificationConfigurations` 属性指定 Amazon CloudFormation 在其中发送通知的 SNS 主题和将导致 Amazon CloudFormation 发送通知的事件。当 `NotificationTypes` 指定的事件发生时，Amazon CloudFormation 会发送一条通知至 `TopicARN` 指定的 SNS 主题中。启动堆栈时，Amazon CloudFormation 会创建在同一模板中声明的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sns-subscription.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sns-subscription.html) 资源（`snsTopicForAutoScalingGroup`）。

自动扩缩组的 `VPCZoneIdentifier` 属性指定三个不同可用区中的一系列现有子网。在创建堆栈之前，必须先从您的账户指定适用的子网 ID。`LaunchTemplate` 属性引用在同一模板中的其他位置声明的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html) 资源的逻辑名称。

### JSON
<a name="quickref-autoscaling-example-3.json"></a>

```
 1. "myASG" : {
 2.   "Type" : "AWS::AutoScaling::AutoScalingGroup",
 3.   "DependsOn": [
 4.     "snsTopicForAutoScalingGroup"
 5.   ],
 6.   "Properties" : {
 7.     "VPCZoneIdentifier" : [ "subnetIdAz1", "subnetIdAz2", "subnetIdAz3" ],
 8.     "LaunchTemplate" : {
 9.       "LaunchTemplateId" : {
10.         "Ref" : "logicalName"
11.       },
12.       "Version" : {
13.         "Fn::GetAtt" : [
14.           "logicalName",
15.           "LatestVersionNumber"
16.         ]
17.       }
18.     },
19.     "MaxSize" : "5",
20.     "MinSize" : "1",
21.     "NotificationConfigurations" : [
22.       {
23.         "TopicARN" : { "Ref" : "snsTopicForAutoScalingGroup" },
24.         "NotificationTypes" : [
25.           "autoscaling:EC2_INSTANCE_LAUNCH",
26.           "autoscaling:EC2_INSTANCE_LAUNCH_ERROR",
27.           "autoscaling:EC2_INSTANCE_TERMINATE",
28.           "autoscaling:EC2_INSTANCE_TERMINATE_ERROR",
29.           "autoscaling:TEST_NOTIFICATION"
30.         ]
31.       }
32.     ]
33.   }
34. }
```

### YAML
<a name="quickref-autoscaling-example-3.yaml"></a>

```
 1. myASG:
 2.   Type: AWS::AutoScaling::AutoScalingGroup
 3.   DependsOn:
 4.     - snsTopicForAutoScalingGroup
 5.   Properties:
 6.     VPCZoneIdentifier:
 7.       - subnetIdAz1
 8.       - subnetIdAz2
 9.       - subnetIdAz3
10.     LaunchTemplate:
11.       LaunchTemplateId: !Ref logicalName
12.       Version: !GetAtt logicalName.LatestVersionNumber
13.     MaxSize: '5'
14.     MinSize: '1'
15.     NotificationConfigurations:
16.       - TopicARN: !Ref snsTopicForAutoScalingGroup
17.         NotificationTypes:
18.           - autoscaling:EC2_INSTANCE_LAUNCH
19.           - autoscaling:EC2_INSTANCE_LAUNCH_ERROR
20.           - autoscaling:EC2_INSTANCE_TERMINATE
21.           - autoscaling:EC2_INSTANCE_TERMINATE_ERROR
22.           - autoscaling:TEST_NOTIFICATION
```

## 创建使用 `CreationPolicy` 和 `UpdatePolicy` 的自动扩缩组
<a name="scenario-as-updatepolicy"></a>

以下示例演示如何将 `CreationPolicy` 和 `UpdatePolicy` 属性添加到 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html) 资源。

示例创建策略会阻止自动扩缩组达到 `CREATE_COMPLETE` 状态，直到 Amazon CloudFormation 在该组准备就绪后收到 `Count` 个成功信号。要发出自动扩缩组已就绪的信号，在实例上运行添加到启动模板用户数据（未显示）的 `cfn-signal` 帮助程序脚本。如果实例未在规定的 `Timeout` 内发送信号，则 CloudFormation 假设未创建实例、资源创建失败和 CloudFormation 回滚堆栈。

示例更新策略指示 CloudFormation 使用 `AutoScalingRollingUpdate` 属性执行滚动更新。滚动更新根据 `MaxBatchSize` 和基于 `PauseTime` 的更新批次之间的暂停时间以小批量的方式更改自动扩缩组（在本示例中，为逐个实例更改）。`MinInstancesInService` 属性指定当 CloudFormation 更新旧实例时，自动扩缩组内必须处于服务状态的实例的最小数量。

`WaitOnResourceSignals` 属性设置为 `true`。CloudFormation 必须在指定的 `PauseTime` 内收到每个新实例的信号，才能继续更新。在执行堆栈更新时，以下 EC2 Auto Scaling 进程会暂停：`HealthCheck`、`ReplaceUnhealthy`、`AZRebalance`、`AlarmNotification` 和 `ScheduledActions`。注意：不要暂停 `Launch`、`Terminate` 或 `AddToLoadBalancer` （如果自动扩缩组正在与 Elastic Load Balancing 一起使用）进程类型，因为这样做会使滚动更新无法正常工作。

自动扩缩组的 `VPCZoneIdentifier` 属性指定三个不同可用区中的一系列现有子网。在创建堆栈之前，必须先从您的账户指定适用的子网 ID。`LaunchTemplate` 属性引用在同一模板中的其他位置声明的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html) 资源的逻辑名称。

有关 `CreationPolicy` 和 `UpdatePolicy` 属性的更多信息，请参阅[资源属性引用](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-product-attribute-reference.html)。

### JSON
<a name="quickref-autoscaling-example-4.json"></a>

```
{
  "Resources":{
    "myASG":{
      "CreationPolicy":{
        "ResourceSignal":{
          "Count":"3",
          "Timeout":"PT15M"
        }
      },
      "UpdatePolicy":{
        "AutoScalingRollingUpdate":{
          "MinInstancesInService":"3",
          "MaxBatchSize":"1",
          "PauseTime":"PT12M5S",
          "WaitOnResourceSignals":"true",
          "SuspendProcesses":[
            "HealthCheck",
            "ReplaceUnhealthy",
            "AZRebalance",
            "AlarmNotification",
            "ScheduledActions",
            "InstanceRefresh"
          ]
        }
      },
      "Type":"AWS::AutoScaling::AutoScalingGroup",
      "Properties":{
        "VPCZoneIdentifier":[ "subnetIdAz1", "subnetIdAz2", "subnetIdAz3" ],
        "LaunchTemplate":{
          "LaunchTemplateId":{
            "Ref":"logicalName"
          },
          "Version":{
            "Fn::GetAtt":[
              "logicalName",
              "LatestVersionNumber"
            ]
          }
        },
        "MaxSize":"5",
        "MinSize":"3"
      }
    }
  }
}
```

### YAML
<a name="quickref-autoscaling-example-4.yaml"></a>

```
---
Resources:
  myASG:
    CreationPolicy:
      ResourceSignal:
        Count: '3'
        Timeout: PT15M
    UpdatePolicy:
      AutoScalingRollingUpdate:
        MinInstancesInService: '3'
        MaxBatchSize: '1'
        PauseTime: PT12M5S
        WaitOnResourceSignals: true
        SuspendProcesses:
          - HealthCheck
          - ReplaceUnhealthy
          - AZRebalance
          - AlarmNotification
          - ScheduledActions
          - InstanceRefresh
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      VPCZoneIdentifier:
        - subnetIdAz1
        - subnetIdAz2
        - subnetIdAz3
      LaunchTemplate:
        LaunchTemplateId: !Ref logicalName
        Version: !GetAtt logicalName.LatestVersionNumber
      MaxSize: '5'
      MinSize: '3'
```

## 创建分步扩缩策略
<a name="scenario-step-scaling-policy"></a>

此示例显示了使用分步扩缩策略横向扩展自动扩缩组的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-scalingpolicy.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-scalingpolicy.html) 资源。`AdjustmentType` 属性指定 `ChangeInCapacity`，这表示 `ScalingAdjustment` 代表待添加（如果 `ScalingAdjustment` 为正值）或待删除（如果它为负值）实例的数量。在此示例中，`ScalingAdjustment` 为 1；因此，当超出警报阈值时，策略会将组中 EC2 实例的数量增加 1。

[https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudwatch-alarm.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudwatch-alarm.html) 资源 `CPUAlarmHigh` 指定扩缩策略 `ASGScalingPolicyHigh` 作为警报处于 ALARM 状态时要运行的操作（`AlarmActions`）。`Dimensions` 属性引用在同一模板中的其他位置声明的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html) 资源的逻辑名称。

### JSON
<a name="quickref-autoscaling-example-5.json"></a>

```
 1. {
 2.   "Resources":{
 3.     "ASGScalingPolicyHigh":{
 4.       "Type":"AWS::AutoScaling::ScalingPolicy",
 5.       "Properties":{
 6.         "AutoScalingGroupName":{ "Ref":"logicalName" },
 7.         "PolicyType":"StepScaling",
 8.         "AdjustmentType":"ChangeInCapacity",
 9.         "StepAdjustments":[
10.           {
11.             "MetricIntervalLowerBound":0,
12.             "ScalingAdjustment":1
13.           }
14.         ]
15.       }
16.     },
17.     "CPUAlarmHigh":{
18.       "Type":"AWS::CloudWatch::Alarm",
19.       "Properties":{
20.         "EvaluationPeriods":"2",
21.         "Statistic":"Average",
22.         "Threshold":"90",
23.         "AlarmDescription":"Scale out if CPU > 90% for 2 minutes",
24.         "Period":"60",
25.         "AlarmActions":[ { "Ref":"ASGScalingPolicyHigh" } ],
26.         "Namespace":"AWS/EC2",
27.         "Dimensions":[
28.           {
29.             "Name":"AutoScalingGroupName",
30.             "Value":{ "Ref":"logicalName" }
31.           }
32.         ],
33.         "ComparisonOperator":"GreaterThanThreshold",
34.         "MetricName":"CPUUtilization"
35.       }
36.     }
37.   }
38. }
```

### YAML
<a name="quickref-autoscaling-example-5.yaml"></a>

```
 1. ---
 2. Resources:
 3.   ASGScalingPolicyHigh:
 4.     Type: AWS::AutoScaling::ScalingPolicy
 5.     Properties:
 6.       AutoScalingGroupName: !Ref logicalName
 7.       PolicyType: StepScaling
 8.       AdjustmentType: ChangeInCapacity
 9.       StepAdjustments: 
10.         - MetricIntervalLowerBound: 0
11.           ScalingAdjustment: 1
12.   CPUAlarmHigh:
13.     Type: AWS::CloudWatch::Alarm
14.     Properties:
15.       EvaluationPeriods: 2
16.       Statistic: Average
17.       Threshold: 90
18.       AlarmDescription: 'Scale out if CPU > 90% for 2 minutes'
19.       Period: 60
20.       AlarmActions:
21.         - !Ref ASGScalingPolicyHigh
22.       Namespace: AWS/EC2
23.       Dimensions:
24.         - Name: AutoScalingGroupName
25.           Value:
26.             !Ref logicalName
27.       ComparisonOperator: GreaterThanThreshold
28.       MetricName: CPUUtilization
```

### 另请参阅
<a name="scenario-as-policy-see-also"></a>

有关扩展策略的更多示例模板，请参阅 `AWS::AutoScaling::ScalingPolicy` 资源中的[示例](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-scalingpolicy.html#aws-resource-autoscaling-scalingpolicy--examples)部分。

## 混合实例组示例
<a name="scenario-mixed-instances-group-template-examples"></a>

### 使用基于属性的实例类型选择创建自动扩缩组
<a name="scenario-mixed-instances-group-instance-requirements"></a>

此示例显示了 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html) 资源，其中包含使用基于属性的实例类型选择启动混合实例组的信息。您指定了 `VCpuCount` 属性的最小值和最大值，以及 `MemoryMiB` 属性的最小值。自动扩缩组使用的所有实例类型都必须与您所需实例的属性匹配。

自动扩缩组的 `VPCZoneIdentifier` 属性指定三个不同可用区中的一系列现有子网。在创建堆栈之前，必须先从您的账户指定适用的子网 ID。`LaunchTemplate` 属性引用在同一模板中的其他位置声明的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html) 资源的逻辑名称。

#### JSON
<a name="quickref-mixed-instances-group-example-2.json"></a>

```
 1. {
 2.   "Resources":{
 3.     "myASG":{
 4.       "Type":"AWS::AutoScaling::AutoScalingGroup",
 5.       "Properties":{
 6.         "VPCZoneIdentifier":[
 7.           "subnetIdAz1",
 8.           "subnetIdAz2",
 9.           "subnetIdAz3"
10.         ],
11.         "MixedInstancesPolicy":{
12.           "LaunchTemplate":{
13.             "LaunchTemplateSpecification":{
14.               "LaunchTemplateId":{
15.                 "Ref":"logicalName"
16.               },
17.               "Version":{
18.                 "Fn::GetAtt":[
19.                   "logicalName",
20.                   "LatestVersionNumber"
21.                 ]
22.               }
23.             },
24.             "Overrides":[
25.               {
26.                 "InstanceRequirements":{
27.                   "VCpuCount":{
28.                     "Min":2,
29.                     "Max":4
30.                   },
31.                   "MemoryMiB":{
32.                     "Min":2048
33.                   }
34.                 }
35.               }
36.             ]
37.           }
38.         },
39.         "MaxSize":"5",
40.         "MinSize":"1"
41.       }
42.     }
43.   }
44. }
```

#### YAML
<a name="quickref-mixed-instances-group-example-1.yaml"></a>

```
 1. ---
 2. Resources:
 3.   myASG:
 4.     Type: AWS::AutoScaling::AutoScalingGroup
 5.     Properties:
 6.       VPCZoneIdentifier:
 7.         - subnetIdAz1
 8.         - subnetIdAz2
 9.         - subnetIdAz3
10.       MixedInstancesPolicy:
11.         LaunchTemplate:
12.           LaunchTemplateSpecification:
13.             LaunchTemplateId: !Ref logicalName
14.             Version: !GetAtt logicalName.LatestVersionNumber
15.           Overrides:
16.             - InstanceRequirements:
17.                 VCpuCount:
18.                   Min: 2
19.                   Max: 4
20.                 MemoryMiB:
21.                   Min: 2048
22.       MaxSize: '5'
23.       MinSize: '1'
```

## 启动配置示例
<a name="scenario-launch-config-template-examples"></a>

### 创建启动配置
<a name="scenario-as-launch-config"></a>

此示例显示了自动扩缩组的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-launchconfiguration.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-launchconfiguration.html) 资源，您可以在其中指定 `ImageId`、`InstanceType` 和 `SecurityGroups` 属性的值。`SecurityGroups` 属性指定在模板中其他位置指定的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html) 资源的逻辑名称，以及名为 `myExistingEC2SecurityGroup` 的现有 EC2 安全组。

#### JSON
<a name="quickref-launch-config-example-1.json"></a>

```
1. "mySimpleConfig" : {
2.    "Type" : "AWS::AutoScaling::LaunchConfiguration",
3.    "Properties" : {
4.       "ImageId" : "ami-02354e95b3example",
5.       "InstanceType" : "t3.micro",
6.       "SecurityGroups" : [ { "Ref" : "logicalName" }, "myExistingEC2SecurityGroup" ]
7.    }
8. }
```

#### YAML
<a name="quickref-launch-config-example-1.yaml"></a>

```
1. mySimpleConfig:
2.   Type: AWS::AutoScaling::LaunchConfiguration
3.   Properties:
4.     ImageId: ami-02354e95b3example
5.     InstanceType: t3.micro
6.     SecurityGroups:
7.       - !Ref logicalName
8.       - myExistingEC2SecurityGroup
```

### 使用启动配置创建自动扩缩组
<a name="scenario-single-instance-as-group-launch-configuration"></a>

此示例显示具有单个实例的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html) 资源。自动扩缩组的 `VPCZoneIdentifier` 属性指定三个不同可用区中的一系列现有子网。在创建堆栈之前，必须先从您的账户指定适用的子网 ID。`LaunchConfigurationName` 属性引用具有在模板中定义的逻辑名称 `mySimpleConfig` 的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-launchconfiguration.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-launchconfiguration.html) 资源。

#### JSON
<a name="quickref-launch-config-example-2.json"></a>

```
1. "myASG" : {
2.    "Type" : "AWS::AutoScaling::AutoScalingGroup",
3.    "Properties" : {
4.       "VPCZoneIdentifier" : [ "subnetIdAz1", "subnetIdAz2", "subnetIdAz3" ],
5.       "LaunchConfigurationName" : { "Ref" : "mySimpleConfig" },
6.       "MaxSize" : "1",
7.       "MinSize" : "1"
8.    }
9. }
```

#### YAML
<a name="quickref-launch-config-example-2.yaml"></a>

```
 1. myASG:
 2.   Type: AWS::AutoScaling::AutoScalingGroup
 3.   Properties:
 4.     VPCZoneIdentifier:
 5.       - subnetIdAz1
 6.       - subnetIdAz2
 7.       - subnetIdAz3
 8.     LaunchConfigurationName: !Ref mySimpleConfig
 9.     MaxSize: '1'
10.     MinSize: '1'
```

# 使用 Amazon CloudFormation 配置 Application Auto Scaling 资源
<a name="quickref-application-auto-scaling"></a>

本节为不同 Amazon 资源的 Application Auto Scaling 扩展策略和计划操作提供了 Amazon CloudFormation 模板示例。

**重要**  
当模板中包含 Application Auto Scaling 代码段时，您可能需要使用 `DependsOn` 属性声明对通过模板创建的特定可扩展资源的依赖关系。这将覆盖默认并行度，并指示 Amazon CloudFormation 按指定的顺序对资源进行操作。否则，可能会在完全设置资源之前应用扩展配置。  
有关更多信息，请参阅 [DependsOn 属性](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-attribute-dependson.html)。

**Topics**
+ [

## 创建 AppStream 实例集的扩缩策略
](#w2aac11c41c15c19b9)
+ [

## 为 Aurora 数据库集群创建扩缩策略
](#w2aac11c41c15c19c11)
+ [

## 创建 DynamoDB 表的扩缩策略
](#w2aac11c41c15c19c13)
+ [

## 创建 Amazon ECS 服务的扩缩策略（指标：平均 CPU 和内存）
](#w2aac11c41c15c19c15)
+ [

## 创建 Amazon ECS 服务的扩缩策略（指标：每个目标的平均请求数）
](#w2aac11c41c15c19c17)
+ [

## 使用 Lambda 函数的 cron 表达式创建计划操作
](#w2aac11c41c15c19c19)
+ [

## 使用竞价型实例集的 `at` 表达式创建计划操作
](#w2aac11c41c15c19c21)

## 创建 AppStream 实例集的扩缩策略
<a name="w2aac11c41c15c19b9"></a>

此代码段说明如何创建策略并将其应用于使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalingpolicy.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalingpolicy.html) 资源的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-appstream-fleet.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-appstream-fleet.html) 资源。[https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalabletarget.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalabletarget.html) 资源声明一个应用此策略的可扩展目标。Application Auto Scaling 可以扩展队列实例数，最少为 1 个实例，最多为 20 个实例。该策略将实例集的平均容量利用率保持在 75%，横向扩展和横向缩减冷却时间为 300 秒（5 分钟）。

此示例利用 `Fn::Join` 和 `Rev` 内置函数，使用在同一模板中指定的 `AWS::AppStream::Fleet` 资源的逻辑名称来构造 `ResourceId` 属性。有关更多信息，请参阅[内置函数参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference.html)。

### JSON
<a name="quickref-autoscaling-example-6.json"></a>

```
{
  "Resources" : {
    "ScalableTarget" : {
      "Type" : "AWS::ApplicationAutoScaling::ScalableTarget",
      "Properties" : {
        "MaxCapacity" : 20,
        "MinCapacity" : 1,
        "RoleARN" : { "Fn::Sub" : "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/appstream.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_AppStreamFleet" },
        "ServiceNamespace" : "appstream",
        "ScalableDimension" : "appstream:fleet:DesiredCapacity",
        "ResourceId" : {
          "Fn::Join" : [
            "/",
            [
              "fleet",
              {
                "Ref" : "logicalName"
              }
            ]
          ]
        }
      }
    },
    "ScalingPolicyAppStreamFleet" : {
      "Type" : "AWS::ApplicationAutoScaling::ScalingPolicy",
      "Properties" : {
        "PolicyName" : { "Fn::Sub" : "${AWS::StackName}-target-tracking-cpu75" },
        "PolicyType" : "TargetTrackingScaling",
        "ServiceNamespace" : "appstream",
        "ScalableDimension" : "appstream:fleet:DesiredCapacity",
        "ResourceId" : {
          "Fn::Join" : [
            "/",
            [
              "fleet",
              {
                "Ref" : "logicalName"
              }
            ]
          ]
        },
        "TargetTrackingScalingPolicyConfiguration" : {
          "TargetValue" : 75,
          "PredefinedMetricSpecification" : {
            "PredefinedMetricType" : "AppStreamAverageCapacityUtilization"
          },
          "ScaleInCooldown" : 300,
          "ScaleOutCooldown" : 300
        }
      }
    } 
  }
}
```

### YAML
<a name="quickref-autoscaling-example-6.yaml"></a>

```
---
Resources:
  ScalableTarget:
    Type: AWS::ApplicationAutoScaling::ScalableTarget
    Properties:
      MaxCapacity: 20
      MinCapacity: 1
      RoleARN: 
        Fn::Sub: 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/appstream.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_AppStreamFleet'
      ServiceNamespace: appstream
      ScalableDimension: appstream:fleet:DesiredCapacity
      ResourceId: !Join
        - /
        - - fleet
          - !Ref logicalName
  ScalingPolicyAppStreamFleet:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    Properties:
      PolicyName: !Sub ${AWS::StackName}-target-tracking-cpu75
      PolicyType: TargetTrackingScaling
      ServiceNamespace: appstream
      ScalableDimension: appstream:fleet:DesiredCapacity
      ResourceId: !Join
        - /
        - - fleet
          - !Ref logicalName
      TargetTrackingScalingPolicyConfiguration:
        TargetValue: 75
        PredefinedMetricSpecification:
          PredefinedMetricType: AppStreamAverageCapacityUtilization
        ScaleInCooldown: 300
        ScaleOutCooldown: 300
```

## 为 Aurora 数据库集群创建扩缩策略
<a name="w2aac11c41c15c19c11"></a>

在此代码段中，您注册了 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbcluster.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbcluster.html) 资源。[https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalabletarget.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalabletarget.html) 资源表示应动态扩展数据库集群以具有 1-8 个 Aurora 副本。您还可以使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalingpolicy.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalingpolicy.html) 资源将目标跟踪扩缩策略应用到集群。

在此配置中，`RDSReaderAverageCPUUtilization` 预定义指标用于根据 Aurora 数据库集群中所有 Aurora 副本上 40% 的平均 CPU 利用率来调整该 Aurora 数据库集群。该配置将缩减冷却时间指定为 10 分钟，并将扩展冷却时间指定为 5 分钟。

此示例利用 `Fn::Sub` 内置函数，使用在同一模板中指定的 `AWS::RDS::DBCluster` 资源的逻辑名称来构造 `ResourceId` 属性。有关更多信息，请参阅[内置函数参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference.html)。

### JSON
<a name="quickref-autoscaling-example-7.json"></a>

```
{
  "Resources" : {
    "ScalableTarget" : {
      "Type" : "AWS::ApplicationAutoScaling::ScalableTarget",
      "Properties" : {
        "MaxCapacity" : 8,
        "MinCapacity" : 1,
        "RoleARN" : { "Fn::Sub" : "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/rds.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_RDSCluster" },
        "ServiceNamespace" : "rds",
        "ScalableDimension" : "rds:cluster:ReadReplicaCount",
        "ResourceId" : { "Fn::Sub" : "cluster:${logicalName}" }
      }
    },
    "ScalingPolicyDBCluster" : {
      "Type" : "AWS::ApplicationAutoScaling::ScalingPolicy",
      "Properties" : {
        "PolicyName" : { "Fn::Sub" : "${AWS::StackName}-target-tracking-cpu40" },
        "PolicyType" : "TargetTrackingScaling",
        "ServiceNamespace" : "rds",
        "ScalableDimension" : "rds:cluster:ReadReplicaCount",
        "ResourceId" : { "Fn::Sub" : "cluster:${logicalName}" }, 
        "TargetTrackingScalingPolicyConfiguration" : {
          "TargetValue" : 40,
          "PredefinedMetricSpecification" : {
            "PredefinedMetricType" : "RDSReaderAverageCPUUtilization"
          },
          "ScaleInCooldown" : 600,
          "ScaleOutCooldown" : 300
        }
      }
    }
  }
}
```

### YAML
<a name="quickref-autoscaling-example-7.yaml"></a>

```
---
Resources:
  ScalableTarget:
    Type: AWS::ApplicationAutoScaling::ScalableTarget
    Properties:
      MaxCapacity: 8
      MinCapacity: 1
      RoleARN: 
        Fn::Sub: 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/rds.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_RDSCluster'
      ServiceNamespace: rds
      ScalableDimension: rds:cluster:ReadReplicaCount
      ResourceId: !Sub cluster:${logicalName}
  ScalingPolicyDBCluster:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    Properties:
      PolicyName: !Sub ${AWS::StackName}-target-tracking-cpu40
      PolicyType: TargetTrackingScaling
      ServiceNamespace: rds
      ScalableDimension: rds:cluster:ReadReplicaCount
      ResourceId: !Sub cluster:${logicalName}
      TargetTrackingScalingPolicyConfiguration:
        TargetValue: 40
        PredefinedMetricSpecification:
          PredefinedMetricType: RDSReaderAverageCPUUtilization
        ScaleInCooldown: 600
        ScaleOutCooldown: 300
```

## 创建 DynamoDB 表的扩缩策略
<a name="w2aac11c41c15c19c13"></a>

此代码段说明如何使用 `TargetTrackingScaling` 策略类型创建策略并将其应用于使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalingpolicy.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalingpolicy.html) 资源的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-dynamodb-table.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-dynamodb-table.html) 资源。[https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalabletarget.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalabletarget.html) 资源声明一个应用此策略的可扩展目标，其最小写入容量单位为 5，最大写入容量单位为 15。扩展策略会扩展表的写入容量吞吐量，以 `DynamoDBWriteCapacityUtilization` 预定义指标将目标利用率维持在 50%。

此示例利用 `Fn::Join` 和 `Ref` 内置函数，使用在同一模板中指定的 `AWS::DynamoDB::Table` 资源的逻辑名称来构造 `ResourceId` 属性。有关更多信息，请参阅[内置函数参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference.html)。

**注意**  
有关如何为 DynamoDB 资源创建 Amazon CloudFormation 模板的更多信息，请参阅 Amazon 数据库博客上的博客文章[如何使用 Amazon CloudFormation 配置 Amazon DynamoDB 表和索引的自动伸缩](https://www.amazonaws.cn/blogs/database/how-to-use-aws-cloudformation-to-configure-auto-scaling-for-amazon-dynamodb-tables-and-indexes/)。

### JSON
<a name="quickref-autoscaling-example-8.json"></a>

```
{
  "Resources" : {
    "WriteCapacityScalableTarget" : {
      "Type" : "AWS::ApplicationAutoScaling::ScalableTarget",
      "Properties" : {
        "MaxCapacity" : 15,
        "MinCapacity" : 5,
        "RoleARN" : { "Fn::Sub" : "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable" },
        "ServiceNamespace" : "dynamodb",
        "ScalableDimension" : "dynamodb:table:WriteCapacityUnits",
        "ResourceId" : {
          "Fn::Join" : [
            "/",
            [
              "table",
              {
                "Ref" : "logicalName"
              }
            ]
          ]
        }
      }
    },
    "WriteScalingPolicy" : {
      "Type" : "AWS::ApplicationAutoScaling::ScalingPolicy",
      "Properties" : {
        "PolicyName" : "WriteScalingPolicy",
        "PolicyType" : "TargetTrackingScaling",
        "ScalingTargetId" : { "Ref" : "WriteCapacityScalableTarget" },
        "TargetTrackingScalingPolicyConfiguration" : {
          "TargetValue" : 50.0,
          "ScaleInCooldown" : 60,
          "ScaleOutCooldown" : 60,
          "PredefinedMetricSpecification" : {
            "PredefinedMetricType" : "DynamoDBWriteCapacityUtilization"
          }
        }
      }
    }
  }
}
```

### YAML
<a name="quickref-autoscaling-example-8.yaml"></a>

```
---
Resources:
  WriteCapacityScalableTarget:
    Type: AWS::ApplicationAutoScaling::ScalableTarget
    Properties:
      MaxCapacity: 15
      MinCapacity: 5
      RoleARN: 
        Fn::Sub: 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable'
      ServiceNamespace: dynamodb
      ScalableDimension: dynamodb:table:WriteCapacityUnits
      ResourceId: !Join
        - /
        - - table
          - !Ref logicalName
  WriteScalingPolicy:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    Properties:
      PolicyName: WriteScalingPolicy
      PolicyType: TargetTrackingScaling
      ScalingTargetId: !Ref WriteCapacityScalableTarget
      TargetTrackingScalingPolicyConfiguration:
        TargetValue: 50.0
        ScaleInCooldown: 60
        ScaleOutCooldown: 60
        PredefinedMetricSpecification:
          PredefinedMetricType: DynamoDBWriteCapacityUtilization
```

## 创建 Amazon ECS 服务的扩缩策略（指标：平均 CPU 和内存）
<a name="w2aac11c41c15c19c15"></a>

此代码段说明如何创建策略并将其应用于使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalingpolicy.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalingpolicy.html) 资源的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-service.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-service.html) 资源。[https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalabletarget.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalabletarget.html) 资源声明一个应用此策略的可扩展目标。Application Auto Scaling 可扩展任务的数量，最少 1 个任务，最多 6 个任务。

此示例创建两个 `TargetTrackingScaling` 策略类型的扩展策略。这些策略用于根据服务的平均 CPU 和内存使用率扩展 ECS 服务。此示例利用 `Fn::Join` 和 `Ref` 内置函数，使用在同一模板中指定的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-cluster.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-cluster.html)（`myContainerCluster`）和 `AWS::ECS::Service`（`myService`）资源的逻辑名称来构造 `ResourceId` 属性。有关更多信息，请参阅[内置函数参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference.html)。

### JSON
<a name="quickref-autoscaling-example-9.json"></a>

```
{
  "Resources" : {
    "ECSScalableTarget" : {
      "Type" : "AWS::ApplicationAutoScaling::ScalableTarget",
      "Properties" : {
        "MaxCapacity" : "6",
        "MinCapacity" : "1",
        "RoleARN" : { "Fn::Sub" : "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService" },
        "ServiceNamespace" : "ecs",
        "ScalableDimension" : "ecs:service:DesiredCount",
        "ResourceId" : {
          "Fn::Join" : [
            "/",
            [
              "service",
              {
                "Ref" : "myContainerCluster"
              },
              {
                "Fn::GetAtt" : [
                  "myService",
                  "Name"
                ]
              }
            ]
          ]
        }
      }
    },
    "ServiceScalingPolicyCPU" : {
      "Type" : "AWS::ApplicationAutoScaling::ScalingPolicy",
      "Properties" : {
        "PolicyName" : { "Fn::Sub" : "${AWS::StackName}-target-tracking-cpu70" },
        "PolicyType" : "TargetTrackingScaling",
        "ScalingTargetId" : { "Ref" : "ECSScalableTarget" },
        "TargetTrackingScalingPolicyConfiguration" : {
          "TargetValue" : 70.0,
          "ScaleInCooldown" : 180,
          "ScaleOutCooldown" : 60,
          "PredefinedMetricSpecification" : {
            "PredefinedMetricType" : "ECSServiceAverageCPUUtilization"
          }
        }
      }
    },
    "ServiceScalingPolicyMem" : {
      "Type" : "AWS::ApplicationAutoScaling::ScalingPolicy",
      "Properties" : {
        "PolicyName" : { "Fn::Sub" : "${AWS::StackName}-target-tracking-mem90" },
        "PolicyType" : "TargetTrackingScaling",
        "ScalingTargetId" : { "Ref" : "ECSScalableTarget" },
        "TargetTrackingScalingPolicyConfiguration" : {
          "TargetValue" : 90.0,
          "ScaleInCooldown" : 180,
          "ScaleOutCooldown" : 60,
          "PredefinedMetricSpecification" : {
            "PredefinedMetricType" : "ECSServiceAverageMemoryUtilization"
          }
        }
      }
    }
  }
}
```

### YAML
<a name="quickref-autoscaling-example-9.yaml"></a>

```
---
Resources:
  ECSScalableTarget:
    Type: AWS::ApplicationAutoScaling::ScalableTarget
    Properties:
      MaxCapacity: 6
      MinCapacity: 1  
      RoleARN: 
        Fn::Sub: 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService'
      ServiceNamespace: ecs
      ScalableDimension: 'ecs:service:DesiredCount'
      ResourceId: !Join 
        - /
        - - service
          - !Ref myContainerCluster
          - !GetAtt myService.Name
  ServiceScalingPolicyCPU:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    Properties:
      PolicyName: !Sub ${AWS::StackName}-target-tracking-cpu70
      PolicyType: TargetTrackingScaling
      ScalingTargetId: !Ref ECSScalableTarget
      TargetTrackingScalingPolicyConfiguration:
        TargetValue: 70.0
        ScaleInCooldown: 180
        ScaleOutCooldown: 60
        PredefinedMetricSpecification:
          PredefinedMetricType: ECSServiceAverageCPUUtilization
  ServiceScalingPolicyMem:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    Properties:
      PolicyName: !Sub ${AWS::StackName}-target-tracking-mem90
      PolicyType: TargetTrackingScaling
      ScalingTargetId: !Ref ECSScalableTarget
      TargetTrackingScalingPolicyConfiguration:
        TargetValue: 90.0
        ScaleInCooldown: 180
        ScaleOutCooldown: 60
        PredefinedMetricSpecification:
          PredefinedMetricType: ECSServiceAverageMemoryUtilization
```

## 创建 Amazon ECS 服务的扩缩策略（指标：每个目标的平均请求数）
<a name="w2aac11c41c15c19c17"></a>

以下示例将具有 `ALBRequestCountPerTarget` 预定义指标的目标跟踪扩展策略应用到 ECS 服务。该策略用于在每个目标的请求计数（每分钟）超过目标值时向 ECS 服务添加容量。由于 `DisableScaleIn` 的值设置为 `true`，因此，目标跟踪策略不会从可扩展目标中删除容量。

此示例利用 `Fn::Join` 和 `Fn::GetAtt` 内置函数，使用在同一模板中指定的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-loadbalancer.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-loadbalancer.html)（`myLoadBalancer`）和 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-targetgroup.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-targetgroup.html)（`myTargetGroup`）资源的逻辑名称来构造 `ResourceLabel` 属性。有关更多信息，请参阅[内置函数参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference.html)。

可扩展目标的 `MaxCapacity` 和 `MinCapacity` 属性以及扩展策略的 `TargetValue` 属性引用您在创建或更新堆栈时传递给模板的参数值。

### JSON
<a name="quickref-autoscaling-example-10.json"></a>

```
{
  "Resources" : {
    "ECSScalableTarget" : {
      "Type" : "AWS::ApplicationAutoScaling::ScalableTarget",
      "Properties" : {
        "MaxCapacity" : { "Ref" : "MaxCount" },
        "MinCapacity" : { "Ref" : "MinCount" },
        "RoleARN" : { "Fn::Sub" : "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService" },
        "ServiceNamespace" : "ecs",
        "ScalableDimension" : "ecs:service:DesiredCount",
        "ResourceId" : {
          "Fn::Join" : [
            "/",
            [
              "service",
              {
                "Ref" : "myContainerCluster"
              },
              {
                "Fn::GetAtt" : [
                  "myService",
                  "Name"
                ]
              }
            ]
          ]
        }
      }
    },
    "ServiceScalingPolicyALB" : {
      "Type" : "AWS::ApplicationAutoScaling::ScalingPolicy",
      "Properties" : {
        "PolicyName" : "alb-requests-per-target-per-minute",
        "PolicyType" : "TargetTrackingScaling",
        "ScalingTargetId" : { "Ref" : "ECSScalableTarget" },
        "TargetTrackingScalingPolicyConfiguration" : {
          "TargetValue" : { "Ref" : "ALBPolicyTargetValue" },
          "ScaleInCooldown" : 180,
          "ScaleOutCooldown" : 30,
          "DisableScaleIn" : true,
          "PredefinedMetricSpecification" : {
            "PredefinedMetricType" : "ALBRequestCountPerTarget",
            "ResourceLabel" : {
              "Fn::Join" : [
                "/",
                [
                  {
                    "Fn::GetAtt" : [
                      "myLoadBalancer",
                      "LoadBalancerFullName"
                    ]
                  },
                  {
                    "Fn::GetAtt" : [
                      "myTargetGroup",
                      "TargetGroupFullName"
                    ]
                  }
                ]
              ]
            }
          }
        }
      }
    }
  }
}
```

### YAML
<a name="quickref-autoscaling-example-10.yaml"></a>

```
---
Resources:
  ECSScalableTarget:
    Type: AWS::ApplicationAutoScaling::ScalableTarget
    Properties:
      MaxCapacity: !Ref MaxCount
      MinCapacity: !Ref MinCount  
      RoleARN: 
        Fn::Sub: 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService'
      ServiceNamespace: ecs
      ScalableDimension: 'ecs:service:DesiredCount'
      ResourceId: !Join 
        - /
        - - service
          - !Ref myContainerCluster
          - !GetAtt myService.Name
  ServiceScalingPolicyALB:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    Properties:
      PolicyName: alb-requests-per-target-per-minute
      PolicyType: TargetTrackingScaling
      ScalingTargetId: !Ref ECSScalableTarget
      TargetTrackingScalingPolicyConfiguration:
        TargetValue: !Ref ALBPolicyTargetValue
        ScaleInCooldown: 180
        ScaleOutCooldown: 30
        DisableScaleIn: true
        PredefinedMetricSpecification:
          PredefinedMetricType: ALBRequestCountPerTarget
          ResourceLabel: !Join 
            - '/' 
            - - !GetAtt myLoadBalancer.LoadBalancerFullName
              - !GetAtt myTargetGroup.TargetGroupFullName
```

## 使用 Lambda 函数的 cron 表达式创建计划操作
<a name="w2aac11c41c15c19c19"></a>

此代码段使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalabletarget.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalabletarget.html) 资源注册名为 `BLUE` 的函数别名（[https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-alias.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-alias.html)）的预置并发。它还使用 cron 表达式创建具有重复计划的计划操作。定期计划的时区为 UTC。

它在 `RoleARN` 属性中使用 `Fn::Join` 和 `Ref` 内置函数以指定服务相关角色的 ARN。此示例利用 `Fn::Sub` 内置函数，使用在同一模板中指定的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html) 或 [https://docs.amazonaws.cn/serverless-application-model/latest/developerguide/sam-resource-function.html](https://docs.amazonaws.cn/serverless-application-model/latest/developerguide/sam-resource-function.html) 资源的逻辑名称来构造 `ResourceId` 属性。有关更多信息，请参阅[内置函数参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference.html)。

**注意**  
您无法在指向未发布版本（`$LATEST`）的别名上分配预置并发。  
有关如何为 Lambda 资源创建 Amazon CloudFormation 模板的更多信息，请参阅 Amazon 计算博客上的博客文章[计划 Amazon Lambda 预置并发性以实现重复使用峰值](https://www.amazonaws.cn/blogs/compute/scheduling-aws-lambda-provisioned-concurrency-for-recurring-peak-usage/)。

### JSON
<a name="quickref-autoscaling-example-11.json"></a>

```
{
  "ScalableTarget" : {
    "Type" : "AWS::ApplicationAutoScaling::ScalableTarget",
    "Properties" : {
      "MaxCapacity" : 250,
      "MinCapacity" : 0,
      "RoleARN" : {
        "Fn::Join" : [
          ":",
          [
            "arn:aws:iam:",
            {
              "Ref" : "AWS::AccountId"
            },
            "role/aws-service-role/lambda.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_LambdaConcurrency"
          ]
        ]
      },
      "ServiceNamespace" : "lambda",
      "ScalableDimension" : "lambda:function:ProvisionedConcurrency",
      "ResourceId" : { "Fn::Sub" : "function:${logicalName}:BLUE" },
      "ScheduledActions" : [
        {
          "ScalableTargetAction" : {
            "MinCapacity" : "250"
          },
          "ScheduledActionName" : "my-scale-out-scheduled-action",
          "Schedule" : "cron(0 18 * * ? *)",
          "EndTime" : "2022-12-31T12:00:00.000Z"
        }
      ]
    }
  }
}
```

### YAML
<a name="quickref-autoscaling-example-11.yaml"></a>

```
ScalableTarget:
  Type: AWS::ApplicationAutoScaling::ScalableTarget
  Properties:
    MaxCapacity: 250
    MinCapacity: 0
    RoleARN: !Join 
      - ':'
      - - 'arn:aws:iam:'
        - !Ref 'AWS::AccountId'
        - role/aws-service-role/lambda.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_LambdaConcurrency
    ServiceNamespace: lambda
    ScalableDimension: lambda:function:ProvisionedConcurrency
    ResourceId: !Sub function:${logicalName}:BLUE
    ScheduledActions:
      - ScalableTargetAction:
          MinCapacity: 250
        ScheduledActionName: my-scale-out-scheduled-action
        Schedule: 'cron(0 18 * * ? *)'
        EndTime: '2022-12-31T12:00:00.000Z'
```

## 使用竞价型实例集的 `at` 表达式创建计划操作
<a name="w2aac11c41c15c19c21"></a>

此代码段展示如何使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalabletarget.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-applicationautoscaling-scalabletarget.html) 资源创建两个仅对 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-spotfleet.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-spotfleet.html) 资源发生一次的计划操作。每个一次性计划操作的时区均为 UTC。

此示例利用 `Fn::Join` 和 `Ref` 内置函数，使用在同一模板中指定的 `AWS::EC2::SpotFleet` 资源的逻辑名称来构造 `ResourceId` 属性。有关更多信息，请参阅[内置函数参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference.html)。

**注意**  
竞价型实例集请求必须使用 `maintain` 作为请求类型。一次性请求或 Spot 型限制不支持自动扩展。

### JSON
<a name="quickref-autoscaling-example-12.json"></a>

```
{
  "Resources" : {
    "SpotFleetScalableTarget" : {
      "Type" : "AWS::ApplicationAutoScaling::ScalableTarget",
      "Properties" : {
        "MaxCapacity" : 0,
        "MinCapacity" : 0,
        "RoleARN" : { "Fn::Sub" : "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ec2.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_EC2SpotFleetRequest" },
        "ServiceNamespace" : "ec2",
        "ScalableDimension" : "ec2:spot-fleet-request:TargetCapacity",
        "ResourceId" : {
          "Fn::Join" : [
            "/",
            [
              "spot-fleet-request",
              {
                "Ref" : "logicalName"
              }
            ]
          ]
        },
        "ScheduledActions" : [
          {
            "ScalableTargetAction" : {
              "MaxCapacity" : "10",
              "MinCapacity" : "10"
            },
            "ScheduledActionName" : "my-scale-out-scheduled-action",
            "Schedule" : "at(2022-05-20T13:00:00)"
          },
          {
            "ScalableTargetAction" : {
              "MaxCapacity" : "0",
              "MinCapacity" : "0"
            },
            "ScheduledActionName" : "my-scale-in-scheduled-action",
            "Schedule" : "at(2022-05-20T21:00:00)"
          }
        ]
      }
    }
  }
}
```

### YAML
<a name="quickref-autoscaling-example-12.yaml"></a>

```
---
Resources:
  SpotFleetScalableTarget:
    Type: AWS::ApplicationAutoScaling::ScalableTarget
    Properties:
      MaxCapacity: 0
      MinCapacity: 0
      RoleARN: 
        Fn::Sub: 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ec2.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_EC2SpotFleetRequest'
      ServiceNamespace: ec2
      ScalableDimension: 'ec2:spot-fleet-request:TargetCapacity'
      ResourceId: !Join 
        - /
        - - spot-fleet-request
          - !Ref logicalName
      ScheduledActions:
        - ScalableTargetAction:
            MaxCapacity: 10
            MinCapacity: 10
          ScheduledActionName: my-scale-out-scheduled-action
          Schedule: 'at(2022-05-20T13:00:00)'
        - ScalableTargetAction:
            MaxCapacity: 0
            MinCapacity: 0
          ScheduledActionName: my-scale-in-scheduled-action
          Schedule: 'at(2022-05-20T21:00:00)'
```

# Amazon 账单控制台模板代码段
<a name="quickref-billingconductor"></a>

此示例创建一个包含 10% 全球加价定价规则的定价计划。此定价计划已附加到账单组。账单组还有两个自定义行项目，在账单组总成本的基础上收取 10 美元的费用和 10% 的费用。

## JSON
<a name="quickref-billingconductor-example-1.json"></a>

```
 1. {
 2.    "Parameters": {
 3.       "LinkedAccountIds": {
 4.          "Type": "ListNumber"
 5.       },
 6.       "PrimaryAccountId": {
 7.          "Type": "Number"
 8.       }
 9.    },
10.    "Resources": {
11.       "TestPricingRule": {
12.          "Type": "AWS::BillingConductor::PricingRule",
13.          "Properties": {
14.             "Name": "TestPricingRule",
15.             "Description": "Test pricing rule created through Cloudformation. Mark everything by 10%.",
16.             "Type": "MARKUP",
17.             "Scope": "GLOBAL",
18.             "ModifierPercentage": 10
19.          }
20.       },
21.       "TestPricingPlan": {
22.          "Type": "AWS::BillingConductor::PricingPlan",
23.          "Properties": {
24.             "Name": "TestPricingPlan",
25.             "Description": "Test pricing plan created through Cloudformation.",
26.             "PricingRuleArns": [
27.                {"Fn::GetAtt": ["TestPricingRule", "Arn"]}
28.             ]
29.          }
30.       },
31.       "TestBillingGroup": {
32.          "Type": "AWS::BillingConductor::BillingGroup",
33.          "Properties": {
34.             "Name": "TestBillingGroup",
35.             "Description": "Test billing group created through Cloudformation with 1 linked account. The linked account is also the primary account.",
36.             "PrimaryAccountId": {
37.                "Ref": "PrimaryAccountId"
38.             },
39.             "AccountGrouping": {
40.                "LinkedAccountIds": null
41.             },
42.             "ComputationPreference": {
43.                "PricingPlanArn": {
44.                  "Fn::GetAtt": ["TestPricingPlan", "Arn"]
45.                }
46.             }
47.          }
48.       },
49.       "TestFlatCustomLineItem": {
50.          "Type": "AWS::BillingConductor::CustomLineItem",
51.          "Properties": {
52.             "Name": "TestFlatCustomLineItem",
53.             "Description": "Test flat custom line item created through Cloudformation for a $10 charge.",
54.             "BillingGroupArn": {
55.               "Fn::GetAtt": ["TestBillingGroup", "Arn"]
56.             },
57.             "CustomLineItemChargeDetails": {
58.                "Flat": {
59.                   "ChargeValue": 10
60.                },
61.                "Type": "FEE"
62.             }
63.          }
64.       },
65.       "TestPercentageCustomLineItem": {
66.          "Type": "AWS::BillingConductor::CustomLineItem",
67.          "Properties": {
68.             "Name": "TestPercentageCustomLineItem",
69.             "Description": "Test percentage custom line item created through Cloudformation for a %10 additional charge on the overall total bill of the billing group.",
70.             "BillingGroupArn": {
71.               "Fn::GetAtt": ["TestBillingGroup", "Arn"]
72.             },
73.             "CustomLineItemChargeDetails": {
74.                "Percentage": {
75.                   "PercentageValue": 10,
76.                   "ChildAssociatedResources": [
77.                      {"Fn::GetAtt": ["TestBillingGroup", "Arn"]}
78.                   ]
79.                },
80.                "Type": "FEE"
81.             }
82.          }
83.       }
84.    }
85. }
```

## YAML
<a name="quickref-billingconductor-example-1.yaml"></a>

```
 1. Parameters:
 2.   LinkedAccountIds:
 3.     Type: ListNumber
 4.   PrimaryAccountId:
 5.     Type: Number
 6. Resources:
 7.   TestPricingRule:
 8.     Type: AWS::BillingConductor::PricingRule
 9.     Properties:
10.       Name: 'TestPricingRule'
11.       Description: 'Test pricing rule created through Cloudformation. Mark everything by 10%.'
12.       Type: 'MARKUP'
13.       Scope: 'GLOBAL'
14.       ModifierPercentage: 10
15.   TestPricingPlan:
16.     Type: AWS::BillingConductor::PricingPlan
17.     Properties:
18.       Name: 'TestPricingPlan'
19.       Description: 'Test pricing plan created through Cloudformation.'
20.       PricingRuleArns:
21.         - !GetAtt TestPricingRule.Arn
22.   TestBillingGroup:
23.     Type: AWS::BillingConductor::BillingGroup
24.     Properties:
25.       Name: 'TestBillingGroup'
26.       Description: 'Test billing group created through Cloudformation with 1 linked account. The linked account is also the primary account.'
27.       PrimaryAccountId: !Ref PrimaryAccountId
28.       AccountGrouping:
29.         LinkedAccountIds: !Ref LinkedAccountIds
30.       ComputationPreference:
31.         PricingPlanArn: !GetAtt TestPricingPlan.Arn
32.   TestFlatCustomLineItem:
33.     Type: AWS::BillingConductor::CustomLineItem
34.     Properties:
35.       Name: 'TestFlatCustomLineItem'
36.       Description: 'Test flat custom line item created through Cloudformation for a $10 charge.'
37.       BillingGroupArn: !GetAtt TestBillingGroup.Arn
38.       CustomLineItemChargeDetails:
39.         Flat:
40.           ChargeValue: 10
41.         Type: 'FEE'
42.   TestPercentageCustomLineItem:
43.     Type: AWS::BillingConductor::CustomLineItem
44.     Properties:
45.       Name: 'TestPercentageCustomLineItem'
46.       Description: 'Test percentage custom line item created through Cloudformation for a %10 additional charge on the overall total bill of the billing group.'
47.       BillingGroupArn: !GetAtt TestBillingGroup.Arn
48.       CustomLineItemChargeDetails:
49.         Percentage:
50.           PercentageValue: 10
51.           ChildAssociatedResources:
52.             - !GetAtt TestBillingGroup.Arn
53.         Type: 'FEE'
```

# Amazon CloudFormation 模板代码段
<a name="quickref-cloudformation"></a>

**Topics**
+ [

## 嵌套堆栈
](#w2aac11c41c23b5)
+ [

## 等待条件
](#w2aac11c41c23b7)

## 嵌套堆栈
<a name="w2aac11c41c23b5"></a>

### 在模板中嵌套堆栈
<a name="scenario-stack"></a>

此示例模板包含一个称为 `myStack` 的嵌套堆栈资源。在 Amazon CloudFormation 通过模板创建堆栈时，它创建 `myStack`，其模板是在 `TemplateURL` 属性中指定的。输出值 `StackRef` 返回 `myStack` 的堆栈 ID，值 `OutputFromNestedStack` 从 `myStack` 资源中返回输出值 `BucketName`。`Outputs.nestedstackoutputname` 是预留格式，用于指定嵌套堆栈的输出值，可以在包含模板的任意位置中使用该格式。

有关更多信息，请参阅 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-stack.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-stack.html)。

#### JSON
<a name="quickref-cloudformation-example-1.json"></a>

```
 1. {
 2.     "AWSTemplateFormatVersion" : "2010-09-09",
 3.     "Resources" : {
 4.         "myStack" : {
 5. 	       "Type" : "AWS::CloudFormation::Stack",
 6. 	       "Properties" : {
 7. 	        "TemplateURL" : "https://s3.amazonaws.com/cloudformation-templates-us-east-1/S3_Bucket.template",
 8.               "TimeoutInMinutes" : "60"
 9. 	       }
10.         }
11.     },
12.     "Outputs": {
13.        "StackRef": {"Value": { "Ref" : "myStack"}},
14.        "OutputFromNestedStack" : {
15.              "Value" : { "Fn::GetAtt" : [ "myStack", "Outputs.BucketName" ] }
16.        }
17.     }
18. }
```

#### YAML
<a name="quickref-cloudformation-example-1.yaml"></a>

```
 1. AWSTemplateFormatVersion: '2010-09-09'
 2. Resources:
 3.   myStack:
 4.     Type: AWS::CloudFormation::Stack
 5.     Properties:
 6.       TemplateURL: https://s3.amazonaws.com/cloudformation-templates-us-east-1/S3_Bucket.template
 7.       TimeoutInMinutes: '60'
 8. Outputs:
 9.   StackRef:
10.     Value: !Ref myStack
11.   OutputFromNestedStack:
12.     Value: !GetAtt myStack.Outputs.BucketName
```

### 使用输入参数在模板中嵌套堆栈
<a name="scenario-stack-parameters"></a>

此示例模板包含指定输入参数的堆栈资源。Amazon CloudFormation 通过该模板创建堆栈时，会将 `Parameters` 属性中声明的值对作为输入参数，供创建 `myStackWithParams` 堆栈的模板使用。在此示例中，已指定 `InstanceType` 和 `KeyName` 参数。

有关更多信息，请参阅 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-stack.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-stack.html)。

#### JSON
<a name="quickref-cloudformation-example-2.json"></a>

```
 1. {
 2.     "AWSTemplateFormatVersion" : "2010-09-09",
 3.     "Resources" : {
 4.         "myStackWithParams" : {
 5.   	       "Type" : "AWS::CloudFormation::Stack",
 6. 	       "Properties" : {
 7. 	           "TemplateURL" : "https://s3.amazonaws.com/cloudformation-templates-us-east-1/EC2ChooseAMI.template",
 8. 	           "Parameters" : {
 9. 	               "InstanceType" : "t2.micro",
10. 	               "KeyName" : "mykey"
11. 	           }
12.    	       }
13.         }
14.     }
15. }
```

#### YAML
<a name="quickref-cloudformation-example-2.yaml"></a>

```
1. AWSTemplateFormatVersion: '2010-09-09'
2. Resources:
3.   myStackWithParams:
4.     Type: AWS::CloudFormation::Stack
5.     Properties:
6.       TemplateURL: https://s3.amazonaws.com/cloudformation-templates-us-east-1/EC2ChooseAMI.template
7.       Parameters:
8.         InstanceType: t2.micro
9.         KeyName: mykey
```

## 等待条件
<a name="w2aac11c41c23b7"></a>

### 将等待条件用于 Amazon EC2 实例
<a name="scenario-waitcondition"></a>

**重要**  
对于 Amazon EC2 和 Auto Scaling 资源，我们建议您使用 CreationPolicy 属性而非等待条件。当实例创建过程成功完成后，将“CreationPolicy”属性添加到这些资源，并使用 cfn-signal 帮助程序脚本发送信号。

如果您无法使用创建策略，请查看以下示例模板，该模板声明了带等待条件的 Amazon EC2 实例。`myWaitCondition` 等待条件使用 `myWaitConditionHandle` 发出信号，使用 `DependsOn` 属性指定等待条件将在创建 Amazon EC2 实例资源后触发，并使用 `Timeout` 属性将等待条件的持续时间指定为 4500 秒。此外，向等待条件发出信号的预签名 URL 将通过 `Ec2Instance` 资源的 `UserData` 属性传输至 Amazon EC2 实例，以使运行在该 Amazon EC2 实例上的应用程序或脚本可以检索预签名 URL，并使用该 URL 向等待条件发出成功或失败信号。您需要使用 `cfn-signal`，或创建向等待条件发出信号的应用程序或脚本。输出值 `ApplicationData` 包含从等待条件信号中传回的数据。

有关更多信息，请参阅 [在 CloudFormation 模板中创建等待条件](using-cfn-waitcondition.md)。

#### JSON
<a name="quickref-cloudformation-example-3.json"></a>

```
 1. {
 2.     "AWSTemplateFormatVersion" : "2010-09-09",
 3.     "Mappings" : {
 4.         "RegionMap" : {
 5.             "us-east-1" : {
 6.                 "AMI" : "ami-0123456789abcdef0"
 7.             },
 8.             "us-west-1" : {
 9.                 "AMI" : "ami-0987654321fedcba0"
10.             },
11.             "eu-west-1" : {
12.                 "AMI" : "ami-0abcdef123456789a"
13.             },
14.             "ap-northeast-1" : {
15.                 "AMI" : "ami-0fedcba987654321b"
16.             },
17.             "ap-southeast-1" : {
18.                 "AMI" : "ami-0c1d2e3f4a5b6c7d8"
19.             }
20.         }
21.     },
22.     "Resources" : {
23.         "Ec2Instance" : {
24.             "Type" : "AWS::EC2::Instance",
25.             "Properties" : {
26.                 "UserData" : { "Fn::Base64" : {"Ref" : "myWaitHandle"}},
27.                 "ImageId" : { "Fn::FindInMap" : [ "RegionMap", { "Ref" : "AWS::Region" }, "AMI" ]}
28.             }
29.         },
30.         "myWaitHandle" : {
31.             "Type" : "AWS::CloudFormation::WaitConditionHandle",
32.             "Properties" : {
33.             }
34.         },
35.         "myWaitCondition" : {
36.             "Type" : "AWS::CloudFormation::WaitCondition",
37.             "DependsOn" : "Ec2Instance",
38.             "Properties" : {
39.                 "Handle" : { "Ref" : "myWaitHandle" },
40.                 "Timeout" : "4500"
41.             }
42.         }
43.     },
44.     "Outputs" : {
45.         "ApplicationData" : {
46.             "Value" : { "Fn::GetAtt" : [ "myWaitCondition", "Data" ]},
47.             "Description" : "The data passed back as part of signalling the WaitCondition."
48.         }
49.     }
50. }
```

#### YAML
<a name="quickref-cloudformation-example-3.yaml"></a>

```
 1. AWSTemplateFormatVersion: '2010-09-09'
 2. Mappings:
 3.   RegionMap:
 4.     us-east-1:
 5.       AMI: ami-0123456789abcdef0
 6.     us-west-1:
 7.       AMI: ami-0987654321fedcba0
 8.     eu-west-1:
 9.       AMI: ami-0abcdef123456789a
10.     ap-northeast-1:
11.       AMI: ami-0fedcba987654321b
12.     ap-southeast-1:
13.       AMI: ami-0c1d2e3f4a5b6c7d8
14. Resources:
15.   Ec2Instance:
16.     Type: AWS::EC2::Instance
17.     Properties:
18.       UserData:
19.         Fn::Base64: !Ref myWaitHandle
20.       ImageId:
21.         Fn::FindInMap:
22.         - RegionMap
23.         - Ref: AWS::Region
24.         - AMI
25.   myWaitHandle:
26.     Type: AWS::CloudFormation::WaitConditionHandle
27.     Properties: {}
28.   myWaitCondition:
29.     Type: AWS::CloudFormation::WaitCondition
30.     DependsOn: Ec2Instance
31.     Properties:
32.       Handle: !Ref myWaitHandle
33.       Timeout: '4500'
34. Outputs:
35.   ApplicationData:
36.     Value: !GetAtt myWaitCondition.Data
37.     Description: The data passed back as part of signalling the WaitCondition.
```

### 使用 cfn-signal 帮助程序脚本向等待条件发出信号
<a name="scenario-waitcondition-cfn-signal"></a>

此示例演示将成功信号发送到等待条件的 `cfn-signal` 命令行。您需要在 EC2 实例的 `UserData` 属性中定义命令行。

#### JSON
<a name="w2aac11c41c23b7b4b4"></a>

```
"UserData": {
  "Fn::Base64": {
    "Fn::Join": [
      "", 
      [
         "#!/bin/bash -xe\n",
         "/opt/aws/bin/cfn-signal --exit-code 0 '", 
         {
           "Ref": "myWaitHandle"
         },
         "'\n"
      ]   
    ]
  }
}
```

#### YAML
<a name="w2aac11c41c23b7b4b6"></a>

```
UserData:
  Fn::Base64: !Sub |
    #!/bin/bash -xe
    /opt/aws/bin/cfn-signal --exit-code 0 '${myWaitHandle}'
```

### 使用 Curl 向等待条件发出信号
<a name="scenario-waitcondition-curl"></a>

此示例显示将成功信号发送到等待条件的 Curl 命令行。

```
1. curl -T /tmp/a "https://cloudformation-waitcondition-test.s3.amazonaws.com/arn%3Aaws%3Acloudformation%3Aus-east-1%3A034017226601%3Astack%2Fstack-gosar-20110427004224-test-stack-with-WaitCondition--VEYW%2Fe498ce60-70a1-11e0-81a7-5081d0136786%2FmyWaitConditionHandle?Expires=1303976584&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Signature=ik1twT6hpS4cgNAw7wyOoRejVoo%3D"
```

其中文件 /tmp/a 包含以下 JSON 结构：

```
1. {
2.   "Status" : "SUCCESS",
3.   "Reason" : "Configuration Complete",
4.   "UniqueId" : "ID1234",
5.   "Data" : "Application has completed configuration."
6. }
```

此示例显示发送同一成功信号的 Curl 命令行，将 JSON 发送为命令行参数的情况除外。

```
1. curl -X PUT -H 'Content-Type:' --data-binary '{"Status" : "SUCCESS","Reason" : "Configuration Complete","UniqueId" : "ID1234","Data" : "Application has completed configuration."}' "https://cloudformation-waitcondition-test.s3.amazonaws.com/arn%3Aaws%3Acloudformation%3Aus-east-1%3A034017226601%3Astack%2Fstack-gosar-20110427004224-test-stack-with-WaitCondition--VEYW%2Fe498ce60-70a1-11e0-81a7-5081d0136786%2FmyWaitConditionHandle?Expires=1303976584&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Signature=ik1twT6hpS4cgNAw7wyOoRejVoo%3D"
```

# Amazon CloudFront 模板代码段
<a name="quickref-cloudfront"></a>

在 Amazon CloudFormation 中，可以将这些示例模板代码段用于 Amazon CloudFront 分发资源。有关更多信息，请参阅 [Amazon CloudFront resource type reference](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/AWS_CloudFront.html)。

**Topics**
+ [

## 具有 Amazon S3 源的 Amazon CloudFront 分布资源
](#scenario-cloudfront-s3origin)
+ [

## 带自定义源的 Amazon CloudFront 分配资源
](#scenario-cloudfront-customorigin)
+ [

## 具有多源支持的 Amazon CloudFront 分配
](#scenario-cloudfront-multiorigin)
+ [

## 以 Lambda 函数为源的 Amazon CloudFront 分发
](#scenario-cloudfront-lambda-origin)
+ [

## 另请参阅
](#w2aac11c41c27c15)

## 具有 Amazon S3 源的 Amazon CloudFront 分布资源
<a name="scenario-cloudfront-s3origin"></a>

以下示例模板显示使用 [S3Origin](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-cloudfront-distribution-s3originconfig.html) 的 Amazon CloudFront [分发](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudfront-distribution.html)和旧式来源访问身份（OAI）。有关改用来源访问控制（OAC）的信息，请参阅《Amazon CloudFront 开发人员指南**》中的[限制对 Amazon Simple Storage Service 源的访问](https://docs.amazonaws.cn/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html)。

### JSON
<a name="quickref-cloudfront-example-1.json"></a>

```
 1. {
 2.     "AWSTemplateFormatVersion" : "2010-09-09",
 3.     "Resources" : {
 4.         "myDistribution" : {
 5.             "Type" : "AWS::CloudFront::Distribution",
 6.             "Properties" : {
 7.                 "DistributionConfig" : {
 8.                     "Origins" : [ {
 9.                         "DomainName" : "amzn-s3-demo-bucket.s3.amazonaws.com",
10.                         "Id" : "myS3Origin",
11.                         "S3OriginConfig" : {
12.                             "OriginAccessIdentity" : "origin-access-identity/cloudfront/E127EXAMPLE51Z"
13.                         }
14.                     }],
15.                     "Enabled" : "true",
16.                     "Comment" : "Some comment",
17.                     "DefaultRootObject" : "index.html",
18.                     "Logging" : {
19.                         "IncludeCookies" : "false",
20.                         "Bucket" : "amzn-s3-demo-logging-bucket.s3.amazonaws.com",
21.                         "Prefix" : "myprefix"
22.                     },
23.                     "Aliases" : [ "mysite.example.com", "yoursite.example.com" ],
24.                     "DefaultCacheBehavior" : {
25.                         "AllowedMethods" : [ "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT" ],  
26.                         "TargetOriginId" : "myS3Origin",
27.                         "ForwardedValues" : {
28.                             "QueryString" : "false",
29.                             "Cookies" : { "Forward" : "none" }
30.                         },
31.                         "TrustedSigners" : [ "1234567890EX", "1234567891EX" ],
32.                         "ViewerProtocolPolicy" : "allow-all"
33.                     },
34.                    "PriceClass" : "PriceClass_200",
35.                    "Restrictions" : {
36.                        "GeoRestriction" : {
37.                            "RestrictionType" : "whitelist",
38.                            "Locations" : [ "AQ", "CV" ]
39.                        }
40.                    },
41.                    "ViewerCertificate" : { "CloudFrontDefaultCertificate" : "true" }  
42.                 }
43.             }
44.         }
45.     }
46. }
```

### YAML
<a name="quickref-cloudfront-example-1.yaml"></a>

```
 1. AWSTemplateFormatVersion: '2010-09-09'
 2. Resources:
 3.   myDistribution:
 4.     Type: AWS::CloudFront::Distribution
 5.     Properties:
 6.       DistributionConfig:
 7.         Origins:
 8.         - DomainName: amzn-s3-demo-bucket.s3.amazonaws.com
 9.           Id: myS3Origin
10.           S3OriginConfig:
11.             OriginAccessIdentity: origin-access-identity/cloudfront/E127EXAMPLE51Z
12.         Enabled: 'true'
13.         Comment: Some comment
14.         DefaultRootObject: index.html
15.         Logging:
16.           IncludeCookies: 'false'
17.           Bucket: amzn-s3-demo-logging-bucket.s3.amazonaws.com
18.           Prefix: myprefix
19.         Aliases:
20.         - mysite.example.com
21.         - yoursite.example.com
22.         DefaultCacheBehavior:
23.           AllowedMethods:
24.           - DELETE
25.           - GET
26.           - HEAD
27.           - OPTIONS
28.           - PATCH
29.           - POST
30.           - PUT
31.           TargetOriginId: myS3Origin
32.           ForwardedValues:
33.             QueryString: 'false'
34.             Cookies:
35.               Forward: none
36.           TrustedSigners:
37.           - 1234567890EX
38.           - 1234567891EX
39.           ViewerProtocolPolicy: allow-all
40.         PriceClass: PriceClass_200
41.         Restrictions:
42.           GeoRestriction:
43.             RestrictionType: whitelist
44.             Locations:
45.             - AQ
46.             - CV
47.         ViewerCertificate:
48.           CloudFrontDefaultCertificate: 'true'
```

## 带自定义源的 Amazon CloudFront 分配资源
<a name="scenario-cloudfront-customorigin"></a>

以下示例模板显示使用 [CustomOrigin](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-cloudfront-distribution-customoriginconfig.html) 的 Amazon CloudFront [分发](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudfront-distribution.html)。

### JSON
<a name="quickref-cloudfront-example-2.json"></a>

```
 1. {
 2.     "AWSTemplateFormatVersion" : "2010-09-09",
 3.     "Resources" : {
 4.         "myDistribution" : {
 5.             "Type" : "AWS::CloudFront::Distribution",
 6.             "Properties" : {
 7.                 "DistributionConfig" : {
 8.                     "Origins" : [ {
 9.                             "DomainName" : "www.example.com",
10.                             "Id" : "myCustomOrigin",
11.                             "CustomOriginConfig" : {
12.                                 "HTTPPort" : "80",
13.                                 "HTTPSPort" : "443",
14.                                 "OriginProtocolPolicy" : "http-only"
15.                             }
16.                     } ],
17.                     "Enabled" : "true",
18.                     "Comment" : "Somecomment",
19.                     "DefaultRootObject" : "index.html",
20.                     "Logging" : {
21.                         "IncludeCookies" : "true",
22.                         "Bucket" : "amzn-s3-demo-logging-bucket.s3.amazonaws.com",
23.                         "Prefix": "myprefix"
24.                     },
25.                     "Aliases" : [
26.                         "mysite.example.com",
27.                         "*.yoursite.example.com"
28.                     ],
29.                     "DefaultCacheBehavior" : {
30.                         "TargetOriginId" : "myCustomOrigin",
31.                         "SmoothStreaming" : "false",  
32.                         "ForwardedValues" : {
33.                             "QueryString" : "false",
34.                             "Cookies" : { "Forward" : "all" }
35.                         },
36.                         "TrustedSigners" : [
37.                             "1234567890EX",
38.                             "1234567891EX"
39.                         ],
40.                         "ViewerProtocolPolicy" : "allow-all"
41.                     },
42.                     "CustomErrorResponses" : [ {
43.                         "ErrorCode" : "404",
44.                         "ResponsePagePath" : "/error-pages/404.html",
45.                         "ResponseCode" : "200",
46.                         "ErrorCachingMinTTL" : "30"
47.                     } ],
48.                    "PriceClass" : "PriceClass_200",
49.                    "Restrictions" : {
50.                        "GeoRestriction" : {
51.                            "RestrictionType" : "whitelist",
52.                            "Locations" : [ "AQ", "CV" ]
53.                        }
54.                    },
55.                    "ViewerCertificate": { "CloudFrontDefaultCertificate" : "true" }
56.                 }
57.             }
58.         }
59.     }
60. }
```

### YAML
<a name="quickref-cloudfront-example-2.yaml"></a>

```
 1. AWSTemplateFormatVersion: '2010-09-09'
 2. Resources:
 3.   myDistribution:
 4.     Type: AWS::CloudFront::Distribution
 5.     Properties:
 6.       DistributionConfig:
 7.         Origins:
 8.         - DomainName: www.example.com
 9.           Id: myCustomOrigin
10.           CustomOriginConfig:
11.             HTTPPort: '80'
12.             HTTPSPort: '443'
13.             OriginProtocolPolicy: http-only
14.         Enabled: 'true'
15.         Comment: Somecomment
16.         DefaultRootObject: index.html
17.         Logging:
18.           IncludeCookies: 'true'
19.           Bucket: amzn-s3-demo-logging-bucket.s3.amazonaws.com
20.           Prefix: myprefix
21.         Aliases:
22.         - mysite.example.com
23.         - "*.yoursite.example.com"
24.         DefaultCacheBehavior:
25.           TargetOriginId: myCustomOrigin
26.           SmoothStreaming: 'false'
27.           ForwardedValues:
28.             QueryString: 'false'
29.             Cookies:
30.               Forward: all
31.           TrustedSigners:
32.           - 1234567890EX
33.           - 1234567891EX
34.           ViewerProtocolPolicy: allow-all
35.         CustomErrorResponses:
36.         - ErrorCode: '404'
37.           ResponsePagePath: "/error-pages/404.html"
38.           ResponseCode: '200'
39.           ErrorCachingMinTTL: '30'
40.         PriceClass: PriceClass_200
41.         Restrictions:
42.           GeoRestriction:
43.             RestrictionType: whitelist
44.             Locations:
45.             - AQ
46.             - CV
47.         ViewerCertificate:
48.           CloudFrontDefaultCertificate: 'true'
```

## 具有多源支持的 Amazon CloudFront 分配
<a name="scenario-cloudfront-multiorigin"></a>

以下示例模板演示如何声明带多源支持的 CloudFront [分配](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudfront-distribution.html)。在 [DistributionConfig](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-cloudfront-distribution-distributionconfig.html) 中，提供了源列表，并且设置了 [DefaultCacheBehavior](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-cloudfront-distribution-defaultcachebehavior.html)。

### JSON
<a name="quickref-cloudfront-example-3.json"></a>

```
{
    "AWSTemplateFormatVersion" : "2010-09-09",
    "Resources" : {
        "myDistribution" : {
            "Type" : "AWS::CloudFront::Distribution",
            "Properties" : {
                "DistributionConfig" : {
                    "Origins" : [ {
                        "Id" : "myS3Origin",
                        "DomainName" : "amzn-s3-demo-bucket.s3.amazonaws.com",
                        "S3OriginConfig" : {
                            "OriginAccessIdentity" : "origin-access-identity/cloudfront/E127EXAMPLE51Z"
                        }
                     }, 
                     {
                         "Id" : "myCustomOrigin",
                         "DomainName" : "www.example.com",
                         "CustomOriginConfig" : {
                             "HTTPPort" : "80",
                             "HTTPSPort" : "443",
                             "OriginProtocolPolicy" : "http-only"
                         }
                     }
                   ],
                   "Enabled" : "true",
                   "Comment" : "Some comment",
                   "DefaultRootObject" : "index.html", 
                   "Logging" : {
                       "IncludeCookies" : "true",
                       "Bucket" : "amzn-s3-demo-logging-bucket.s3.amazonaws.com",
                       "Prefix" : "myprefix"
                   },            
                   "Aliases" : [ "mysite.example.com", "yoursite.example.com" ],
                   "DefaultCacheBehavior" : {
                       "TargetOriginId" : "myS3Origin",
                       "ForwardedValues" : {
                           "QueryString" : "false",
                           "Cookies" : { "Forward" : "all" }
                        },
                       "TrustedSigners" : [ "1234567890EX", "1234567891EX"  ],
                       "ViewerProtocolPolicy" : "allow-all",
                       "MinTTL" : "100",
                       "SmoothStreaming" : "true"
                   },
                   "CacheBehaviors" : [ {
                            "AllowedMethods" : [ "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT" ],  
                            "TargetOriginId" : "myS3Origin",
                            "ForwardedValues" : {
                                "QueryString" : "true",
                                "Cookies" : { "Forward" : "none" }
                            },
                            "TrustedSigners" : [ "1234567890EX", "1234567891EX" ],
                            "ViewerProtocolPolicy" : "allow-all",
                            "MinTTL" : "50",
                            "PathPattern" : "images1/*.jpg"
                        }, 
                        {
                            "AllowedMethods" : [ "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT" ],  
                            "TargetOriginId" : "myCustomOrigin",
                            "ForwardedValues" : {
                                "QueryString" : "true",
                                "Cookies" : { "Forward" : "none" }
                            },
                            "TrustedSigners" : [ "1234567890EX", "1234567891EX"  ],
                            "ViewerProtocolPolicy" : "allow-all",
                            "MinTTL" : "50",
                            "PathPattern" : "images2/*.jpg"
                        }
                   ],
                   "CustomErrorResponses" : [ {
                       "ErrorCode" : "404",
                       "ResponsePagePath" : "/error-pages/404.html",
                       "ResponseCode" : "200",
                       "ErrorCachingMinTTL" : "30"
                   } ],
                   "PriceClass" : "PriceClass_All",
                   "ViewerCertificate" : { "CloudFrontDefaultCertificate" : "true" }
                }
            }
        }
    }
}
```

### YAML
<a name="quickref-cloudfront-example-3.yaml"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  myDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Origins:
        - Id: myS3Origin
          DomainName: amzn-s3-demo-bucket.s3.amazonaws.com
          S3OriginConfig:
            OriginAccessIdentity: origin-access-identity/cloudfront/E127EXAMPLE51Z
        - Id: myCustomOrigin
          DomainName: www.example.com
          CustomOriginConfig:
            HTTPPort: '80'
            HTTPSPort: '443'
            OriginProtocolPolicy: http-only
        Enabled: 'true'
        Comment: Some comment
        DefaultRootObject: index.html
        Logging:
          IncludeCookies: 'true'
          Bucket: amzn-s3-demo-logging-bucket.s3.amazonaws.com
          Prefix: myprefix
        Aliases:
        - mysite.example.com
        - yoursite.example.com
        DefaultCacheBehavior:
          TargetOriginId: myS3Origin
          ForwardedValues:
            QueryString: 'false'
            Cookies:
              Forward: all
          TrustedSigners:
          - 1234567890EX
          - 1234567891EX
          ViewerProtocolPolicy: allow-all
          MinTTL: '100'
          SmoothStreaming: 'true'
        CacheBehaviors:
        - AllowedMethods:
          - DELETE
          - GET
          - HEAD
          - OPTIONS
          - PATCH
          - POST
          - PUT
          TargetOriginId: myS3Origin
          ForwardedValues:
            QueryString: 'true'
            Cookies:
              Forward: none
          TrustedSigners:
          - 1234567890EX
          - 1234567891EX
          ViewerProtocolPolicy: allow-all
          MinTTL: '50'
          PathPattern: images1/*.jpg
        - AllowedMethods:
          - DELETE
          - GET
          - HEAD
          - OPTIONS
          - PATCH
          - POST
          - PUT
          TargetOriginId: myCustomOrigin
          ForwardedValues:
            QueryString: 'true'
            Cookies:
              Forward: none
          TrustedSigners:
          - 1234567890EX
          - 1234567891EX
          ViewerProtocolPolicy: allow-all
          MinTTL: '50'
          PathPattern: images2/*.jpg
        CustomErrorResponses:
        - ErrorCode: '404'
          ResponsePagePath: "/error-pages/404.html"
          ResponseCode: '200'
          ErrorCachingMinTTL: '30'
        PriceClass: PriceClass_All
        ViewerCertificate:
          CloudFrontDefaultCertificate: 'true'
```

## 以 Lambda 函数为源的 Amazon CloudFront 分发
<a name="scenario-cloudfront-lambda-origin"></a>

以下示例创建了一个前端为指定的 Lambda 函数 URL（作为参数提供）的 CloudFront 分发，启用了仅限 HTTPS 访问、缓存、压缩和全球交付。此示例将 Lambda URL 配置为自定义 HTTPS 来源，并且应用标准 Amazon 缓存策略。该分发针对性能进行了优化，支持 HTTP/2 和 IPv6，输出 CloudFront 域名，允许用户通过 CDN 支持的安全端点访问 Lambda 函数。有关更多信息，请参阅 Amazon 博客上的 [Using Amazon CloudFront with Amazon Lambda as origin to accelerate your web applications](https://www.amazonaws.cn/blogs/networking-and-content-delivery/using-amazon-cloudfront-with-aws-lambda-as-origin-to-accelerate-your-web-applications/)。

### JSON
<a name="quickref-cloudfront-example-lambda-origin.json"></a>

```
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Parameters": {
        "LambdaEndpoint": {
            "Type": "String",
            "Description": "The Lambda function URL endpoint without the 'https://'"
        }
    },
    "Resources": {
        "MyDistribution": {
            "Type": "AWS::CloudFront::Distribution",
            "Properties": {
                "DistributionConfig": {
                    "PriceClass": "PriceClass_All",
                    "HttpVersion": "http2",
                    "IPV6Enabled": true,
                    "Origins": [
                        {
                            "DomainName": {
                                "Ref": "LambdaEndpoint"
                            },
                            "Id": "LambdaOrigin",
                            "CustomOriginConfig": {
                                "HTTPSPort": 443,
                                "OriginProtocolPolicy": "https-only"
                            }
                        }
                    ],
                    "Enabled": "true",
                    "DefaultCacheBehavior": {
                        "TargetOriginId": "LambdaOrigin",
                        "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6",
                        "ViewerProtocolPolicy": "redirect-to-https",
                        "SmoothStreaming": "false",
                        "Compress": "true"
                    }
                }
            }
        }
    },
    "Outputs": {
        "CloudFrontDomain": {
            "Description": "CloudFront default domain name configured",
            "Value": {
                "Fn::Sub": "https://${MyDistribution.DomainName}/"
            }
        }
    }
}
```

### YAML
<a name="quickref-cloudfront-example-lambda-origin.yaml"></a>

```
AWSTemplateFormatVersion: 2010-09-09
Parameters:
  LambdaEndpoint:
    Type: String
    Description: The Lambda function URL endpoint without the 'https://'
Resources:
  MyDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        PriceClass: PriceClass_All
        HttpVersion: http2
        IPV6Enabled: true
        Origins:
        - DomainName: !Ref LambdaEndpoint
          Id: LambdaOrigin
          CustomOriginConfig:
            HTTPSPort: 443
            OriginProtocolPolicy: https-only
        Enabled: 'true'
        DefaultCacheBehavior:
          TargetOriginId: LambdaOrigin
          CachePolicyId: '658327ea-f89d-4fab-a63d-7e88639e58f6'
          ViewerProtocolPolicy: redirect-to-https
          SmoothStreaming: 'false'
          Compress: 'true'
Outputs:
  CloudFrontDomain:
    Description: CloudFront default domain name configured
    Value: !Sub https://${MyDistribution.DomainName}/
```

## 另请参阅
<a name="w2aac11c41c27c15"></a>

有关向 Route 53 记录添加自定义别名以便更好地为 CloudFront 分发命名的示例，请参阅 [CloudFront 分配的别名资源记录集](quickref-route53.md#scenario-user-friendly-url-for-cloudfront-distribution)。

# Amazon CloudWatch 模板代码段
<a name="quickref-cloudwatch"></a>

您可以在 Amazon CloudFormation 中使用这些示例模板代码段来帮助描述 Amazon CloudWatch 资源。有关更多信息，请参阅 [Amazon CloudWatch resource type reference](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/AWS_CloudWatch.html)。

**Topics**
+ [

## 账单警报
](#cloudwatch-sample-billing-alarm)
+ [

## CPU 使用率警报
](#cloudwatch-sample-cpu-utilization-alarm)
+ [

## 恢复 Amazon Elastic Compute Cloud 实例
](#cloudwatch-sample-recover-instance)
+ [

## 创建基本控制面板
](#cloudwatch-sample-dashboard-basic)
+ [

## 使用并排显示小部件创建控制面板
](#cloudwatch-sample-dashboard-sidebyside)

## 账单警报
<a name="cloudwatch-sample-billing-alarm"></a>

在下面的示例中，Amazon CloudWatch 在您的 Amazon 账户费用超过警报阈值时发送电子邮件通知。要接收使用情况通知，请启用账单提醒。有关更多信息，请参阅《Amazon CloudWatch 用户指南》中的[创建账单警报以监控预估 Amazon 费用](https://docs.amazonaws.cn/AmazonCloudWatch/latest/monitoring/monitor_estimated_charges_with_cloudwatch.html)**。

### JSON
<a name="quickref-cloudwatch-example-1.json"></a>

```
"SpendingAlarm": {
  "Type": "AWS::CloudWatch::Alarm",
  "Properties": {
    "AlarmDescription": { "Fn::Join": ["", [
      "Alarm if AWS spending is over $",
      { "Ref": "AlarmThreshold" }
    ]]},
    "Namespace": "AWS/Billing",
    "MetricName": "EstimatedCharges",
    "Dimensions": [{
      "Name": "Currency",
      "Value" : "USD"
    }],
    "Statistic": "Maximum",
    "Period": "21600",
    "EvaluationPeriods": "1",
    "Threshold": { "Ref": "AlarmThreshold" },
    "ComparisonOperator": "GreaterThanThreshold",
    "AlarmActions": [{
      "Ref": "BillingAlarmNotification"
    }],
    "InsufficientDataActions": [{
      "Ref": "BillingAlarmNotification"
    }]
  }
}
```

### YAML
<a name="quickref-cloudwatch-example-1.yaml"></a>

```
SpendingAlarm:
  Type: AWS::CloudWatch::Alarm
  Properties:
    AlarmDescription: 
      'Fn::Join':
        - ''
        - - Alarm if AWS spending is over $
          - !Ref: AlarmThreshold
    Namespace: AWS/Billing
    MetricName: EstimatedCharges
    Dimensions:
    - Name: Currency
      Value: USD
    Statistic: Maximum
    Period: '21600'
    EvaluationPeriods: '1'
    Threshold:
      !Ref: "AlarmThreshold"
    ComparisonOperator: GreaterThanThreshold
    AlarmActions:
    - !Ref: "BillingAlarmNotification"
    InsufficientDataActions:
    - !Ref: "BillingAlarmNotification"
```

## CPU 使用率警报
<a name="cloudwatch-sample-cpu-utilization-alarm"></a>

以下示例代码段创建一个警报，该警报在三个评估周期内 Amazon EC2 实例的平均 CPU 利用率超出 90% 的时间大于 60 秒时发送通知。

### JSON
<a name="quickref-cloudwatch-example-2.json"></a>

```
 1. "CPUAlarm" : {
 2.   "Type" : "AWS::CloudWatch::Alarm",
 3.   "Properties" : {
 4.     "AlarmDescription" : "CPU alarm for my instance",
 5.     "AlarmActions" : [ { "Ref" : "logical name of an AWS::SNS::Topic resource" } ],
 6.     "MetricName" : "CPUUtilization",
 7.     "Namespace" : "AWS/EC2",
 8.     "Statistic" : "Average",
 9.     "Period" : "60",
10.     "EvaluationPeriods" : "3",
11.     "Threshold" : "90",
12.     "ComparisonOperator" : "GreaterThanThreshold",
13.     "Dimensions" : [ {
14.       "Name" : "InstanceId",
15.       "Value" : { "Ref" : "logical name of an AWS::EC2::Instance resource" }
16.     } ]
17.   }
18. }
```

### YAML
<a name="quickref-cloudwatch-example-2.yaml"></a>

```
 1. CPUAlarm:
 2.   Type: AWS::CloudWatch::Alarm
 3.   Properties:
 4.     AlarmDescription: CPU alarm for my instance
 5.     AlarmActions:
 6.     - !Ref: "logical name of an AWS::SNS::Topic resource"
 7.     MetricName: CPUUtilization
 8.     Namespace: AWS/EC2
 9.     Statistic: Average
10.     Period: '60'
11.     EvaluationPeriods: '3'
12.     Threshold: '90'
13.     ComparisonOperator: GreaterThanThreshold
14.     Dimensions:
15.     - Name: InstanceId
16.       Value: !Ref: "logical name of an AWS::EC2::Instance resource"
```

## 恢复 Amazon Elastic Compute Cloud 实例
<a name="cloudwatch-sample-recover-instance"></a>

当以下 CloudWatch 警报在连续的 15 分钟时间内存在状态检查故障时，它将恢复 EC2 实例。有关警报操作的更多信息，请参阅《Amazon CloudWatch 用户指南》中的[创建警报以停止、终止、重启或恢复 EC2 实例](https://docs.amazonaws.cn/AmazonCloudWatch/latest/monitoring/UsingAlarmActions.html)**。

### JSON
<a name="quickref-cloudwatch-example-3.json"></a>

```
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Parameters" : {
    "RecoveryInstance" : {
      "Description" : "The EC2 instance ID to associate this alarm with.",
      "Type" : "AWS::EC2::Instance::Id"
    }
  },
  "Resources": {
    "RecoveryTestAlarm": {
      "Type": "AWS::CloudWatch::Alarm",
      "Properties": {
        "AlarmDescription": "Trigger a recovery when instance status check fails for 15 consecutive minutes.",
        "Namespace": "AWS/EC2" ,
        "MetricName": "StatusCheckFailed_System",
        "Statistic": "Minimum",
        "Period": "60",
        "EvaluationPeriods": "15",
        "ComparisonOperator": "GreaterThanThreshold",
        "Threshold": "0",
        "AlarmActions": [ {"Fn::Join" : ["", ["arn:aws:automate:", { "Ref" : "AWS::Region" }, ":ec2:recover" ]]} ],
        "Dimensions": [{"Name": "InstanceId","Value": {"Ref": "RecoveryInstance"}}]
      }
    }
  }
}
```

### YAML
<a name="quickref-cloudwatch-example-3.yaml"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  RecoveryInstance:
    Description: The EC2 instance ID to associate this alarm with.
    Type: AWS::EC2::Instance::Id
Resources:
  RecoveryTestAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmDescription: Trigger a recovery when instance status check fails for 15
        consecutive minutes.
      Namespace: AWS/EC2
      MetricName: StatusCheckFailed_System
      Statistic: Minimum
      Period: '60'
      EvaluationPeriods: '15'
      ComparisonOperator: GreaterThanThreshold
      Threshold: '0'
      AlarmActions: [ !Sub "arn:aws:automate:${AWS::Region}:ec2:recover" ]
      Dimensions:
      - Name: InstanceId
        Value: !Ref: RecoveryInstance
```

## 创建基本控制面板
<a name="cloudwatch-sample-dashboard-basic"></a>

以下示例创建一个简单的 CloudWatch 控制面板，其中包含一个显示 CPU 使用率的指标小部件和一个显示消息的文本小部件。

### JSON
<a name="quickref-cloudwatch-sample-dashboard-basic.json"></a>

```
{
    "BasicDashboard": {
        "Type": "AWS::CloudWatch::Dashboard",
        "Properties": {
            "DashboardName": "Dashboard1",
            "DashboardBody": "{\"widgets\":[{\"type\":\"metric\",\"x\":0,\"y\":0,\"width\":12,\"height\":6,\"properties\":{\"metrics\":[[\"AWS/EC2\",\"CPUUtilization\",\"InstanceId\",\"i-012345\"]],\"period\":300,\"stat\":\"Average\",\"region\":\"us-east-1\",\"title\":\"EC2 Instance CPU\"}},{\"type\":\"text\",\"x\":0,\"y\":7,\"width\":3,\"height\":3,\"properties\":{\"markdown\":\"Hello world\"}}]}"
        }
    }
}
```

### YAML
<a name="quickref-cloudwatch-sample-dashboard-basic.yaml"></a>

```
BasicDashboard:
  Type: AWS::CloudWatch::Dashboard
  Properties:
    DashboardName: Dashboard1
    DashboardBody: '{"widgets":[{"type":"metric","x":0,"y":0,"width":12,"height":6,"properties":{"metrics":[["AWS/EC2","CPUUtilization","InstanceId","i-012345"]],"period":300,"stat":"Average","region":"us-east-1","title":"EC2 Instance CPU"}},{"type":"text","x":0,"y":7,"width":3,"height":3,"properties":{"markdown":"Hello world"}}]}'
```

## 使用并排显示小部件创建控制面板
<a name="cloudwatch-sample-dashboard-sidebyside"></a>

以下示例创建一个包含两个指标小部件 (并排显示) 的控制面板。

### JSON
<a name="quickref-cloudwatch-sample-dashboard-sidebyside.json"></a>

```
{
    "DashboardSideBySide": {
        "Type": "AWS::CloudWatch::Dashboard",
        "Properties": {
            "DashboardName": "Dashboard1",
            "DashboardBody": "{\"widgets\":[{\"type\":\"metric\",\"x\":0,\"y\":0,\"width\":12,\"height\":6,\"properties\":{\"metrics\":[[\"AWS/EC2\",\"CPUUtilization\",\"InstanceId\",\"i-012345\"]],\"period\":300,\"stat\":\"Average\",\"region\":\"us-east-1\",\"title\":\"EC2 Instance CPU\"}},{\"type\":\"metric\",\"x\":12,\"y\":0,\"width\":12,\"height\":6,\"properties\":{\"metrics\":[[\"AWS/S3\",\"BucketSizeBytes\",\"BucketName\",\"amzn-s3-demo-bucket\"]],\"period\":86400,\"stat\":\"Maximum\",\"region\":\"us-east-1\",\"title\":\"amzn-s3-demo-bucket bytes\"}}]}"
        }
    }
}
```

### YAML
<a name="quickref-cloudwatch-sample-dashboard-sidebysidequickref-cloudwatch-sample-dashboard-sidebyside.yaml"></a>

```
DashboardSideBySide:
  Type: AWS::CloudWatch::Dashboard
  Properties:
    DashboardName: Dashboard1
    DashboardBody: '{"widgets":[{"type":"metric","x":0,"y":0,"width":12,"height":6,"properties":{"metrics":[["AWS/EC2","CPUUtilization","InstanceId","i-012345"]],"period":300,"stat":"Average","region":"us-east-1","title":"EC2 Instance CPU"}},{"type":"metric","x":12,"y":0,"width":12,"height":6,"properties":{"metrics":[["AWS/S3","BucketSizeBytes","BucketName","amzn-s3-demo-bucket"]],"period":86400,"stat":"Maximum","region":"us-east-1","title":"amzn-s3-demo-bucket bytes"}}]}'
```

# Amazon CloudWatch Logs 模板代码段
<a name="quickref-cloudwatchlogs"></a>

Amazon CloudWatch Logs 能够监控系统、应用程序和来自 Amazon EC2 实例或其他源的自定义日志文件。您可以使用 Amazon CloudFormation 配置和管理日志组和指标筛选条件。有关 Amazon CloudWatch Logs 的更多信息，请参阅 [Amazon CloudWatch Logs 用户指南](https://docs.amazonaws.cn/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html)。

**Topics**
+ [

## 从 Linux 实例将日志发送到 CloudWatch Logs
](#quickref-cloudwatchlogs-example1)
+ [

## 从 Windows 实例将日志发送到 CloudWatch Logs
](#quickref-cloudwatchlogs-example2)
+ [

## 另请参阅
](#w2aac11c41c35c11)

## 从 Linux 实例将日志发送到 CloudWatch Logs
<a name="quickref-cloudwatchlogs-example1"></a>

以下模板演示了如何在集成 CloudWatch Logs 的 Amazon Linux 2023 上设置 Web 服务器。该模板将执行以下任务：
+ 安装 Apache 和 PHP。
+ 配置 CloudWatch Logs 代理，将 Apache 访问日志转发到 CloudWatch Logs。
+ 设置一个 IAM 角色让 CloudWatch 代理将日志数据发送到 CloudWatch Logs。
+ 创建自定义警报和通知，监控 404 错误或高带宽使用情况。

来自 Web 服务器的日志事件为 CloudWatch 警报提供了指标数据。两个指标筛选条件描述了将日志信息转换成 CloudWatch 指标的方法。404 指标用于统计出现 404 错误的次数。大小指标用于跟踪请求的大小。如果两分钟内出现两次以上的 404 错误，或平均请求大小在高于 3500 KB 的情况下持续 10 分钟，这两个 CloudWatch 警报将发送通知。

### JSON
<a name="quickref-cloudwatchlogs-example.json"></a>

```
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "Sample template that sets up and configures CloudWatch Logs on Amazon Linux 2023 instance.",
    "Parameters": {
        "KeyName": {
            "Description": "Name of an existing EC2 KeyPair to enable SSH access to the instances",
            "Type": "AWS::EC2::KeyPair::KeyName",
            "ConstraintDescription": "must be the name of an existing EC2 KeyPair."
        },
        "SSHLocation": {
            "Description": "The IP address range that can be used to SSH to the EC2 instances",
            "Type": "String",
            "MinLength": "9",
            "MaxLength": "18",
            "Default": "0.0.0.0/0",
            "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
            "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
        },
        "OperatorEmail": {
            "Description": "Email address to notify when CloudWatch alarms are triggered (404 errors or high bandwidth usage)",
            "Type": "String"
        }
    },
    "Resources": {
        "LogRole": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",		 	 	 
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": {
                                "Service": [
                                    "ec2.amazonaws.com"
                                ]
                            },
                            "Action": [
                                "sts:AssumeRole"
                            ]
                        }
                    ]
                },
                "Path": "/",
                "Policies": [
                    {
                        "PolicyName": "LogRolePolicy",
                        "PolicyDocument": {
                            "Version": "2012-10-17",		 	 	 
                            "Statement": [
                                {
                                    "Effect": "Allow",
                                    "Action": [
                                        "logs:PutLogEvents",
                                        "logs:DescribeLogStreams",
                                        "logs:DescribeLogGroups",
                                        "logs:CreateLogGroup",
                                        "logs:CreateLogStream"
                                    ],
                                    "Resource": "*"
                                }
                            ]
                        }
                    }
                ]
            }
        },
        "LogRoleInstanceProfile": {
            "Type": "AWS::IAM::InstanceProfile",
            "Properties": {
                "Path": "/",
                "Roles": [{"Ref": "LogRole"}]
            }
        },
        "WebServerSecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": "Enable HTTP access via port 80 and SSH access via port 22",
                "SecurityGroupIngress": [
                    {
                        "IpProtocol": "tcp",
                        "FromPort": 80,
                        "ToPort": 80,
                        "CidrIp": "0.0.0.0/0"
                    },
                    {
                        "IpProtocol": "tcp",
                        "FromPort": 22,
                        "ToPort": 22,
                        "CidrIp": {"Ref": "SSHLocation"}
                    }
                ]
            }
        },
        "WebServerHost": {
            "Type": "AWS::EC2::Instance",
            "Metadata": {
                "Comment": "Install a simple PHP application on Amazon Linux 2023",
                "AWS::CloudFormation::Init": {
                    "config": {
                        "packages": {
                            "dnf": {
                                "httpd": [],
                                "php": [],
                                "php-fpm": []
                            }
                        },
                        "files": {
                            "/etc/amazon-cloudwatch-agent/amazon-cloudwatch-agent.json": {
                                "content": {
                                    "logs": {
                                        "logs_collected": {
                                            "files": {
                                                "collect_list": [{
                                                    "file_path": "/var/log/httpd/access_log",
                                                    "log_group_name": {"Ref": "WebServerLogGroup"},
                                                    "log_stream_name": "{instance_id}/apache.log",
                                                    "timestamp_format": "%d/%b/%Y:%H:%M:%S %z"
                                                }]
                                            }
                                        }
                                    }
                                },
                                "mode": "000644",
                                "owner": "root",
                                "group": "root"
                            },
                            "/var/www/html/index.php": {
                                "content": "<?php\necho '<h1>AWS CloudFormation sample PHP application on Amazon Linux 2023</h1>';\n?>\n",
                                "mode": "000644",
                                "owner": "apache",
                                "group": "apache"
                            },
                            "/etc/cfn/cfn-hup.conf": {
                                "content":  {
                                    "Fn::Join": [
                                        "",
                                        [
                                            "[main]\n",
                                            "stack=",
                                            {"Ref": "AWS::StackId"},
                                            "\n",
                                            "region=",
                                            {"Ref": "AWS::Region"},
                                            "\n"
                                        ]
                                    ]
                                },
                                "mode": "000400",
                                "owner": "root",
                                "group": "root"
                            },
                            "/etc/cfn/hooks.d/cfn-auto-reloader.conf": {
                                "content": {
                                    "Fn::Join": [
                                        "",
                                        [
                                            "[cfn-auto-reloader-hook]\n",
                                            "triggers=post.update\n",
                                            "path=Resources.WebServerHost.Metadata.AWS::CloudFormation::Init\n",
                                            "action=/opt/aws/bin/cfn-init -s ",
                                            {"Ref": "AWS::StackId"},
                                            " -r WebServerHost ",
                                            " --region     ",
                                            {"Ref": "AWS::Region"},
                                            "\n",
                                            "runas=root\n"
                                        ]
                                    ]
                                }
                            }
                        },
                        "services": {
                            "systemd": {
                                "httpd": {
                                    "enabled": "true",
                                    "ensureRunning": "true"
                                },
                                "php-fpm": {
                                    "enabled": "true",
                                    "ensureRunning": "true"
                                }
                            }
                        }
                    }
                }
            },
            "CreationPolicy": {
                "ResourceSignal": {
                    "Timeout": "PT5M"
                }
            },
            "Properties": {
                "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64}}",
                "KeyName": {"Ref": "KeyName"},
                "InstanceType": "t3.micro",
                "SecurityGroupIds": [{"Ref": "WebServerSecurityGroup"}],
                "IamInstanceProfile": {"Ref": "LogRoleInstanceProfile"},
                "UserData": {"Fn::Base64": {"Fn::Join": [ "", [
                    "#!/bin/bash\n",
                    "dnf update -y aws-cfn-bootstrap\n",
                    "dnf install -y amazon-cloudwatch-agent\n",
                    "/opt/aws/bin/cfn-init -v --stack ", {"Ref": "AWS::StackName"}, " --resource WebServerHost --region ", {"Ref": "AWS::Region"}, "\n",
                    "\n",
                    "# Verify Apache log directory exists and create if needed\n",
                    "mkdir -p /var/log/httpd\n",
                    "\n",
                    "# Start CloudWatch agent\n",
                    "/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/etc/amazon-cloudwatch-agent/amazon-cloudwatch-agent.json -s\n",
                    "\n",
                    "# Signal success\n",
                    "/opt/aws/bin/cfn-signal -e $? --stack ", {"Ref": "AWS::StackName"}, " --resource WebServerHost --region ", {"Ref": "AWS::Region"}, "\n"
                ]]}}
            }
        },
        "WebServerLogGroup": {
            "Type": "AWS::Logs::LogGroup",
            "DeletionPolicy": "Retain",
            "UpdateReplacePolicy": "Retain",
            "Properties": {
                "RetentionInDays": 7
            }
        },
        "404MetricFilter": {
            "Type": "AWS::Logs::MetricFilter",
            "Properties": {
                "LogGroupName": {"Ref": "WebServerLogGroup"},
                "FilterPattern": "[ip, identity, user_id, timestamp, request, status_code = 404, size, ...]",
                "MetricTransformations": [
                    {
                        "MetricValue": "1",
                        "MetricNamespace": "test/404s",
                        "MetricName": "test404Count"
                    }
                ]
            }
        },
        "BytesTransferredMetricFilter": {
            "Type": "AWS::Logs::MetricFilter",
            "Properties": {
                "LogGroupName": {"Ref": "WebServerLogGroup"},
                "FilterPattern": "[ip, identity, user_id, timestamp, request, status_code, size, ...]",
                "MetricTransformations": [
                    {
                        "MetricValue": "$size",
                        "MetricNamespace": "test/BytesTransferred",
                        "MetricName": "testBytesTransferred"
                    }
                ]
            }
        },
        "404Alarm": {
            "Type": "AWS::CloudWatch::Alarm",
            "Properties": {
                "AlarmDescription": "The number of 404s is greater than 2 over 2 minutes",
                "MetricName": "test404Count",
                "Namespace": "test/404s",
                "Statistic": "Sum",
                "Period": "60",
                "EvaluationPeriods": "2",
                "Threshold": "2",
                "AlarmActions": [{"Ref": "AlarmNotificationTopic"}],
                "ComparisonOperator": "GreaterThanThreshold"
            }
        },
        "BandwidthAlarm": {
            "Type": "AWS::CloudWatch::Alarm",
            "Properties": {
                "AlarmDescription": "The average volume of traffic is greater 3500 KB over 10 minutes",
                "MetricName": "testBytesTransferred",
                "Namespace": "test/BytesTransferred",
                "Statistic": "Average",
                "Period": "300",
                "EvaluationPeriods": "2",
                "Threshold": "3500",
                "AlarmActions": [{"Ref": "AlarmNotificationTopic"}],
                "ComparisonOperator": "GreaterThanThreshold"
            }
        },
        "AlarmNotificationTopic": {
            "Type": "AWS::SNS::Topic",
            "Properties": {
                "Subscription": [{"Endpoint": {"Ref": "OperatorEmail"}, "Protocol": "email"}]
            }
        }
    },
    "Outputs": {
        "InstanceId": {
            "Description": "The instance ID of the web server",
            "Value": {"Ref": "WebServerHost"}
        },
        "WebsiteURL": {
            "Value": {"Fn::Sub": "http://${WebServerHost.PublicDnsName}"},
            "Description": "URL for the web server"
        },
        "PublicIP": {
            "Description": "Public IP address of the web server",
            "Value": {"Fn::GetAtt": ["WebServerHost","PublicIp"]
            }
        },
        "CloudWatchLogGroupName": {
            "Description": "The name of the CloudWatch log group",
            "Value": {"Ref": "WebServerLogGroup"}
        }
    }
}
```

### YAML
<a name="quickref-cloudwatchlogs-example.yaml"></a>

```
AWSTemplateFormatVersion: 2010-09-09
Description: Sample template that sets up and configures CloudWatch Logs on Amazon Linux 2023 instance.
Parameters:
  KeyName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instances
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription: must be the name of an existing EC2 KeyPair.
  SSHLocation:
    Description: The IP address range that can be used to SSH to the EC2 instances
    Type: String
    MinLength: '9'
    MaxLength: '18'
    Default: 0.0.0.0/0
    AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})'
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
  OperatorEmail:
    Description: Email address to notify when CloudWatch alarms are triggered (404 errors or high bandwidth usage)
    Type: String
Resources:
  LogRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17		 	 	 
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      Policies:
        - PolicyName: LogRolePolicy
          PolicyDocument:
            Version: 2012-10-17		 	 	 
            Statement:
              - Effect: Allow
                Action:
                  - 'logs:PutLogEvents'
                  - 'logs:DescribeLogStreams'
                  - 'logs:DescribeLogGroups'
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                Resource: '*'
  LogRoleInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref LogRole
  WebServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable HTTP access via port 80 and SSH access via port 22
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref SSHLocation
  WebServerHost:
    Type: AWS::EC2::Instance
    Metadata:
      Comment: Install a simple PHP application on Amazon Linux 2023
      'AWS::CloudFormation::Init':
        config:
          packages:
            dnf:
              httpd: []
              php: []
              php-fpm: []
          files:
            /etc/amazon-cloudwatch-agent/amazon-cloudwatch-agent.json:
              content: !Sub |
                {
                  "logs": {
                    "logs_collected": {
                      "files": {
                        "collect_list": [
                          {
                            "file_path": "/var/log/httpd/access_log",
                            "log_group_name": "${WebServerLogGroup}",
                            "log_stream_name": "{instance_id}/apache.log",
                            "timestamp_format": "%d/%b/%Y:%H:%M:%S %z"
                          }
                        ]
                      }
                    }
                  }
                }
              mode: '000644'
              owner: root
              group: root
            /var/www/html/index.php:
              content: |
                <?php echo '<h1>AWS CloudFormation sample PHP application on Amazon Linux 2023</h1>';
                ?>
              mode: '000644'
              owner: apache
              group: apache
            /etc/cfn/cfn-hup.conf:
              content: !Sub |
                [main]
                stack=${AWS::StackId}
                region=${AWS::Region}
              mode: '000400'
              owner: root
              group: root
            /etc/cfn/hooks.d/cfn-auto-reloader.conf:
              content: !Sub |
                [cfn-auto-reloader-hook]
                triggers=post.update
                path=Resources.WebServerHost.Metadata.AWS::CloudFormation::Init
                action=/opt/aws/bin/cfn-init -s ${AWS::StackId} -r WebServerHost --region ${AWS::Region}
                runas=root
          services:
            systemd:
              httpd:
                enabled: 'true'
                ensureRunning: 'true'
              php-fpm:
                enabled: 'true'
                ensureRunning: 'true'
    CreationPolicy:
      ResourceSignal:
        Timeout: PT5M
    Properties:
      ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64}}'
      KeyName: !Ref KeyName
      InstanceType: t3.micro
      SecurityGroupIds:
        - !Ref WebServerSecurityGroup
      IamInstanceProfile: !Ref LogRoleInstanceProfile
      UserData: !Base64
        Fn::Sub: |
          #!/bin/bash
          dnf update -y aws-cfn-bootstrap
          dnf install -y amazon-cloudwatch-agent
          /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerHost --region ${AWS::Region}
          
          # Verify Apache log directory exists and create if needed
          mkdir -p /var/log/httpd
          
          # Start CloudWatch agent
          /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/etc/amazon-cloudwatch-agent/amazon-cloudwatch-agent.json -s
          
          # Signal success
          /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerHost --region ${AWS::Region}
          echo "Done"
  WebServerLogGroup:
    Type: AWS::Logs::LogGroup
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      RetentionInDays: 7
  404MetricFilter:
    Type: AWS::Logs::MetricFilter
    Properties:
      LogGroupName: !Ref WebServerLogGroup
      FilterPattern: >-
        [ip, identity, user_id, timestamp, request, status_code = 404, size, ...]
      MetricTransformations:
        - MetricValue: '1'
          MetricNamespace: test/404s
          MetricName: test404Count
  BytesTransferredMetricFilter:
    Type: AWS::Logs::MetricFilter
    Properties:
      LogGroupName: !Ref WebServerLogGroup
      FilterPattern: '[ip, identity, user_id, timestamp, request, status_code, size, ...]'
      MetricTransformations:
        - MetricValue: $size
          MetricNamespace: test/BytesTransferred
          MetricName: testBytesTransferred
  404Alarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmDescription: The number of 404s is greater than 2 over 2 minutes
      MetricName: test404Count
      Namespace: test/404s
      Statistic: Sum
      Period: '60'
      EvaluationPeriods: '2'
      Threshold: '2'
      AlarmActions:
        - !Ref AlarmNotificationTopic
      ComparisonOperator: GreaterThanThreshold
  BandwidthAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmDescription: The average volume of traffic is greater 3500 KB over 10 minutes
      MetricName: testBytesTransferred
      Namespace: test/BytesTransferred
      Statistic: Average
      Period: '300'
      EvaluationPeriods: '2'
      Threshold: '3500'
      AlarmActions:
        - !Ref AlarmNotificationTopic
      ComparisonOperator: GreaterThanThreshold
  AlarmNotificationTopic:
    Type: AWS::SNS::Topic
    Properties:
      Subscription:
        - Endpoint: !Ref OperatorEmail
          Protocol: email
Outputs:
  InstanceId:
    Description: The instance ID of the web server
    Value: !Ref WebServerHost
  WebsiteURL:
    Value: !Sub 'http://${WebServerHost.PublicDnsName}'
    Description: URL for the web server
  PublicIP:
    Description: Public IP address of the web server
    Value: !GetAtt WebServerHost.PublicIp
  CloudWatchLogGroupName:
    Description: The name of the CloudWatch log group
    Value: !Ref WebServerLogGroup
```

## 从 Windows 实例将日志发送到 CloudWatch Logs
<a name="quickref-cloudwatchlogs-example2"></a>

以下模板为 Windows 2012R2 实例配置 CloudWatch Logs。

Windows 上的 CloudWatch Logs 代理（Windows 2012R2 和 Windows 2016 AMI 上的 SSM 代理）仅在启动之后才会发送日志，因此不会发送启动之前生成的任何日志。针对此问题，该模板帮助确保在任何日志写入之前启动代理，方法为：
+ 将代理安装程序配置为 cfn-init `config` 中的第一个 `configSets` 项。
+ 使用 `waitAfterCompletion` 在启动代理的命令之后插入一个暂停。

### JSON
<a name="quickref-cloudwatchlogs-example2.json"></a>

```
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "Sample template that sets up and configures CloudWatch Logs on Windows 2012R2 instance.",
    "Parameters": {
        "KeyPair": {
            "Description": "Name of an existing EC2 KeyPair to enable RDP access to the instances",
            "Type": "AWS::EC2::KeyPair::KeyName",
            "ConstraintDescription": "must be the name of an existing EC2 KeyPair."
        },
        "RDPLocation": {
            "Description": "The IP address range that can be used to RDP to the EC2 instances",
            "Type": "String",
            "MinLength": "9",
            "MaxLength": "18",
            "Default": "0.0.0.0/0",
            "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
            "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
        },
        "OperatorEmail": {
            "Description": "Email address to notify when CloudWatch alarms are triggered (404 errors)",
            "Type": "String"
        }
    },
    "Resources": {
        "WebServerSecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": "Enable HTTP access via port 80 and RDP access via port 3389",
                "SecurityGroupIngress": [
                    {
                        "IpProtocol": "tcp",
                        "FromPort": "80",
                        "ToPort": "80",
                        "CidrIp": "0.0.0.0/0"
                    },
                    {
                        "IpProtocol": "tcp",
                        "FromPort": "3389",
                        "ToPort": "3389",
                        "CidrIp": {"Ref": "RDPLocation"}
                    }
                ]
            }
        },
        "LogRole": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",		 	 	 
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": {
                                "Service": [
                                    "ec2.amazonaws.com"
                                ]
                            },
                            "Action": [
                                "sts:AssumeRole"
                            ]
                        }
                    ]
                },
                "ManagedPolicyArns": [
                    "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
                ],
                "Path": "/",
                "Policies": [
                    {
                        "PolicyName": "LogRolePolicy",
                        "PolicyDocument": {
                            "Version": "2012-10-17",		 	 	 
                            "Statement": [
                                {
                                    "Effect": "Allow",
                                    "Action": [
                                        "logs:Create*",
                                        "logs:PutLogEvents",
                                        "s3:GetObject"
                                    ],
                                    "Resource": [
                                        "arn:aws:logs:*:*:*",
                                        "arn:aws:s3:::*"
                                    ]
                                }
                            ]
                        }
                    }
                ]
            }
        },
        "LogRoleInstanceProfile": {
            "Type": "AWS::IAM::InstanceProfile",
            "Properties": {
                "Path": "/",
                "Roles": [{"Ref": "LogRole"}]
            }
        },
        "WebServerHost": {
            "Type": "AWS::EC2::Instance",
            "CreationPolicy": {
                "ResourceSignal": {
                    "Timeout": "PT15M"
                }
            },
            "Metadata": {
                "AWS::CloudFormation::Init": {
                    "configSets": {
                        "config": [
                            "00-ConfigureCWLogs",
                            "01-InstallWebServer",
                            "02-ConfigureApplication",
                            "03-Finalize"
                        ]
                    },
                    "00-ConfigureCWLogs": {
                        "files": {
                            "C:\\Program Files\\Amazon\\SSM\\Plugins\\awsCloudWatch\\AWS.EC2.Windows.CloudWatch.json": {
                                "content": {
                                    "EngineConfiguration": {
                                        "Components": [
                                            {
                                                "FullName": "AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch",
                                                "Id": "ApplicationEventLog",
                                                "Parameters": {
                                                    "Levels": "7",
                                                    "LogName": "Application"
                                                }
                                            },
                                            {
                                                "FullName": "AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch",
                                                "Id": "SystemEventLog",
                                                "Parameters": {
                                                    "Levels": "7",
                                                    "LogName": "System"
                                                }
                                            },
                                            {
                                                "FullName": "AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch",
                                                "Id": "SecurityEventLog",
                                                "Parameters": {
                                                    "Levels": "7",
                                                    "LogName": "Security"
                                                }
                                            },
                                            {
                                                "FullName": "AWS.EC2.Windows.CloudWatch.CustomLog.CustomLogInputComponent,AWS.EC2.Windows.CloudWatch",
                                                "Id": "EC2ConfigLog",
                                                "Parameters": {
                                                    "CultureName": "en-US",
                                                    "Encoding": "ASCII",
                                                    "Filter": "EC2ConfigLog.txt",
                                                    "LogDirectoryPath": "C:\\Program Files\\Amazon\\Ec2ConfigService\\Logs",
                                                    "TimeZoneKind": "UTC",
                                                    "TimestampFormat": "yyyy-MM-ddTHH:mm:ss.fffZ:"
                                                }
                                            },
                                            {
                                                "FullName": "AWS.EC2.Windows.CloudWatch.CustomLog.CustomLogInputComponent,AWS.EC2.Windows.CloudWatch",
                                                "Id": "CfnInitLog",
                                                "Parameters": {
                                                    "CultureName": "en-US",
                                                    "Encoding": "ASCII",
                                                    "Filter": "cfn-init.log",
                                                    "LogDirectoryPath": "C:\\cfn\\log",
                                                    "TimeZoneKind": "Local",
                                                    "TimestampFormat": "yyyy-MM-dd HH:mm:ss,fff"
                                                }
                                            },
                                            {
                                                "FullName": "AWS.EC2.Windows.CloudWatch.CustomLog.CustomLogInputComponent,AWS.EC2.Windows.CloudWatch",
                                                "Id": "IISLogs",
                                                "Parameters": {
                                                    "CultureName": "en-US",
                                                    "Encoding": "UTF-8",
                                                    "Filter": "",
                                                    "LineCount": "3",
                                                    "LogDirectoryPath": "C:\\inetpub\\logs\\LogFiles\\W3SVC1",
                                                    "TimeZoneKind": "UTC",
                                                    "TimestampFormat": "yyyy-MM-dd HH:mm:ss"
                                                }
                                            },
                                            {
                                                "FullName": "AWS.EC2.Windows.CloudWatch.PerformanceCounterComponent.PerformanceCounterInputComponent,AWS.EC2.Windows.CloudWatch",
                                                "Id": "MemoryPerformanceCounter",
                                                "Parameters": {
                                                    "CategoryName": "Memory",
                                                    "CounterName": "Available MBytes",
                                                    "DimensionName": "",
                                                    "DimensionValue": "",
                                                    "InstanceName": "",
                                                    "MetricName": "Memory",
                                                    "Unit": "Megabytes"
                                                }
                                            },
                                            {
                                                "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                                                "Id": "CloudWatchApplicationEventLog",
                                                "Parameters": {
                                                    "AccessKey": "",
                                                    "LogGroup": {"Ref": "LogGroup"},
                                                    "LogStream": "{instance_id}/ApplicationEventLog",
                                                    "Region": {"Ref": "AWS::Region"},
                                                    "SecretKey": ""
                                                }
                                            },
                                            {
                                                "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                                                "Id": "CloudWatchSystemEventLog",
                                                "Parameters": {
                                                    "AccessKey": "",
                                                    "LogGroup": {"Ref": "LogGroup"},
                                                    "LogStream": "{instance_id}/SystemEventLog",
                                                    "Region": {"Ref": "AWS::Region"},
                                                    "SecretKey": ""
                                                }
                                            },
                                            {
                                                "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                                                "Id": "CloudWatchSecurityEventLog",
                                                "Parameters": {
                                                    "AccessKey": "",
                                                    "LogGroup": {"Ref": "LogGroup"},
                                                    "LogStream": "{instance_id}/SecurityEventLog",
                                                    "Region": {"Ref": "AWS::Region"},
                                                    "SecretKey": ""
                                                }
                                            },
                                            {
                                                "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                                                "Id": "CloudWatchEC2ConfigLog",
                                                "Parameters": {
                                                    "AccessKey": "",
                                                    "LogGroup": {"Ref": "LogGroup"},
                                                    "LogStream": "{instance_id}/EC2ConfigLog",
                                                    "Region": {"Ref": "AWS::Region"},
                                                    "SecretKey": ""
                                                }
                                            },
                                            {
                                                "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                                                "Id": "CloudWatchCfnInitLog",
                                                "Parameters": {
                                                    "AccessKey": "",
                                                    "LogGroup": {"Ref": "LogGroup"},
                                                    "LogStream": "{instance_id}/CfnInitLog",
                                                    "Region": {"Ref": "AWS::Region"},
                                                    "SecretKey": ""
                                                }
                                            },
                                            {
                                                "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                                                "Id": "CloudWatchIISLogs",
                                                "Parameters": {
                                                    "AccessKey": "",
                                                    "LogGroup": {"Ref": "LogGroup"},
                                                    "LogStream": "{instance_id}/IISLogs",
                                                    "Region": {"Ref": "AWS::Region"},
                                                    "SecretKey": ""
                                                }
                                            },
                                            {
                                                "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatch.CloudWatchOutputComponent,AWS.EC2.Windows.CloudWatch",
                                                "Id": "CloudWatch",
                                                "Parameters": {
                                                    "AccessKey": "",
                                                    "NameSpace": "Windows/Default",
                                                    "Region": {"Ref": "AWS::Region"},
                                                    "SecretKey": ""
                                                }
                                            }
                                        ],
                                        "Flows": {
                                            "Flows": [
                                                "ApplicationEventLog,CloudWatchApplicationEventLog",
                                                "SystemEventLog,CloudWatchSystemEventLog",
                                                "SecurityEventLog,CloudWatchSecurityEventLog",
                                                "EC2ConfigLog,CloudWatchEC2ConfigLog",
                                                "CfnInitLog,CloudWatchCfnInitLog",
                                                "IISLogs,CloudWatchIISLogs",
                                                "MemoryPerformanceCounter,CloudWatch"
                                            ]
                                        },
                                        "PollInterval": "00:00:05"
                                    },
                                    "IsEnabled": true
                                }
                            }
                        },
                        "commands": {
                            "0-enableSSM": {
                                "command": "powershell.exe -Command \"Set-Service -Name AmazonSSMAgent -StartupType Automatic\" ",
                                "waitAfterCompletion": "0"
                            },
                            "1-restartSSM": {
                                "command": "powershell.exe -Command \"Restart-Service AmazonSSMAgent \"",
                                "waitAfterCompletion": "30"
                            }
                        }
                    },
                    "01-InstallWebServer": {
                        "commands": {
                            "01_install_webserver": {
                                "command": "powershell.exe -Command \"Install-WindowsFeature Web-Server  -IncludeAllSubFeature\"",
                                "waitAfterCompletion": "0"
                            }
                        }
                    },
                    "02-ConfigureApplication": {
                        "files": {
                            "c:\\Inetpub\\wwwroot\\index.htm": {
                                "content": "<html> <head> <title>Test Application Page</title> </head> <body> <h1>Congratulations!! Your IIS server is configured.</h1> </body> </html>"
                            }
                        }
                    },
                    "03-Finalize": {
                        "commands": {
                            "00_signal_success": {
                                "command": {
                                    "Fn::Sub": "cfn-signal.exe -e 0 --resource WebServerHost --stack ${AWS::StackName} --region ${AWS::Region}"
                                },
                                "waitAfterCompletion": "0"
                            }
                        }
                    }
                }
            },
            "Properties": {
                "KeyName": {
                    "Ref": "KeyPair"
                },
                "ImageId": "{{resolve:ssm:/aws/service/ami-windows-latest/Windows_Server-2012-R2_RTM-English-64Bit-Base}}",
                "InstanceType": "t2.xlarge",
                "SecurityGroupIds": [{"Ref": "WebServerSecurityGroup"}],
                "IamInstanceProfile": {"Ref": "LogRoleInstanceProfile"},
                "UserData": {
                    "Fn::Base64": {
                        "Fn::Join": [
                            "",
                            [
                                "<script>\n",
                                "wmic product where \"description='Amazon SSM Agent' \" uninstall\n",
                                "wmic product where \"description='aws-cfn-bootstrap' \" uninstall \n",
                                "start /wait c:\\Windows\\system32\\msiexec /passive /qn /i https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-win64-latest.msi\n",
                                "powershell.exe -Command \"iwr https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/windows_amd64/AmazonSSMAgentSetup.exe  -UseBasicParsing -OutFile C:\\AmazonSSMAgentSetup.exe\"\n",
                                "start /wait C:\\AmazonSSMAgentSetup.exe /install /quiet\n",
                                "cfn-init.exe -v -c config -s ", {"Ref": "AWS::StackName"}, " --resource WebServerHost --region ", {"Ref": "AWS::Region"}, " \n",
                                "</script>\n"
                            ]
                        ]
                    }
                }
            }
        },
        "LogGroup": {
            "Type": "AWS::Logs::LogGroup",
            "Properties": {
                "RetentionInDays": 7
            }
        },
        "404MetricFilter": {
            "Type": "AWS::Logs::MetricFilter",
            "Properties": {
                "LogGroupName": {"Ref": "LogGroup"},
                "FilterPattern": "[timestamps, serverip, method, uri, query, port, dash, clientip, useragent, status_code = 404, ...]",
                "MetricTransformations": [
                    {
                        "MetricValue": "1",
                        "MetricNamespace": "test/404s",
                        "MetricName": "test404Count"
                    }
                ]
            }
        },
        "404Alarm": {
            "Type": "AWS::CloudWatch::Alarm",
            "Properties": {
                "AlarmDescription": "The number of 404s is greater than 2 over 2 minutes",
                "MetricName": "test404Count",
                "Namespace": "test/404s",
                "Statistic": "Sum",
                "Period": "60",
                "EvaluationPeriods": "2",
                "Threshold": "2",
                "AlarmActions": [{"Ref": "AlarmNotificationTopic"}],
                "ComparisonOperator": "GreaterThanThreshold"
            }
        },
        "AlarmNotificationTopic": {
            "Type": "AWS::SNS::Topic",
            "Properties": {
                "Subscription": [{"Endpoint": {"Ref": "OperatorEmail"}, "Protocol": "email"}]
            }
        }
    },
    "Outputs": {
        "InstanceId": {
            "Description": "The instance ID of the web server",
            "Value": {"Ref": "WebServerHost"}
        },
        "WebsiteURL": {
            "Value": {"Fn::Sub": "http://${WebServerHost.PublicDnsName}"},
            "Description": "URL for the web server"
        },
        "PublicIP": {
            "Description": "Public IP address of the web server",
            "Value": {"Fn::GetAtt": ["WebServerHost","PublicIp"]}
        },
        "CloudWatchLogGroupName": {
            "Description": "The name of the CloudWatch log group",
            "Value": {"Ref": "LogGroup"}
        }
    }
}
```

### YAML
<a name="quickref-cloudwatchlogs-example2.yaml"></a>

```
AWSTemplateFormatVersion: 2010-09-09
Description: >-
  Sample template that sets up and configures CloudWatch Logs on Windows 2012R2 instance.
Parameters:
  KeyPair:
    Description: Name of an existing EC2 KeyPair to enable RDP access to the instances
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription: must be the name of an existing EC2 KeyPair.
  RDPLocation:
    Description: The IP address range that can be used to RDP to the EC2 instances
    Type: String
    MinLength: '9'
    MaxLength: '18'
    Default: 0.0.0.0/0
    AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})'
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
  OperatorEmail:
    Description: Email address to notify when CloudWatch alarms are triggered (404 errors)
    Type: String
Resources:
  WebServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable HTTP access via port 80 and RDP access via port 3389
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '80'
          ToPort: '80'
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: '3389'
          ToPort: '3389'
          CidrIp: !Ref RDPLocation
  LogRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17		 	 	 
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore'
      Path: /
      Policies:
        - PolicyName: LogRolePolicy
          PolicyDocument:
            Version: 2012-10-17		 	 	 
            Statement:
              - Effect: Allow
                Action:
                  - 'logs:Create*'
                  - 'logs:PutLogEvents'
                  - 's3:GetObject'
                Resource:
                  - 'arn:aws:logs:*:*:*'
                  - 'arn:aws:s3:::*'
  LogRoleInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref LogRole
  WebServerHost:
    Type: AWS::EC2::Instance
    CreationPolicy:
      ResourceSignal:
        Timeout: PT15M
    Metadata:
      'AWS::CloudFormation::Init':
        configSets:
          config:
            - 00-ConfigureCWLogs
            - 01-InstallWebServer
            - 02-ConfigureApplication
            - 03-Finalize
        00-ConfigureCWLogs:
          files:
            'C:\Program Files\Amazon\SSM\Plugins\awsCloudWatch\AWS.EC2.Windows.CloudWatch.json':
              content: !Sub |
                {
                  "EngineConfiguration": {
                      "Components": [
                          {
                              "FullName": "AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch",
                              "Id": "ApplicationEventLog",
                              "Parameters": {
                                  "Levels": "7",
                                  "LogName": "Application"
                              }
                          },
                          {
                              "FullName": "AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch",
                              "Id": "SystemEventLog",
                              "Parameters": {
                                  "Levels": "7",
                                  "LogName": "System"
                              }
                          },
                          {
                              "FullName": "AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch",
                              "Id": "SecurityEventLog",
                              "Parameters": {
                                  "Levels": "7",
                                  "LogName": "Security"
                              }
                          },
                          {
                              "FullName": "AWS.EC2.Windows.CloudWatch.CustomLog.CustomLogInputComponent,AWS.EC2.Windows.CloudWatch",
                              "Id": "EC2ConfigLog",
                              "Parameters": {
                                  "CultureName": "en-US",
                                  "Encoding": "ASCII",
                                  "Filter": "EC2ConfigLog.txt",
                                  "LogDirectoryPath": "C:\\Program Files\\Amazon\\Ec2ConfigService\\Logs",
                                  "TimeZoneKind": "UTC",
                                  "TimestampFormat": "yyyy-MM-ddTHH:mm:ss.fffZ:"
                              }
                          },
                          {
                              "FullName": "AWS.EC2.Windows.CloudWatch.CustomLog.CustomLogInputComponent,AWS.EC2.Windows.CloudWatch",
                              "Id": "CfnInitLog",
                              "Parameters": {
                                  "CultureName": "en-US",
                                  "Encoding": "ASCII",
                                  "Filter": "cfn-init.log",
                                  "LogDirectoryPath": "C:\\cfn\\log",
                                  "TimeZoneKind": "Local",
                                  "TimestampFormat": "yyyy-MM-dd HH:mm:ss,fff"
                              }
                          },
                          {
                              "FullName": "AWS.EC2.Windows.CloudWatch.CustomLog.CustomLogInputComponent,AWS.EC2.Windows.CloudWatch",
                              "Id": "IISLogs",
                              "Parameters": {
                                  "CultureName": "en-US",
                                  "Encoding": "UTF-8",
                                  "Filter": "",
                                  "LineCount": "3",
                                  "LogDirectoryPath": "C:\\inetpub\\logs\\LogFiles\\W3SVC1",
                                  "TimeZoneKind": "UTC",
                                  "TimestampFormat": "yyyy-MM-dd HH:mm:ss"
                              }
                          },
                          {
                              "FullName": "AWS.EC2.Windows.CloudWatch.PerformanceCounterComponent.PerformanceCounterInputComponent,AWS.EC2.Windows.CloudWatch",
                              "Id": "MemoryPerformanceCounter",
                              "Parameters": {
                                  "CategoryName": "Memory",
                                  "CounterName": "Available MBytes",
                                  "DimensionName": "",
                                  "DimensionValue": "",
                                  "InstanceName": "",
                                  "MetricName": "Memory",
                                  "Unit": "Megabytes"
                              }
                          },
                          {
                              "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                              "Id": "CloudWatchApplicationEventLog",
                              "Parameters": {
                                  "AccessKey": "",
                                  "LogGroup": "${LogGroup}",
                                  "LogStream": "{instance_id}/ApplicationEventLog",
                                  "Region": "${AWS::Region}",
                                  "SecretKey": ""
                              }
                          },
                          {
                              "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                              "Id": "CloudWatchSystemEventLog",
                              "Parameters": {
                                  "AccessKey": "",
                                  "LogGroup": "${LogGroup}",
                                  "LogStream": "{instance_id}/SystemEventLog",
                                  "Region": "${AWS::Region}",
                                  "SecretKey": ""
                              }
                          },
                          {
                              "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                              "Id": "CloudWatchSecurityEventLog",
                              "Parameters": {
                                  "AccessKey": "",
                                  "LogGroup": "${LogGroup}",
                                  "LogStream": "{instance_id}/SecurityEventLog",
                                  "Region": "${AWS::Region}",
                                  "SecretKey": ""
                              }
                          },
                          {
                              "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                              "Id": "CloudWatchEC2ConfigLog",
                              "Parameters": {
                                  "AccessKey": "",
                                  "LogGroup": "${LogGroup}",
                                  "LogStream": "{instance_id}/EC2ConfigLog",
                                  "Region": "${AWS::Region}",
                                  "SecretKey": ""
                              }
                          },
                          {
                              "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                              "Id": "CloudWatchCfnInitLog",
                              "Parameters": {
                                  "AccessKey": "",
                                  "LogGroup": "${LogGroup}",
                                  "LogStream": "{instance_id}/CfnInitLog",
                                  "Region": "${AWS::Region}",
                                  "SecretKey": ""
                              }
                          },
                          {
                              "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                              "Id": "CloudWatchIISLogs",
                              "Parameters": {
                                  "AccessKey": "",
                                  "LogGroup": "${LogGroup}",
                                  "LogStream": "{instance_id}/IISLogs",
                                  "Region": "${AWS::Region}",
                                  "SecretKey": ""
                              }
                          },
                          {
                              "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatch.CloudWatchOutputComponent,AWS.EC2.Windows.CloudWatch",
                              "Id": "CloudWatch",
                              "Parameters": {
                                  "AccessKey": "",
                                  "NameSpace": "Windows/Default",
                                  "Region": "${AWS::Region}",
                                  "SecretKey": ""
                              }
                          }
                      ],
                      "Flows": {
                          "Flows": [
                              "ApplicationEventLog,CloudWatchApplicationEventLog",
                              "SystemEventLog,CloudWatchSystemEventLog",
                              "SecurityEventLog,CloudWatchSecurityEventLog",
                              "EC2ConfigLog,CloudWatchEC2ConfigLog",
                              "CfnInitLog,CloudWatchCfnInitLog",
                              "IISLogs,CloudWatchIISLogs",
                              "MemoryPerformanceCounter,CloudWatch"
                          ]
                      },
                      "PollInterval": "00:00:05"
                  },
                  "IsEnabled": true
                }
          commands:
            0-enableSSM:
              command: >-
                powershell.exe -Command "Set-Service -Name AmazonSSMAgent
                -StartupType Automatic" 
              waitAfterCompletion: '0'
            1-restartSSM:
              command: powershell.exe -Command "Restart-Service AmazonSSMAgent "
              waitAfterCompletion: '30'
        01-InstallWebServer:
          commands:
            01_install_webserver:
              command: >-
                powershell.exe -Command "Install-WindowsFeature Web-Server 
                -IncludeAllSubFeature"
              waitAfterCompletion: '0'
        02-ConfigureApplication:
          files:
            'c:\Inetpub\wwwroot\index.htm':
              content: >-
                <html> <head> <title>Test Application Page</title> </head>
                <body> <h1>Congratulations !! Your IIS server is
                configured.</h1> </body> </html>
        03-Finalize:
          commands:
            00_signal_success:
              command: !Sub >-
                cfn-signal.exe -e 0 --resource WebServerHost --stack
                ${AWS::StackName} --region ${AWS::Region}
              waitAfterCompletion: '0'
    Properties:
      KeyName: !Ref KeyPair
      ImageId: "{{resolve:ssm:/aws/service/ami-windows-latest/Windows_Server-2012-R2_RTM-English-64Bit-Base}}"
      InstanceType: t2.xlarge
      SecurityGroupIds:
        - !Ref WebServerSecurityGroup
      IamInstanceProfile: !Ref LogRoleInstanceProfile
      UserData: !Base64 
        'Fn::Sub': >
          <script>

          wmic product where "description='Amazon SSM Agent' " uninstall

          wmic product where "description='aws-cfn-bootstrap' " uninstall 

          start /wait c:\\Windows\\system32\\msiexec /passive /qn /i
          https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-win64-latest.msi

          powershell.exe -Command "iwr
          https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/windows_amd64/AmazonSSMAgentSetup.exe 
          -UseBasicParsing -OutFile C:\\AmazonSSMAgentSetup.exe"

          start /wait C:\\AmazonSSMAgentSetup.exe /install /quiet

          cfn-init.exe -v -c config -s ${AWS::StackName} --resource
          WebServerHost --region ${AWS::Region} 

          </script>
  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      RetentionInDays: 7
  404MetricFilter:
    Type: AWS::Logs::MetricFilter
    Properties:
      LogGroupName: !Ref LogGroup
      FilterPattern: >-
        [timestamps, serverip, method, uri, query, port, dash, clientip,
        useragent, status_code = 404, ...]
      MetricTransformations:
        - MetricValue: '1'
          MetricNamespace: test/404s
          MetricName: test404Count
  404Alarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmDescription: The number of 404s is greater than 2 over 2 minutes
      MetricName: test404Count
      Namespace: test/404s
      Statistic: Sum
      Period: '60'
      EvaluationPeriods: '2'
      Threshold: '2'
      AlarmActions:
        - !Ref AlarmNotificationTopic
      ComparisonOperator: GreaterThanThreshold
  AlarmNotificationTopic:
    Type: AWS::SNS::Topic
    Properties:
      Subscription:
        - Endpoint: !Ref OperatorEmail
          Protocol: email
Outputs:
  InstanceId:
    Description: The instance ID of the web server
    Value: !Ref WebServerHost
  WebsiteURL:
    Value: !Sub 'http://${WebServerHost.PublicDnsName}'
    Description: URL for the web server
  PublicIP:
    Description: Public IP address of the web server
    Value: !GetAtt 
      - WebServerHost
      - PublicIp
  CloudWatchLogGroupName:
    Description: The name of the CloudWatch log group
    Value: !Ref LogGroup
```

## 另请参阅
<a name="w2aac11c41c35c11"></a>

有关 CloudWatch Logs 资源的更多信息，请参阅 [AWS::Logs::LogGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-logs-loggroup.html) 或 [AWs::Logs::MetricFilter](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-logs-metricfilter.html)。

# Amazon DynamoDB 模板代码段
<a name="quickref-dynamodb"></a>

**Topics**
+ [

## 具有 Amazon DynamoDB 表的 Application Auto Scaling
](#quickref-dynamodb-application-autoscaling)
+ [

## 另请参阅
](#w2aac11c41c39b7)

## 具有 Amazon DynamoDB 表的 Application Auto Scaling
<a name="quickref-dynamodb-application-autoscaling"></a>

此示例为 `AWS::DynamoDB::Table` 资源设置 Application Auto Scaling。此模板定义扩展表的 `TargetTrackingScaling` 吞吐量的 `WriteCapacityUnits` 扩展策略。

### JSON
<a name="quickref-dynamodb-example.json"></a>

```
{
    "Resources": {
        "DDBTable": {
            "Type": "AWS::DynamoDB::Table",
            "Properties": {
                "AttributeDefinitions": [
                    {
                        "AttributeName": "ArtistId",
                        "AttributeType": "S"
                    },
                    {
                        "AttributeName": "Concert",
                        "AttributeType": "S"
                    },
                    {
                        "AttributeName": "TicketSales",
                        "AttributeType": "S"
                    }
                ],
                "KeySchema": [
                    {
                        "AttributeName": "ArtistId",
                        "KeyType": "HASH"
                    },
                    {
                        "AttributeName": "Concert",
                        "KeyType": "RANGE"
                    }
                ],
                "GlobalSecondaryIndexes": [
                    {
                        "IndexName": "GSI",
                        "KeySchema": [
                            {
                                "AttributeName": "TicketSales",
                                "KeyType": "HASH"
                            }
                        ],
                        "Projection": {
                            "ProjectionType": "KEYS_ONLY"
                        },
                        "ProvisionedThroughput": {
                            "ReadCapacityUnits": 5,
                            "WriteCapacityUnits": 5
                        }
                    }
                ],
                "ProvisionedThroughput": {
                    "ReadCapacityUnits": 5,
                    "WriteCapacityUnits": 5
                }
            }
        },
        "WriteCapacityScalableTarget": {
            "Type": "AWS::ApplicationAutoScaling::ScalableTarget",
            "Properties": {
                "MaxCapacity": 15,
                "MinCapacity": 5,
                "ResourceId": {
                    "Fn::Join": [
                        "/",
                        [
                            "table",
                            {
                                "Ref": "DDBTable"
                            }
                        ]
                    ]
                },
                "RoleARN" : { "Fn::Sub" : "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable" },
                "ScalableDimension": "dynamodb:table:WriteCapacityUnits",
                "ServiceNamespace": "dynamodb"
            }
        },
        "WriteScalingPolicy": {
            "Type": "AWS::ApplicationAutoScaling::ScalingPolicy",
            "Properties": {
                "PolicyName": "WriteAutoScalingPolicy",
                "PolicyType": "TargetTrackingScaling",
                "ScalingTargetId": {
                    "Ref": "WriteCapacityScalableTarget"
                },
                "TargetTrackingScalingPolicyConfiguration": {
                    "TargetValue": 50,
                    "ScaleInCooldown": 60,
                    "ScaleOutCooldown": 60,
                    "PredefinedMetricSpecification": {
                        "PredefinedMetricType": "DynamoDBWriteCapacityUtilization"
                    }
                }
            }
        }
    }
}
```

### YAML
<a name="quickref-dynamodb-example.yaml"></a>

```
Resources:
  DDBTable:
    Type: AWS::DynamoDB::Table
    Properties:
      AttributeDefinitions:
        - AttributeName: "ArtistId"
          AttributeType: "S"
        - AttributeName: "Concert"
          AttributeType: "S"
        - AttributeName: "TicketSales"
          AttributeType: "S"
      KeySchema:
        - AttributeName: "ArtistId"
          KeyType: "HASH"
        - AttributeName: "Concert"
          KeyType: "RANGE"
      GlobalSecondaryIndexes:
        - IndexName: "GSI"
          KeySchema:
            - AttributeName: "TicketSales"
              KeyType: "HASH"
          Projection:
            ProjectionType: "KEYS_ONLY"
          ProvisionedThroughput:
            ReadCapacityUnits: 5
            WriteCapacityUnits: 5
      ProvisionedThroughput:
        ReadCapacityUnits: 5
        WriteCapacityUnits: 5
  WriteCapacityScalableTarget:
    Type: AWS::ApplicationAutoScaling::ScalableTarget
    Properties:
      MaxCapacity: 15
      MinCapacity: 5
      ResourceId: !Join
        - /
        - - table
          - !Ref DDBTable
      RoleARN:
        Fn::Sub: 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable'
      ScalableDimension: dynamodb:table:WriteCapacityUnits
      ServiceNamespace: dynamodb
  WriteScalingPolicy:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    Properties:
      PolicyName: WriteAutoScalingPolicy
      PolicyType: TargetTrackingScaling
      ScalingTargetId: !Ref WriteCapacityScalableTarget
      TargetTrackingScalingPolicyConfiguration:
        TargetValue: 50.0
        ScaleInCooldown: 60
        ScaleOutCooldown: 60
        PredefinedMetricSpecification:
          PredefinedMetricType: DynamoDBWriteCapacityUtilization
```

## 另请参阅
<a name="w2aac11c41c39b7"></a>

有关更多信息，请参阅 Amazon 数据库博客文章 [How to use Amazon CloudFormation to configure auto scaling for DynamoDB tables and indexes](https://www.amazonaws.cn/blogs/database/how-to-use-aws-cloudformation-to-configure-auto-scaling-for-amazon-dynamodb-tables-and-indexes/)。

有关 DynamoDB 资源的更多信息，请参阅 [AWS::DynamoDB::Table](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-dynamodb-table.html)。

# Amazon EC2 CloudFormation 模板代码段
<a name="quickref-ec2"></a>

Amazon EC2 在 Amazon Web Services 云 中提供了可扩展的计算容量。您可以使用 Amazon EC2 启动所需数量的虚拟服务器，配置安全性和联网以及管理存储。这些虚拟服务器（称为实例）可以运行各种操作系统和应用程序，并且可以根据您的具体要求进行自定义。您可以利用 Amazon EC2 进行扩展或缩减，以便应对需求变化或使用高峰。

您可以使用 CloudFormation 模板定义和预置 Amazon EC2 实例作为基础设施的一部分。模板可以让您轻松地以可重复且一致的方式管理和自动部署 Amazon EC2 资源。

以下示例模板代码段描述了 Amazon EC2 的 CloudFormation 资源或组件。这些代码段旨在集成到模板中，不打算独立运行。

**Topics**
+ [配置 EC2 实例](quickref-ec2-instance-config.md)
+ [创建启动模板](quickref-ec2-launch-templates.md)
+ [管理安全组](quickref-ec2-sg.md)
+ [分配弹性 IP](quickref-ec2-elastic-ip.md)
+ [配置 VPC 资源](quickref-ec2-vpc.md)

# 使用 CloudFormation 配置 Amazon EC2 实例
<a name="quickref-ec2-instance-config"></a>

以下代码段演示了如何使用 CloudFormation 配置 Amazon EC2 实例。

**Topics**
+ [

## Amazon EC2 的常规配置
](#quickref-ec2-instance-config-general)
+ [

## 指定实例的块设备映射
](#scenario-ec2-bdm)

## Amazon EC2 的常规配置
<a name="quickref-ec2-instance-config-general"></a>

以下代码段演示了如何使用 CloudFormation 对 Amazon EC2 实例进行常规配置。

**Topics**
+ [

### 在指定的可用区中创建 Amazon EC2 实例
](#scenario-ec2-instance)
+ [

### 使用 EBS 卷和用户数据配置标记的 Amazon EC2 实例
](#scenario-ec2-instance-with-vol-and-tags)
+ [

### 在用户数据中定义 DynamoDB 表名用于启动 Amazon EC2 实例
](#scenario-ec2-with-sdb-domain)
+ [

### 使用 `DeletionPolicy` 创建 Amazon EBS 卷
](#scenario-ec2-volume)

### 在指定的可用区中创建 Amazon EC2 实例
<a name="scenario-ec2-instance"></a>

以下代码段使用 [AWS::EC2::Instance](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-instance.html) 资源在指定的可用区中创建 Amazon EC2 实例。可用区的代码由其区域代码后跟一个字母标识符组成。您可以在单个可用区中启动实例。

#### JSON
<a name="quickref-ec2-example-6.json"></a>

```
1. "Ec2Instance": {
2.     "Type": "AWS::EC2::Instance",
3.     "Properties": {
4.         "AvailabilityZone": "aa-example-1a",
5.         "ImageId": "ami-1234567890abcdef0"
6.     }
7. }
```

#### YAML
<a name="quickref-ec2-example-6.yaml"></a>

```
1. Ec2Instance:
2.   Type: AWS::EC2::Instance
3.   Properties:
4.     AvailabilityZone: aa-example-1a
5.     ImageId: ami-1234567890abcdef0
```

### 使用 EBS 卷和用户数据配置标记的 Amazon EC2 实例
<a name="scenario-ec2-instance-with-vol-and-tags"></a>

以下代码段使用标记、EBS 卷和用户数据创建了一个 Amazon EC2 实例。该实例使用 [AWS::EC2::Instance](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-instance.html) 资源。必须在同一个模板中定义 [AWS::EC2::SecurityGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html) 资源、[AWS::SNS::Topic](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sns-topic.html) 资源和 [AWS::EC2::Volume](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-volume.html) 资源。必须在模板的 `Parameters` 部分中定义 `KeyName`。

标签可帮助您按用途、拥有者或环境等首选项对 Amazon 资源进行分类。用户数据允许在启动期间向实例预置自定义脚本或数据。这些数据有助于实现任务自动化、软件配置、软件包安装以及初始化期间对实例执行的其他操作。

有关标记资源的更多信息，请参阅《Amazon EC2 用户指南》**中的[标记 Amazon EC2 资源](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/Using_Tags.html)。

有关用户数据的信息，请参阅《Amazon EC2 用户指南》中的[使用实例元数据管理 EC2 实例](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/ec2-instance-metadata.html)。**

#### JSON
<a name="quickref-ec2-example-7.json"></a>

```
 1. "Ec2Instance": {
 2.   "Type": "AWS::EC2::Instance",
 3.   "Properties": {
 4.     "KeyName": { "Ref": "KeyName" },
 5.     "SecurityGroups": [ { "Ref": "Ec2SecurityGroup" } ],
 6.     "UserData": {
 7.       "Fn::Base64": {
 8.         "Fn::Join": [ ":", [
 9.             "PORT=80",
10.             "TOPIC=",
11.             { "Ref": "MySNSTopic" }
12.           ]
13.         ]
14.       }
15.     },
16.     "InstanceType": "aa.size",
17.     "AvailabilityZone": "aa-example-1a",
18.     "ImageId": "ami-1234567890abcdef0",
19.     "Volumes": [
20.       {
21.         "VolumeId": { "Ref": "MyVolumeResource" },
22.         "Device": "/dev/sdk"
23.       }
24.     ],
25.     "Tags": [ { "Key": "Name", "Value": "MyTag" } ]
26.   }
27. }
```

#### YAML
<a name="quickref-ec2-example-7.yaml"></a>

```
 1. Ec2Instance:
 2.   Type: AWS::EC2::Instance
 3.   Properties:
 4.     KeyName: !Ref KeyName
 5.     SecurityGroups:
 6.       - !Ref Ec2SecurityGroup
 7.     UserData:
 8.       Fn::Base64:
 9.         Fn::Join:
10.           - ":"
11.           - - "PORT=80"
12.             - "TOPIC="
13.             - !Ref MySNSTopic
14.     InstanceType: aa.size
15.     AvailabilityZone: aa-example-1a
16.     ImageId: ami-1234567890abcdef0
17.     Volumes:
18.       - VolumeId: !Ref MyVolumeResource
19.         Device: "/dev/sdk"
20.     Tags:
21.       - Key: Name
22.         Value: MyTag
```

### 在用户数据中定义 DynamoDB 表名用于启动 Amazon EC2 实例
<a name="scenario-ec2-with-sdb-domain"></a>

以下代码段创建了一个 Amazon EC2 实例，并在用户数据中定义了一个 DynamoDB 表名，以便在启动时传递给实例。该实例使用 [AWS::EC2::Instance](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-instance.html) 资源。您可以在用户数据中定义参数或动态值，以便在启动时传递 EC2 实例。

有关用户数据的更多信息，请参阅《Amazon EC2 用户指南》中的[使用实例元数据管理 EC2 实例](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/ec2-instance-metadata.html)。**

#### JSON
<a name="quickref-ec2-example-8.json"></a>

```
 1. "Ec2Instance": {
 2.     "Type": "AWS::EC2::Instance",
 3.     "Properties": {
 4.         "UserData": {
 5.             "Fn::Base64": {
 6.                 "Fn::Join": [
 7.                     "",
 8.                     [
 9.                         "TableName=",
10.                         {
11.                             "Ref": "DynamoDBTableName"
12.                         }
13.                     ]
14.                 ]
15.             }
16.         },
17.         "AvailabilityZone": "aa-example-1a",
18.         "ImageId": "ami-1234567890abcdef0"
19.     }
20. }
```

#### YAML
<a name="quickref-ec2-example-8.yaml"></a>

```
 1. Ec2Instance:
 2.   Type: AWS::EC2::Instance
 3.   Properties:
 4.     UserData:
 5.       Fn::Base64:
 6.         Fn::Join:
 7.           - ''
 8.           - - 'TableName='
 9.             - Ref: DynamoDBTableName
10.     AvailabilityZone: aa-example-1a
11.     ImageId: ami-1234567890abcdef0
```

### 使用 `DeletionPolicy` 创建 Amazon EBS 卷
<a name="scenario-ec2-volume"></a>

以下代码段使用 Amazon EC2 [AWS::EC2::Volume](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-volume.html) 资源创建 Amazon EBS 卷。您可以使用 `Size` 或 `SnapshotID` 属性来定义卷，但不能同时使用两者。`DeletionPolicy` 属性设置为在删除堆栈时创建卷的快照。

有关 `DeletionPolicy` 属性的更多信息，请参阅 [DeletionPolicy 属性](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-attribute-deletionpolicy.html)。

有关创建 Amazon EBS 卷的更多信息，请参阅[创建 Amazon EBS 卷](https://docs.amazonaws.cn/ebs/latest/userguide/ebs-creating-volume.html)。

#### JSON
<a name="quickref-ec2-example-13.json"></a>

此代码段会创建具有指定**大小**的 Amazon EBS 卷。大小虽设置为 10，但可按需加以调整。[AWS::EC2::Volume](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-volume.html) 资源允许指定大小或快照 ID，但不允许同时指定这两者。

```
 1. "MyEBSVolume": {
 2.     "Type": "AWS::EC2::Volume",
 3.     "Properties": {
 4.         "Size": "10",
 5.         "AvailabilityZone": {
 6.             "Ref": "AvailabilityZone"
 7.         }
 8.     },
 9.     "DeletionPolicy": "Snapshot"
10. }
```

此代码段使用提供的**快照 ID** 创建一个 Amazon EBS 卷。[AWS::EC2::Volume](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-volume.html) 资源允许指定大小或快照 ID，但不允许同时指定这两者。

```
 1. "MyEBSVolume": {
 2.     "Type": "AWS::EC2::Volume",
 3.     "Properties": {
 4.         "SnapshotId" : "snap-1234567890abcdef0",
 5.         "AvailabilityZone": {
 6.             "Ref": "AvailabilityZone"
 7.         }
 8.     },
 9.     "DeletionPolicy": "Snapshot"
10. }
```

#### YAML
<a name="quickref-ec2-example-13.yaml"></a>

此代码段会创建具有指定**大小**的 Amazon EBS 卷。大小虽设置为 10，但可按需加以调整。[AWS::EC2::Volume](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-volume.html) 资源允许指定大小或快照 ID，但不允许同时指定这两者。

```
1. MyEBSVolume:
2.   Type: AWS::EC2::Volume
3.   Properties:
4.     Size: 10
5.     AvailabilityZone:
6.       Ref: AvailabilityZone
7.   DeletionPolicy: Snapshot
```

此代码段使用提供的**快照 ID** 创建一个 Amazon EBS 卷。[AWS::EC2::Volume](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-volume.html) 资源允许指定大小或快照 ID，但不允许同时指定这两者。

```
1. MyEBSVolume:
2.   Type: AWS::EC2::Volume
3.   Properties:
4.     SnapshotId: snap-1234567890abcdef0
5.     AvailabilityZone:
6.       Ref: AvailabilityZone
7.   DeletionPolicy: Snapshot
```

## 指定实例的块设备映射
<a name="scenario-ec2-bdm"></a>

块设备映射定义了挂载到某个实例的块设备（包含实例存储卷和 EBS 卷）。您可以在创建 AMI 时指定块设备映射，以便让从该 AMI 启动的所有实例都可使用该映射。另外，您可以在启动实例时指定块设备映射，这样该映射会覆盖您从启动实例的 AMI 中指定的块设备映射。

您可以使用以下模板代码段中 [AWS::EC2::Instance](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-instance.html) 资源的 `BlockDeviceMappings` 属性，为 EBS 或实例存储卷指定块设备映射。

有关块设备映射的更多信息，请参阅《Amazon EC2 用户指南》**中的 [Amazon EC2 实例上卷的块设备映射](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html)。

**Topics**
+ [

### 为两个 EBS 卷指定块设备映射
](#w2aac11c41c43c13b9c11)
+ [

### 为实例存储卷指定块设备映射
](#w2aac11c41c43c13b9c13)

### 为两个 EBS 卷指定块设备映射
<a name="w2aac11c41c43c13b9c11"></a>

#### JSON
<a name="quickref-ec2-example-1.json"></a>

```
"Ec2Instance": {
    "Type": "AWS::EC2::Instance",
    "Properties": {
      "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}",
      "KeyName": { "Ref": "KeyName" },
      "InstanceType": { "Ref": "InstanceType" },
      "SecurityGroups": [{ "Ref": "Ec2SecurityGroup" }],
      "BlockDeviceMappings": [
        {
          "DeviceName": "/dev/sda1",
          "Ebs": { "VolumeSize": "50" }
        },
        {
          "DeviceName": "/dev/sdm",
          "Ebs": { "VolumeSize": "100" }
        }
      ]
    }
  }
}
```

#### YAML
<a name="quickref-ec2-example-1.yaml"></a>

```
EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}'
      KeyName: !Ref KeyName
      InstanceType: !Ref InstanceType
      SecurityGroups:
        - !Ref Ec2SecurityGroup
      BlockDeviceMappings:
        -
          DeviceName: /dev/sda1
          Ebs:
            VolumeSize: 50
        -
          DeviceName: /dev/sdm
          Ebs:
            VolumeSize: 100
```

### 为实例存储卷指定块设备映射
<a name="w2aac11c41c43c13b9c13"></a>

#### JSON
<a name="quickref-ec2-example-2.json"></a>

```
"Ec2Instance" : {
  "Type" : "AWS::EC2::Instance", 
  "Properties" : {
    "ImageId" : "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}",
    "KeyName" : { "Ref" : "KeyName" },
    "InstanceType": { "Ref": "InstanceType" },
    "SecurityGroups" : [{ "Ref" : "Ec2SecurityGroup" }],
    "BlockDeviceMappings" : [
      {
        "DeviceName"  : "/dev/sdc",
        "VirtualName" : "ephemeral0"
      }
    ]
  }
}
```

#### YAML
<a name="quickref-ec2-example-2.yaml"></a>

```
EC2Instance:
  Type: AWS::EC2::Instance
  Properties:
    ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}'
    KeyName: !Ref KeyName
    InstanceType: !Ref InstanceType
    SecurityGroups:
      - !Ref Ec2SecurityGroup
    BlockDeviceMappings:
      - DeviceName: /dev/sdc
        VirtualName: ephemeral0
```

# 使用 CloudFormation 创建启动模板
<a name="quickref-ec2-launch-templates"></a>

本节提供了使用 CloudFormation 创建 Amazon EC2 启动模板的示例。启动模板允许您创建用于在 Amazon 中配置和预置 Amazon EC2 实例的模板。通过启动模板，您可以存储启动参数，而无需在每次启动实例时都指定这些参数。有关更多示例，请参阅 `AWS::EC2::LaunchTemplate` 资源中的[示例](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html#aws-resource-ec2-launchtemplate--examples)部分。

有关启动模板的更多信息，请参阅《Amazon EC2 用户指南》**中的[在 Amazon EC2 启动模板中存储实例启动参数](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/ec2-launch-templates.html)。

有关创建启动模板用于自动扩缩组的信息，请参阅《Amazon EC2 Auto Scaling User Guide》**中的 [Auto Scaling launch templates](https://docs.amazonaws.cn/autoscaling/ec2/userguide/launch-templates.html)。

**Topics**
+ [

## 创建指定安全组、标签、用户数据和 IAM 角色的启动模板
](#scenario-as-launch-template)

## 创建指定安全组、标签、用户数据和 IAM 角色的启动模板
<a name="scenario-as-launch-template"></a>

此代码段显示 [AWS::EC2::LaunchTemplate](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html) 资源，其中包含启动实例的配置信息。您可以为 `ImageId`、`InstanceType`、`SecurityGroups`、`UserData` 和 `TagSpecifications` 属性指定值。`SecurityGroups` 属性会指定一个现有 EC2 安全组和一个新安全组。`Ref` 函数会获取在堆栈模板中其他位置声明的 [AWS::EC2::SecurityGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html) 资源 `myNewEC2SecurityGroup` 的 ID。

启动模板包括自定义用户数据的部分。在本节中，您可以传入实例启动时运行的配置任务和脚本。在此示例中，用户数据安装 Amazon Systems Manager 代理并启动该代理。

启动模板还包含一个 IAM 角色，该角色允许在实例上运行的应用程序代表您执行操作。此示例显示启动模板的 [AWS::IAM::Role](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-role.html) 资源，其使用 `IamInstanceProfile` 属性来指定 IAM 角色。`Ref` 函数会获取 [AWS::IAM::InstanceProfile](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-instanceprofile.html) 资源 `myInstanceProfile` 的名称。要配置 IAM 角色的权限，请指定 `ManagedPolicyArns` 属性的值。

### JSON
<a name="quickref-launch-template-example-1.json"></a>

```
 1. {
 2.   "Resources":{
 3.     "myLaunchTemplate":{
 4.       "Type":"AWS::EC2::LaunchTemplate",
 5.       "Properties":{
 6.         "LaunchTemplateName":{ "Fn::Sub": "${AWS::StackName}-launch-template" },
 7.         "LaunchTemplateData":{
 8.           "ImageId":"ami-02354e95b3example",
 9.           "InstanceType":"t3.micro",
10.           "IamInstanceProfile":{
11.             "Name":{
12.               "Ref":"myInstanceProfile"
13.             }
14.           },
15.           "SecurityGroupIds":[
16.             {
17.               "Ref":"myNewEC2SecurityGroup"
18.             },
19.             "sg-083cd3bfb8example"
20.           ],
21.           "UserData":{
22.             "Fn::Base64":{
23.               "Fn::Join": [
24.                 "", [
25.                   "#!/bin/bash\n",
26.                   "cd /tmp\n",
27.                   "yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm\n",
28.                   "systemctl enable amazon-ssm-agent\n",
29.                   "systemctl start amazon-ssm-agent\n"
30.                 ]
31.               ]
32.             }
33.           },
34.           "TagSpecifications":[
35.             {
36.               "ResourceType":"instance",
37.               "Tags":[
38.                 {
39.                   "Key":"environment",
40.                   "Value":"development"
41.                 }
42.               ]
43.             },
44.             {
45.               "ResourceType":"volume",
46.               "Tags":[
47.                 {
48.                   "Key":"environment",
49.                   "Value":"development"
50.                 }
51.               ]
52.             }
53.           ]
54.         }
55.       }
56.     },
57.     "myInstanceRole":{
58.       "Type":"AWS::IAM::Role",
59.       "Properties":{
60.         "RoleName":"InstanceRole",
61.         "AssumeRolePolicyDocument":{
62.           "Version": "2012-10-17",		 	 	 
63.           "Statement":[
64.             {
65.               "Effect":"Allow",
66.               "Principal":{
67.                 "Service":[
68.                   "ec2.amazonaws.com"
69.                 ]
70.               },
71.               "Action":[
72.                 "sts:AssumeRole"
73.               ]
74.             }
75.           ]
76.         },
77.         "ManagedPolicyArns":[
78.           "arn:aws:iam::aws:policy/myCustomerManagedPolicy"
79.         ]
80.       }
81.     },
82.     "myInstanceProfile":{
83.       "Type":"AWS::IAM::InstanceProfile",
84.       "Properties":{
85.         "Path":"/",
86.         "Roles":[
87.           {
88.             "Ref":"myInstanceRole"
89.           }
90.         ]
91.       }
92.     }
93.   }
94. }
```

### YAML
<a name="quickref-launch-template-example-1.yaml"></a>

```
 1. ---
 2. Resources:
 3.   myLaunchTemplate:
 4.     Type: AWS::EC2::LaunchTemplate
 5.     Properties:
 6.       LaunchTemplateName: !Sub ${AWS::StackName}-launch-template
 7.       LaunchTemplateData:
 8.         ImageId: ami-02354e95b3example
 9.         InstanceType: t3.micro
10.         IamInstanceProfile:
11.           Name: !Ref myInstanceProfile
12.         SecurityGroupIds:
13.         - !Ref myNewEC2SecurityGroup
14.         - sg-083cd3bfb8example
15.         UserData:
16.           Fn::Base64: !Sub |
17.             #!/bin/bash
18.             cd /tmp
19.             yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
20.             systemctl enable amazon-ssm-agent
21.             systemctl start amazon-ssm-agent
22.         TagSpecifications:
23.         - ResourceType: instance
24.           Tags:
25.           - Key: environment
26.             Value: development
27.         - ResourceType: volume
28.           Tags:
29.           - Key: environment
30.             Value: development
31.   myInstanceRole:
32.     Type: AWS::IAM::Role
33.     Properties:
34.       RoleName: InstanceRole
35.       AssumeRolePolicyDocument:
36.         Version: '2012-10-17'
37.         Statement:
38.         - Effect: 'Allow'
39.           Principal:
40.             Service:
41.             - 'ec2.amazonaws.com'
42.           Action:
43.           - 'sts:AssumeRole'
44.       ManagedPolicyArns:
45.         - 'arn:aws:iam::aws:policy/myCustomerManagedPolicy'
46.   myInstanceProfile:
47.     Type: AWS::IAM::InstanceProfile
48.     Properties:
49.       Path: '/'
50.       Roles:
51.       - !Ref myInstanceRole
```

# 使用 CloudFormation 管理安全组
<a name="quickref-ec2-sg"></a>

以下代码段演示了如何使用 CloudFormation 管理安全组和 Amazon EC2 实例，从而控制对 Amazon 资源的访问权限。

**Topics**
+ [

## 将 Amazon EC2 实例与安全组关联
](#quickref-ec2-instances-associate-security-group)
+ [

## 使用入口规则创建安全组
](#quickref-ec2-instances-ingress)
+ [

## 使用安全组入口规则创建弹性负载均衡器
](#scenario-ec2-security-group-elbingress)

## 将 Amazon EC2 实例与安全组关联
<a name="quickref-ec2-instances-associate-security-group"></a>

以下示例代码段演示了如何使用 CloudFormation 将 Amazon EC2 实例与默认的 Amazon VPC 安全组关联起来。

**Topics**
+ [

### 将 Amazon EC2 实例与默认 VPC 安全组关联
](#using-cfn-getatt-default-values)
+ [

### 创建带有附加卷和安全组的 Amazon EC2 实例
](#scenario-ec2-volumeattachment)

### 将 Amazon EC2 实例与默认 VPC 安全组关联
<a name="using-cfn-getatt-default-values"></a>

以下代码段创建了一个 Amazon VPC、一个 VPC 内的子网和一个 Amazon EC2 实例。VPC 是使用 [AWS::EC2::VPC](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-vpc.html) 资源创建的。VPC 的 IP 地址范围在较大的模板中定义并由 `MyVPCCIDRRange` 参数引用。

子网是使用 [AWS::EC2:: Subnet](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-subnet.html) 资源在 VPC 中创建的。子网与 VPC 关联，后者被引用为 `MyVPC`。

使用 [AWS::EC2::Instance](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-instance.html) 资源在 VPC 和子网内启动 EC2 实例。此资源指定用于启动实例的亚马逊机器映像（AMI）、实例将在其中运行的子网以及要与该实例关联的安全组。`ImageId` 使用 Systems Manager 参数动态检索最新的 Amazon Linux 2 AMI。

安全组 ID 是使用 `Fn::GetAtt` 函数获取的，该函数从 `MyVPC` 资源中检索默认安全组。

该实例位于代码段中定义的 `MySubnet` 资源中。

使用 CloudFormation 创建 VPC 时，Amazon 会在 VPC 中自动创建默认资源，包括默认安全组。但是，当您在 CloudFormation 模板中定义 VPC 时，可能无法在创建模板时访问这些默认资源的 ID。要访问和使用模板中指定的默认资源，您可以使用内置函数，例如 `Fn::GetAtt`。此函数允许您使用由 CloudFormation 自动创建的默认资源。

#### JSON
<a name="quickref-ec2-example-15.json"></a>

```
"MyVPC": {
    "Type": "AWS::EC2::VPC",
    "Properties": {
        "CidrBlock": {
            "Ref": "MyVPCCIDRRange"
        },
        "EnableDnsSupport": false,
        "EnableDnsHostnames": false,
        "InstanceTenancy": "default"
    }
},
"MySubnet": {
    "Type": "AWS::EC2::Subnet",
    "Properties": {
        "CidrBlock": {
            "Ref": "MyVPCCIDRRange"
        },
        "VpcId": {
            "Ref": "MyVPC"
        }
    }
},
"MyInstance": {
    "Type": "AWS::EC2::Instance",
    "Properties": {
        "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}",
        "SecurityGroupIds": [
            {
                "Fn::GetAtt": [
                    "MyVPC",
                    "DefaultSecurityGroup"
                ]
            }
        ],
        "SubnetId": {
            "Ref": "MySubnet"
        }
    }
}
```

#### YAML
<a name="quickref-ec2-example-15.yaml"></a>

```
MyVPC:
  Type: AWS::EC2::VPC
  Properties:
    CidrBlock:
      Ref: MyVPCCIDRRange
    EnableDnsSupport: false
    EnableDnsHostnames: false
    InstanceTenancy: default
MySubnet:
  Type: AWS::EC2::Subnet
  Properties:
    CidrBlock:
      Ref: MyVPCCIDRRange
    VpcId:
      Ref: MyVPC
MyInstance:
  Type: AWS::EC2::Instance
  Properties:
    ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}'
    SecurityGroupIds:
      - Fn::GetAtt:
          - MyVPC
          - DefaultSecurityGroup
    SubnetId:
      Ref: MySubnet
```

### 创建带有附加卷和安全组的 Amazon EC2 实例
<a name="scenario-ec2-volumeattachment"></a>

以下代码段使用从指定 AMI 启动的 [AWS::EC2::Instance](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-instance.html) 资源创建 Amazon EC2 实例。该实例与一个安全组关联，该安全组使用 [AWS::EC2::SecurityGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html) 资源允许来自指定 IP 地址端口 22 上的传入 SSH 流量。它使用 [AWS::EC2::Volume](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-volume.html) 资源创建一个 100GB 的 Amazon EBS 卷。根据 `GetAtt` 函数的指定，这个卷在与实例相同的可用区中创建，并安装到 `/dev/sdh` 设备上的实例。

有关创建 Amazon EBS 卷的更多信息，请参阅[创建 Amazon EBS 卷](https://docs.amazonaws.cn/ebs/latest/userguide/ebs-creating-volume.html)。

#### JSON
<a name="quickref-ec2-example-14.json"></a>

```
 1. "Ec2Instance": {
 2.     "Type": "AWS::EC2::Instance",
 3.     "Properties": {
 4.         "SecurityGroups": [
 5.             {
 6.                 "Ref": "InstanceSecurityGroup"
 7.             }
 8.         ],
 9.         "ImageId": "ami-1234567890abcdef0"
10.     }
11. },
12. "InstanceSecurityGroup": {
13.     "Type": "AWS::EC2::SecurityGroup",
14.     "Properties": {
15.         "GroupDescription": "Enable SSH access via port 22",
16.         "SecurityGroupIngress": [
17.             {
18.                 "IpProtocol": "tcp",
19.                 "FromPort": "22",
20.                 "ToPort": "22",
21.                 "CidrIp": "192.0.2.0/24"
22.             }
23.         ]
24.     }
25. },
26. "NewVolume": {
27.     "Type": "AWS::EC2::Volume",
28.     "Properties": {
29.         "Size": "100",
30.         "AvailabilityZone": {
31.             "Fn::GetAtt": [
32.                 "Ec2Instance",
33.                 "AvailabilityZone"
34.             ]
35.         }
36.     }
37. },
38. "MountPoint": {
39.     "Type": "AWS::EC2::VolumeAttachment",
40.     "Properties": {
41.         "InstanceId": {
42.             "Ref": "Ec2Instance"
43.         },
44.         "VolumeId": {
45.             "Ref": "NewVolume"
46.         },
47.         "Device": "/dev/sdh"
48.     }
49. }
```

#### YAML
<a name="quickref-ec2-example-14.yaml"></a>

```
 1. Ec2Instance:
 2.   Type: AWS::EC2::Instance
 3.   Properties:
 4.     SecurityGroups:
 5.       - !Ref InstanceSecurityGroup
 6.     ImageId: ami-1234567890abcdef0
 7. InstanceSecurityGroup:
 8.   Type: AWS::EC2::SecurityGroup
 9.   Properties:
10.     GroupDescription: Enable SSH access via port 22
11.     SecurityGroupIngress:
12.       - IpProtocol: tcp
13.         FromPort: 22
14.         ToPort: 22
15.         CidrIp: 192.0.2.0/24
16. NewVolume:
17.   Type: AWS::EC2::Volume
18.   Properties:
19.     Size: 100
20.     AvailabilityZone: !GetAtt [Ec2Instance, AvailabilityZone]
21. MountPoint:
22.   Type: AWS::EC2::VolumeAttachment
23.   Properties:
24.     InstanceId: !Ref Ec2Instance
25.     VolumeId: !Ref NewVolume
26.     Device: /dev/sdh
```

## 使用入口规则创建安全组
<a name="quickref-ec2-instances-ingress"></a>

以下示例代码段演示了如何使用 CloudFormation 配置具有特定入口规则的安全组。

**Topics**
+ [

### 使用入口规则创建安全组以允许 SSH 和 HTTP 访问
](#scenario-ec2-security-group-rule)
+ [

### 使用入口规则创建安全组以允许来自指定 CIDR 范围的 HTTP 和 SSH 访问
](#scenario-ec2-security-group-two-ports)
+ [

### 使用入口规则创建交叉引用安全组
](#scenario-ec2-security-group-ingress)

### 使用入口规则创建安全组以允许 SSH 和 HTTP 访问
<a name="scenario-ec2-security-group-rule"></a>

以下代码段描述了两个使用 [AWS::EC2::SecurityGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html) 资源的安全组入口规则。第一个入口规则允许从名为 `MyAdminSecurityGroup` 的现有安全组访问 SSH（端口 22），该安全组由账号为 `1111-2222-3333` 的 Amazon 账户所有。第二个入口规则允许从名为 `MySecurityGroupCreatedInCFN` 的另一个安全组访问 HTTP（端口 80），该安全组是在同一个模板中创建的。`Ref` 函数用于引用在同一模板中创建的安全组的逻辑名称。

在第一个入口规则中，必须为 `SourceSecurityGroupName` 和 `SourceSecurityGroupOwnerId` 属性添加一个值。在第二个入口规则中，`MySecurityGroupCreatedInCFNTemplate` 引用了在同一个模板中创建的另一个安全组。验证逻辑名称 `MySecurityGroupCreatedInCFNTemplate` 是否与您在较大模板中指定的安全组资源的实际逻辑名称相匹配。

有关安全组的更多信息，请参阅《Amazon EC2 用户指南》**中的 [Amazon EC2 实例的 Amazon EC2 安全组](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/ec2-security-groups.html)。

#### JSON
<a name="quickref-ec2-example-10.json"></a>

```
 1. "SecurityGroup": {
 2.     "Type": "AWS::EC2::SecurityGroup",
 3.     "Properties": {
 4.         "GroupDescription": "Allow connections from specified source security group",
 5.         "SecurityGroupIngress": [
 6.             {
 7.                 "IpProtocol": "tcp",
 8.                 "FromPort": "22",
 9.                 "ToPort": "22",
10.                 "SourceSecurityGroupName": "MyAdminSecurityGroup",
11.                 "SourceSecurityGroupOwnerId": "1111-2222-3333"
12.             },
13.             {
14.                 "IpProtocol": "tcp",
15.                 "FromPort": "80",
16.                 "ToPort": "80",
17.                 "SourceSecurityGroupName": {
18.                     "Ref": "MySecurityGroupCreatedInCFNTemplate"
19.                 }
20.             }
21.         ]
22.     }
23. }
```

#### YAML
<a name="quickref-ec2-example-10.yaml"></a>

```
 1. SecurityGroup:
 2.   Type: AWS::EC2::SecurityGroup
 3.   Properties:
 4.     GroupDescription: Allow connections from specified source security group
 5.     SecurityGroupIngress:
 6.       - IpProtocol: tcp
 7.         FromPort: '22'
 8.         ToPort: '22'
 9.         SourceSecurityGroupName: MyAdminSecurityGroup
10.         SourceSecurityGroupOwnerId: '1111-2222-3333'
11.       - IpProtocol: tcp
12.         FromPort: '80'
13.         ToPort: '80'
14.         SourceSecurityGroupName:
15.           Ref: MySecurityGroupCreatedInCFNTemplate
```

### 使用入口规则创建安全组以允许来自指定 CIDR 范围的 HTTP 和 SSH 访问
<a name="scenario-ec2-security-group-two-ports"></a>

以下代码段为具有两个入站规则的 Amazon EC2 实例创建了一个安全组。入站规则允许来自指定 CIDR 范围指定端口上的传入 TCP 流量。[AWS::EC2::SecurityGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html) 资源用于指定规则。您必须为每个规则指定一个协议。对于 TCP，您必须指定端口或端口范围。如果未指定源安全组或 CIDR 范围，堆栈虽会成功启动，但规则不会应用于安全组。

有关安全组的更多信息，请参阅《Amazon EC2 用户指南》**中的 [Amazon EC2 实例的 Amazon EC2 安全组](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/ec2-security-groups.html)。

#### JSON
<a name="quickref-ec2-example-9.json"></a>

```
 1. "ServerSecurityGroup": {
 2.   "Type": "AWS::EC2::SecurityGroup",
 3.   "Properties": {
 4.     "GroupDescription": "Allow connections from specified CIDR ranges",
 5.     "SecurityGroupIngress": [
 6.       {
 7.         "IpProtocol": "tcp",
 8.         "FromPort": "80",
 9.         "ToPort": "80",
10.         "CidrIp": "192.0.2.0/24"
11.       },
12.       {
13.         "IpProtocol": "tcp",
14.         "FromPort": "22",
15.         "ToPort": "22",
16.         "CidrIp": "192.0.2.0/24"
17.       }
18.     ]
19.   }
20. }
```

#### YAML
<a name="quickref-ec2-example-9.yaml"></a>

```
 1. ServerSecurityGroup:
 2.   Type: AWS::EC2::SecurityGroup
 3.   Properties:
 4.     GroupDescription: Allow connections from specified CIDR ranges
 5.     SecurityGroupIngress:
 6.       - IpProtocol: tcp
 7.         FromPort: 80
 8.         ToPort: 80
 9.         CidrIp: 192.0.2.0/24
10.       - IpProtocol: tcp
11.         FromPort: 22
12.         ToPort: 22
13.         CidrIp: 192.0.2.0/24
```

### 使用入口规则创建交叉引用安全组
<a name="scenario-ec2-security-group-ingress"></a>

以下代码段使用 [AWS::EC2::SecurityGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html) 资源创建两个 Amazon EC2 安全组：`SGroup1` 和 `SGroup2`。允许在两个安全组之间通信的入口规则是使用 [AWS::EC2::SecurityGroupIngress](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroupingress.html) 资源创建的。`SGroup1Ingress` 为 `SGroup1` 建立了一个入口规则，允许来自源安全组 `SGroup2` 端口 80 上的传入 TCP 流量。`SGroup2Ingress` 为 `SGroup2` 建立了一个入口规则，允许来自源安全组 `SGroup1` 端口 80 上的传入 TCP 流量。

#### JSON
<a name="quickref-ec2-example-12.json"></a>

```
 1. "SGroup1": {
 2.     "Type": "AWS::EC2::SecurityGroup",
 3.     "Properties": {
 4.         "GroupDescription": "EC2 instance access"
 5.     }
 6. },
 7. "SGroup2": {
 8.     "Type": "AWS::EC2::SecurityGroup",
 9.     "Properties": {
10.         "GroupDescription": "EC2 instance access"
11.     }
12. },
13. "SGroup1Ingress": {
14.     "Type": "AWS::EC2::SecurityGroupIngress",
15.     "Properties": {
16.         "GroupName": {
17.             "Ref": "SGroup1"
18.         },
19.         "IpProtocol": "tcp",
20.         "ToPort": "80",
21.         "FromPort": "80",
22.         "SourceSecurityGroupName": {
23.             "Ref": "SGroup2"
24.         }
25.     }
26. },
27. "SGroup2Ingress": {
28.     "Type": "AWS::EC2::SecurityGroupIngress",
29.     "Properties": {
30.         "GroupName": {
31.             "Ref": "SGroup2"
32.         },
33.         "IpProtocol": "tcp",
34.         "ToPort": "80",
35.         "FromPort": "80",
36.         "SourceSecurityGroupName": {
37.             "Ref": "SGroup1"
38.         }
39.     }
40. }
```

#### YAML
<a name="quickref-ec2-example-12.yaml"></a>

```
 1. SGroup1:
 2.   Type: AWS::EC2::SecurityGroup
 3.   Properties:
 4.     GroupDescription: EC2 Instance access
 5. SGroup2:
 6.   Type: AWS::EC2::SecurityGroup
 7.   Properties:
 8.     GroupDescription: EC2 Instance access
 9. SGroup1Ingress:
10.   Type: AWS::EC2::SecurityGroupIngress
11.   Properties:
12.     GroupName: !Ref SGroup1
13.     IpProtocol: tcp
14.     ToPort: 80
15.     FromPort: 80
16.     SourceSecurityGroupName: !Ref SGroup2
17. SGroup2Ingress:
18.   Type: AWS::EC2::SecurityGroupIngress
19.   Properties:
20.     GroupName: !Ref SGroup2
21.     IpProtocol: tcp
22.     ToPort: 80
23.     FromPort: 80
24.     SourceSecurityGroupName: !Ref SGroup1
```

## 使用安全组入口规则创建弹性负载均衡器
<a name="scenario-ec2-security-group-elbingress"></a>

以下模板在指定的可用区中创建了 [AWS::ElasticLoadBalancing::LoadBalancer](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancing-loadbalancer.html) 资源。[AWS::ElasticLoadBalancing::LoadBalancer](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancing-loadbalancer.html) 资源配置为在端口 80 上侦听 HTTP 流量，并将请求定向到端口 80 上的实例。弹性负载均衡器负责对实例间传入的 HTTP 流量进行负载均衡。

 此外，此模板将生成一个与负载均衡器关联的 [AWS::EC2::SecurityGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html) 资源。此安全组是使用单个入口规则（描述为 `ELB ingress group`）创建的，该规则允许端口 80 上的传入 TCP 流量。此入口规则的来源是使用从负载均衡器资源检索属性的 `Fn::GetAtt` 函数定义的。`SourceSecurityGroupOwnerId` 使用 `Fn::GetAtt` 来获取负载均衡器源安全组的 `OwnerAlias`。`SourceSecurityGroupName` 使用 `Fn::Getatt` 来获取 ELB 源安全组的 `GroupName`。

此设置可确保 ELB 和实例之间的安全通信。

有关负载均衡的更多信息，请参阅 [Elastic Load Balancing 用户指南](https://docs.amazonaws.cn/elasticloadbalancing/latest/userguide/)。

### JSON
<a name="quickref-ec2-example-11.json"></a>

```
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Resources": {
        "MyELB": {
            "Type": "AWS::ElasticLoadBalancing::LoadBalancer",
            "Properties": {
                "AvailabilityZones": [
                    "aa-example-1a"
                ],
                "Listeners": [
                    {
                        "LoadBalancerPort": "80",
                        "InstancePort": "80",
                        "Protocol": "HTTP"
                    }
                ]
            }
        },
        "MyELBIngressGroup": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": "ELB ingress group",
                "SecurityGroupIngress": [
                    {
                        "IpProtocol": "tcp",
                        "FromPort": 80,
                        "ToPort": 80,
                        "SourceSecurityGroupOwnerId": {
                            "Fn::GetAtt": [
                                "MyELB",
                                "SourceSecurityGroup.OwnerAlias"
                            ]
                        },
                        "SourceSecurityGroupName": {
                            "Fn::GetAtt": [
                                "MyELB",
                                "SourceSecurityGroup.GroupName"
                            ]
                        }
                    }
                ]
            }
        }
    }
}
```

### YAML
<a name="quickref-ec2-example-11.yaml"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  MyELB:
    Type: AWS::ElasticLoadBalancing::LoadBalancer
    Properties:
      AvailabilityZones:
        - aa-example-1a
      Listeners:
        - LoadBalancerPort: '80'
          InstancePort: '80'
          Protocol: HTTP
  MyELBIngressGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: ELB ingress group
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '80'
          ToPort: '80'
          SourceSecurityGroupOwnerId:
            Fn::GetAtt:
              - MyELB
              - SourceSecurityGroup.OwnerAlias
          SourceSecurityGroupName:
            Fn::GetAtt:
              - MyELB
              - SourceSecurityGroup.GroupName
```

# 分配弹性 IP 地址并将其与 CloudFormation 关联
<a name="quickref-ec2-elastic-ip"></a>

以下模板代码段展示了与 Amazon EC2 中的弹性 IP 地址（EIP）相关的示例。这些示例涵盖您实例的 EIP 分配、关联和管理。

**Topics**
+ [

## 分配弹性 IP 地址并将其与 Amazon EC2 实例关联
](#scenario-ec2-eip)
+ [

## 通过指定 IP 地址将弹性 IP 地址与 Amazon EC2 实例关联
](#scenario-ec2-eip-association)
+ [

## 通过指定 IP 地址的分配 ID 将弹性 IP 地址与 Amazon EC2 实例关联
](#scenario-ec2-eip-association-vpc)

## 分配弹性 IP 地址并将其与 Amazon EC2 实例关联
<a name="scenario-ec2-eip"></a>

以下代码段分配一个 Amazon EC2 弹性 IP（EIP）地址并将其与使用 [AWS::EC2::EIP](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-eip.html) 资源的 Amazon EC2 实例关联。使用[自带 IP 地址（BYOIP）](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/ec2-byoip.html)，您可以从 Amazon 拥有的地址池或从公共 IPv4 地址范围（您引入到 Amazon 中以与 Amazon 资源一起使用的地址范围）创建的地址池中分配 EIP 地址。在本示例中，EIP 是从 Amazon 拥有的地址池中分配的。

有关弹性 IP 地址的更多信息，请参阅《Amazon EC2 用户指南》**中的[弹性 IP 地址](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html)。

### JSON
<a name="quickref-ec2-example-3.json"></a>

```
1. "ElasticIP": {
2.     "Type": "AWS::EC2::EIP",
3.     "Properties": {
4.         "InstanceId": {
5.             "Ref": "Ec2Instance"
6.         }
7.     }
8. }
```

### YAML
<a name="quickref-ec2-example-3.yaml"></a>

```
1. ElasticIP:
2.   Type: AWS::EC2::EIP
3.   Properties:
4.     InstanceId: !Ref EC2Instance
```

## 通过指定 IP 地址将弹性 IP 地址与 Amazon EC2 实例关联
<a name="scenario-ec2-eip-association"></a>

以下代码段使用 [AWS::EC2::EIPAssociation](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-eipassociation.html) 资源将现有的 Amazon EC2 弹性 IP 地址与 EC2 实例关联。您必须先分配一个弹性 IP 地址，才能在自己的账户中使用。弹性 IP 地址可以与单个实例关联。

### JSON
<a name="quickref-ec2-example-4.json"></a>

```
1. "IPAssoc": {
2.   "Type": "AWS::EC2::EIPAssociation",
3.   "Properties": {
4.     "InstanceId": {
5.       "Ref": "Ec2Instance"
6.     },
7.     "EIP": "192.0.2.0"
8.   }
9. }
```

### YAML
<a name="quickref-ec2-example-4.yaml"></a>

```
1. IPAssoc:
2.   Type: AWS::EC2::EIPAssociation
3.   Properties:
4.     InstanceId: !Ref EC2Instance
5.     EIP: 192.0.2.0
```

## 通过指定 IP 地址的分配 ID 将弹性 IP 地址与 Amazon EC2 实例关联
<a name="scenario-ec2-eip-association-vpc"></a>

以下代码段使用 [AWS::EC2::EIPAssociation](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-eipassociation.html) 资源指定分配 ID，将现有的弹性 IP 地址与 Amazon EC2 实例关联。分配弹性 IP 地址时，即会为弹性 IP 地址分配一个分配 ID。

### JSON
<a name="quickref-ec2-example-5.json"></a>

```
1. "IPAssoc": {
2.     "Type": "AWS::EC2::EIPAssociation",
3.     "Properties": {
4.         "InstanceId": {
5.             "Ref": "Ec2Instance"
6.         },
7.         "AllocationId": "eipalloc-1234567890abcdef0"
8.     }
9. }
```

### YAML
<a name="quickref-ec2-example-5.yaml"></a>

```
1. IPAssoc:
2.   Type: AWS::EC2::EIPAssociation
3.   Properties:
4.     InstanceId: !Ref EC2Instance
5.     AllocationId: eipalloc-1234567890abcdef0
```

# 使用 CloudFormation 配置 Amazon VPC 资源
<a name="quickref-ec2-vpc"></a>

本节提供使用 CloudFormation 配置 Amazon VPC 资源的示例。VPC 允许您在 Amazon 中创建一个虚拟网络，这些代码段展示了如何配置 VPC 各个方面来满足自己的网络要求。

**Topics**
+ [

## 在 VPC 中启用 IPv6 仅出口互联网访问
](#quickref-ec2-route-egressonlyinternetgateway)
+ [

## 弹性网络接口 (ENI) 模板代码段
](#cfn-template-snippets-eni)

## 在 VPC 中启用 IPv6 仅出口互联网访问
<a name="quickref-ec2-route-egressonlyinternetgateway"></a>

仅出口互联网网关允许 VPC 中的实例访问互联网并阻止互联网上的资源与实例通信。以下代码段支持在 VPC 中启用 IPv6 仅出口互联网访问。它使用 [AWS::EC2::VPC](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-vpc.html) 资源创建 IPv4 地址范围为 `10.0.0/16` 的 VPC。将路由表与使用 [AWS::EC2::RouteTable](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-routetable.html) 资源的 VPC 资源关联起来。路由表会管理 VPC 内实例的路由。[AWS::EC2::EgressOnlyInternetGateway](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-egressonlyinternetgateway.html) 用于创建仅出口互联网网关，为来自 VPC 中实例的出站流量启用 IPv6 通信，同时阻止入站流量。[AWS::EC2::Route](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-route.html) 资源用于在路由表中创建 IPv6 路由，该路由会将所有出站 IPv6 流量 (`::/0`) 定向到仅出口互联网网关。

有关仅出口互联网网关的更多信息，请参阅《Amazon VPC 用户指南》**中的[使用仅出口互联网网关允许出站 IPv6 流量](https://docs.amazonaws.cn/vpc/latest/userguide/egress-only-internet-gateway.html)。

### JSON
<a name="quickref-ec2-example-16.json"></a>

```
"DefaultIpv6Route": {
    "Type": "AWS::EC2::Route",
    "Properties": {
        "DestinationIpv6CidrBlock": "::/0",
        "EgressOnlyInternetGatewayId": {
            "Ref": "EgressOnlyInternetGateway"
        },
        "RouteTableId": {
            "Ref": "RouteTable"
        }
    }
},
"EgressOnlyInternetGateway": {
    "Type": "AWS::EC2::EgressOnlyInternetGateway",
    "Properties": {
        "VpcId": {
            "Ref": "VPC"
        }
    }
},
"RouteTable": {
    "Type": "AWS::EC2::RouteTable",
    "Properties": {
        "VpcId": {
            "Ref": "VPC"
        }
    }
},
"VPC": {
    "Type": "AWS::EC2::VPC",
    "Properties": {
        "CidrBlock": "10.0.0.0/16"
    }
}
```

### YAML
<a name="quickref-ec2-example-16.yaml"></a>

```
DefaultIpv6Route:
  Type: AWS::EC2::Route
  Properties:
    DestinationIpv6CidrBlock: "::/0"
    EgressOnlyInternetGatewayId:
      Ref: "EgressOnlyInternetGateway"
    RouteTableId:
      Ref: "RouteTable"
EgressOnlyInternetGateway:
  Type: AWS::EC2::EgressOnlyInternetGateway
  Properties:
    VpcId:
      Ref: "VPC"
RouteTable:
  Type: AWS::EC2::RouteTable
  Properties:
    VpcId:
      Ref: "VPC"
VPC:
  Type: AWS::EC2::VPC
  Properties:
    CidrBlock: "10.0.0.0/16"
```

## 弹性网络接口 (ENI) 模板代码段
<a name="cfn-template-snippets-eni"></a>

### 创建带有附加弹性网络接口（ENI）的 Amazon EC2 实例
<a name="cfn-template-snippets-eni-template"></a>

以下示例代码段使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-instance.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-instance.html) 资源在指定的 Amazon VPC 和子网中创建 Amazon EC2 实例。它将两个网络接口（ENI）连接到实例，通过附加的 ENI 将弹性 IP 地址关联到实例，并针对 SSH 和 HTTP 访问配置安全组。创建实例时，用户数据作为启动配置的一部分提供给实例。用户数据包括以 `base64` 格式编码的脚本，可确保将其传递到实例。当实例启动时，脚本会作为引导过程的一部分自动运行。它会安装 `ec2-net-utils`、配置网络接口并启动 HTTP 服务。

为了根据所选区域确定合适的亚马逊机器映像（AMI），该代码段使用了一个可在 `RegionMap` 映射中查找值的 `Fn::FindInMap` 函数。此映射必须在较大的模板中定义。这两个网络接口是使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-networkinterface.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-networkinterface.html) 资源创建的。使用分配给 `vpc` 域的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-eip.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-eip.html) 资源指定弹性 IP 地址。这些弹性 IP 地址与使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-eipassociation.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-eipassociation.html) 资源的网络接口关联。

`Outputs` 部分定义了您想在堆栈创建后访问的值或资源。在此代码段中，定义的输出是 `InstancePublicIp`，表示堆栈创建的 EC2 实例的公有 IP 地址。您可以使用 Amazon CloudFormation 控制台的**输出**选项卡或使用 [describe-stacks](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/describe-stacks.html) 命令来检索此输出。

有关弹性网络接口的更多信息，请参阅[弹性网络接口](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/using-eni.html)。

#### JSON
<a name="cfn-template-snippets-eni-example-1.json"></a>

```
"Resources": {
    "ControlPortAddress": {
        "Type": "AWS::EC2::EIP",
        "Properties": {
            "Domain": "vpc"
        }
    },
    "AssociateControlPort": {
        "Type": "AWS::EC2::EIPAssociation",
        "Properties": {
            "AllocationId": {
                "Fn::GetAtt": [
                    "ControlPortAddress",
                    "AllocationId"
                ]
            },
            "NetworkInterfaceId": {
                "Ref": "controlXface"
            }
        }
    },
    "WebPortAddress": {
        "Type": "AWS::EC2::EIP",
        "Properties": {
            "Domain": "vpc"
        }
    },
    "AssociateWebPort": {
        "Type": "AWS::EC2::EIPAssociation",
        "Properties": {
            "AllocationId": {
                "Fn::GetAtt": [
                    "WebPortAddress",
                    "AllocationId"
                ]
            },
            "NetworkInterfaceId": {
                "Ref": "webXface"
            }
        }
    },
    "SSHSecurityGroup": {
        "Type": "AWS::EC2::SecurityGroup",
        "Properties": {
            "VpcId": {
                "Ref": "VpcId"
            },
            "GroupDescription": "Enable SSH access via port 22",
            "SecurityGroupIngress": [
                {
                    "CidrIp": "0.0.0.0/0",
                    "FromPort": 22,
                    "IpProtocol": "tcp",
                    "ToPort": 22
                }
            ]
        }
    },
    "WebSecurityGroup": {
        "Type": "AWS::EC2::SecurityGroup",
        "Properties": {
            "VpcId": {
                "Ref": "VpcId"
            },
            "GroupDescription": "Enable HTTP access via user-defined port",
            "SecurityGroupIngress": [
                {
                    "CidrIp": "0.0.0.0/0",
                    "FromPort": 80,
                    "IpProtocol": "tcp",
                    "ToPort": 80
                }
            ]
        }
    },
    "controlXface": {
        "Type": "AWS::EC2::NetworkInterface",
        "Properties": {
            "SubnetId": {
                "Ref": "SubnetId"
            },
            "Description": "Interface for controlling traffic such as SSH",
            "GroupSet": [
                {
                    "Fn::GetAtt": [
                        "SSHSecurityGroup",
                        "GroupId"
                    ]
                }
            ],
            "SourceDestCheck": true,
            "Tags": [
                {
                    "Key": "Network",
                    "Value": "Control"
                }
            ]
        }
    },
    "webXface": {
        "Type": "AWS::EC2::NetworkInterface",
        "Properties": {
            "SubnetId": {
                "Ref": "SubnetId"
            },
            "Description": "Interface for web traffic",
            "GroupSet": [
                {
                    "Fn::GetAtt": [
                        "WebSecurityGroup",
                        "GroupId"
                    ]
                }
            ],
            "SourceDestCheck": true,
            "Tags": [
                {
                    "Key": "Network",
                    "Value": "Web"
                }
            ]
        }
    },
    "Ec2Instance": {
        "Type": "AWS::EC2::Instance",
        "Properties": {
            "ImageId": {
                "Fn::FindInMap": [
                    "RegionMap",
                    {
                        "Ref": "AWS::Region"
                    },
                    "AMI"
                ]
            },
            "KeyName": {
                "Ref": "KeyName"
            },
            "NetworkInterfaces": [
                {
                    "NetworkInterfaceId": {
                        "Ref": "controlXface"
                    },
                    "DeviceIndex": "0"
                },
                {
                    "NetworkInterfaceId": {
                        "Ref": "webXface"
                    },
                    "DeviceIndex": "1"
                }
            ],
            "Tags": [
                {
                    "Key": "Role",
                    "Value": "Test Instance"
                }
            ],
            "UserData": {
                "Fn::Base64": {
                    "Fn::Sub": "#!/bin/bash -xe\nyum install ec2-net-utils -y\nec2ifup eth1\nservice httpd start\n"
                }
            }
        }
    }
},
"Outputs": {
    "InstancePublicIp": {
        "Description": "Public IP Address of the EC2 Instance",
        "Value": {
            "Fn::GetAtt": [
                "Ec2Instance",
                "PublicIp"
            ]
        }
    }
}
```

#### YAML
<a name="cfn-template-snippets-eni-example.yaml"></a>

```
Resources:
  ControlPortAddress:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
  AssociateControlPort:
    Type: AWS::EC2::EIPAssociation
    Properties:
      AllocationId:
        Fn::GetAtt:
          - ControlPortAddress
          - AllocationId
      NetworkInterfaceId:
        Ref: controlXface
  WebPortAddress:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
  AssociateWebPort:
    Type: AWS::EC2::EIPAssociation
    Properties:
      AllocationId:
        Fn::GetAtt:
          - WebPortAddress
          - AllocationId
      NetworkInterfaceId:
        Ref: webXface
  SSHSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId:
        Ref: VpcId
      GroupDescription: Enable SSH access via port 22
      SecurityGroupIngress:
        - CidrIp: 0.0.0.0/0
          FromPort: 22
          IpProtocol: tcp
          ToPort: 22
  WebSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId:
        Ref: VpcId
      GroupDescription: Enable HTTP access via user-defined port
      SecurityGroupIngress:
        - CidrIp: 0.0.0.0/0
          FromPort: 80
          IpProtocol: tcp
          ToPort: 80
  controlXface:
    Type: AWS::EC2::NetworkInterface
    Properties:
      SubnetId:
        Ref: SubnetId
      Description: Interface for controlling traffic such as SSH
      GroupSet:
        - Fn::GetAtt:
            - SSHSecurityGroup
            - GroupId
      SourceDestCheck: true
      Tags:
        - Key: Network
          Value: Control
  webXface:
    Type: AWS::EC2::NetworkInterface
    Properties:
      SubnetId:
        Ref: SubnetId
      Description: Interface for web traffic
      GroupSet:
        - Fn::GetAtt:
            - WebSecurityGroup
            - GroupId
      SourceDestCheck: true
      Tags:
        - Key: Network
          Value: Web
  Ec2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId:
        Fn::FindInMap:
          - RegionMap
          - Ref: AWS::Region
          - AMI
      KeyName:
        Ref: KeyName
      NetworkInterfaces:
        - NetworkInterfaceId:
            Ref: controlXface
          DeviceIndex: "0"
        - NetworkInterfaceId:
            Ref: webXface
          DeviceIndex: "1"
      Tags:
        - Key: Role
          Value: Test Instance
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash -xe
          yum install ec2-net-utils -y
          ec2ifup eth1
          service httpd start
Outputs:
  InstancePublicIp:
    Description: Public IP Address of the EC2 Instance
    Value:
      Fn::GetAtt:
        - Ec2Instance
        - PublicIp
```

# Amazon Elastic Container Service 示例模板
<a name="quickref-ecs"></a>

Amazon Elastic Container Service (Amazon ECS) 是一项容器管理服务，可让您轻松地在 Amazon Elastic Compute Cloud (Amazon EC2) 实例集群上运行、停止和管理 Docker 容器。

## 使用 AL2023 Amazon ECS-Optimized-AMI 创建集群
<a name="create-cluster-al2023"></a>

定义一个集群，该集群使用在 Amazon EC2 上启动 AL2023 实例的容量提供程序。

**重要**  
有关最新的 AMI ID，请参阅《Amazon Elastic Container Service 开发人员指南》中的 [Amazon ECS 优化的 AMI](https://docs.amazonaws.cn/AmazonECS/latest/developerguide/ecs-optimized_AMI.html)。

### JSON
<a name="quickref-ecs-example-1.json"></a>

```
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "EC2 ECS cluster that starts out empty, with no EC2 instances yet. An ECS capacity provider automatically launches more EC2 instances as required on the fly when you request ECS to launch services or standalone tasks.",
  "Parameters": {
      "InstanceType": {
          "Type": "String",
          "Description": "EC2 instance type",
          "Default": "t2.medium",
          "AllowedValues": [
              "t1.micro",
              "t2.2xlarge",
              "t2.large",
              "t2.medium",
              "t2.micro",
              "t2.nano",
              "t2.small",
              "t2.xlarge",
              "t3.2xlarge",
              "t3.large",
              "t3.medium",
              "t3.micro",
              "t3.nano",
              "t3.small",
              "t3.xlarge"
          ]
      },
      "DesiredCapacity": {
          "Type": "Number",
          "Default": "0",
          "Description": "Number of EC2 instances to launch in your ECS cluster."
      },
      "MaxSize": {
          "Type": "Number",
          "Default": "100",
          "Description": "Maximum number of EC2 instances that can be launched in your ECS cluster."
      },
      "ECSAMI": {
          "Description": "The Amazon Machine Image ID used for the cluster",
          "Type": "AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>",
          "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2023/recommended/image_id"
      },
      "VpcId": {
          "Type": "AWS::EC2::VPC::Id",
          "Description": "VPC ID where the ECS cluster is launched",
          "Default": "vpc-1234567890abcdef0"
      },
      "SubnetIds": {
          "Type": "List<AWS::EC2::Subnet::Id>",
          "Description": "List of subnet IDs where the EC2 instances will be launched",
          "Default": "subnet-021345abcdef67890"
      }
  },
  "Resources": {
      "ECSCluster": {
          "Type": "AWS::ECS::Cluster",
          "Properties": {
              "ClusterSettings": [
                  {
                      "Name": "containerInsights",
                      "Value": "enabled"
                  }
              ]
          }
      },
      "ECSAutoScalingGroup": {
          "Type": "AWS::AutoScaling::AutoScalingGroup",
          "DependsOn": [
              "ECSCluster",
              "EC2Role"
          ],
          "Properties": {
              "VPCZoneIdentifier": {
                  "Ref": "SubnetIds"
              },
              "LaunchTemplate": {
                  "LaunchTemplateId": {
                      "Ref": "ContainerInstances"
                  },
                  "Version": {
                      "Fn::GetAtt": [
                          "ContainerInstances",
                          "LatestVersionNumber"
                      ]
                  }
              },
              "MinSize": 0,
              "MaxSize": {
                  "Ref": "MaxSize"
              },
              "DesiredCapacity": {
                  "Ref": "DesiredCapacity"
              },
              "NewInstancesProtectedFromScaleIn": true
          },
          "UpdatePolicy": {
              "AutoScalingReplacingUpdate": {
                  "WillReplace": "true"
              }
          }
      },
      "ContainerInstances": {
          "Type": "AWS::EC2::LaunchTemplate",
          "Properties": {
              "LaunchTemplateName": "asg-launch-template",
              "LaunchTemplateData": {
                  "ImageId": {
                      "Ref": "ECSAMI"
                  },
                  "InstanceType": {
                      "Ref": "InstanceType"
                  },
                  "IamInstanceProfile": {
                      "Name": {
                          "Ref": "EC2InstanceProfile"
                      }
                  },
                  "SecurityGroupIds": [
                      {
                          "Ref": "ContainerHostSecurityGroup"
                      }
                  ],
                  "UserData": {
                      "Fn::Base64": {
                          "Fn::Sub": "#!/bin/bash -xe\n echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config\n yum install -y aws-cfn-bootstrap\n /opt/aws/bin/cfn-init -v --stack ${AWS::StackId} --resource ContainerInstances --configsets full_install --region ${AWS::Region} &\n"
                      }
                  },
                  "MetadataOptions": {
                      "HttpEndpoint": "enabled",
                      "HttpTokens": "required"
                  }
              }
          }
      },
      "EC2InstanceProfile": {
          "Type": "AWS::IAM::InstanceProfile",
          "Properties": {
              "Path": "/",
              "Roles": [
                  {
                      "Ref": "EC2Role"
                  }
              ]
          }
      },
      "CapacityProvider": {
          "Type": "AWS::ECS::CapacityProvider",
          "Properties": {
              "AutoScalingGroupProvider": {
                  "AutoScalingGroupArn": {
                      "Ref": "ECSAutoScalingGroup"
                  },
                  "ManagedScaling": {
                      "InstanceWarmupPeriod": 60,
                      "MinimumScalingStepSize": 1,
                      "MaximumScalingStepSize": 100,
                      "Status": "ENABLED",
                      "TargetCapacity": 100
                  },
                  "ManagedTerminationProtection": "ENABLED"
              }
          }
      },
      "CapacityProviderAssociation": {
          "Type": "AWS::ECS::ClusterCapacityProviderAssociations",
          "Properties": {
              "CapacityProviders": [
                  {
                      "Ref": "CapacityProvider"
                  }
              ],
              "Cluster": {
                  "Ref": "ECSCluster"
              },
              "DefaultCapacityProviderStrategy": [
                  {
                      "Base": 0,
                      "CapacityProvider": {
                          "Ref": "CapacityProvider"
                      },
                      "Weight": 1
                  }
              ]
          }
      },
      "ContainerHostSecurityGroup": {
          "Type": "AWS::EC2::SecurityGroup",
          "Properties": {
              "GroupDescription": "Access to the EC2 hosts that run containers",
              "VpcId": {
                  "Ref": "VpcId"
              }
          }
      },
      "EC2Role": {
          "Type": "AWS::IAM::Role",
          "Properties": {
              "AssumeRolePolicyDocument": {
                  "Statement": [
                      {
                          "Effect": "Allow",
                          "Principal": {
                              "Service": [
                                  "ec2.amazonaws.com"
                              ]
                          },
                          "Action": [
                              "sts:AssumeRole"
                          ]
                      }
                  ]
              },
              "Path": "/",
              "ManagedPolicyArns": [
                  "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role",
                  "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
              ]
          }
      },
      "ECSTaskExecutionRole": {
          "Type": "AWS::IAM::Role",
          "Properties": {
              "AssumeRolePolicyDocument": {
                  "Statement": [
                      {
                          "Effect": "Allow",
                          "Principal": {
                              "Service": [
                                  "ecs-tasks.amazonaws.com"
                              ]
                          },
                          "Action": [
                              "sts:AssumeRole"
                          ],
                          "Condition": {
                              "ArnLike": {
                                  "aws:SourceArn": {
                                      "Fn::Sub": "arn:${AWS::Partition}:ecs:${AWS::Region}:${AWS::AccountId}:*"
                                  }
                              },
                              "StringEquals": {
                                  "aws:SourceAccount": {
                                        "Fn::Sub": "${AWS::AccountId}"
                                    }
                              }
                          }
                      }
                  ]
              },
              "Path": "/",
              "ManagedPolicyArns": [
                  "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
              ]
          }
      }
  },
  "Outputs": {
      "ClusterName": {
          "Description": "The ECS cluster into which to launch resources",
          "Value": "ECSCluster"
      },
      "ECSTaskExecutionRole": {
          "Description": "The role used to start up a task",
          "Value": "ECSTaskExecutionRole"
      },
      "CapacityProvider": {
          "Description": "The cluster capacity provider that the service should use to request capacity when it wants to start up a task",
          "Value": "CapacityProvider"
      }
  }
}
```

### YAML
<a name="quickref-ecs-example-1.yaml"></a>

```
AWSTemplateFormatVersion: 2010-09-09
Description: EC2 ECS cluster that starts out empty, with no EC2 instances yet.
  An ECS capacity provider automatically launches more EC2 instances as required
  on the fly when you request ECS to launch services or standalone tasks.
Parameters:
  InstanceType:
    Type: String
    Description: EC2 instance type
    Default: "t2.medium"
    AllowedValues:
      - t1.micro
      - t2.2xlarge
      - t2.large
      - t2.medium
      - t2.micro
      - t2.nano
      - t2.small
      - t2.xlarge
      - t3.2xlarge
      - t3.large
      - t3.medium
      - t3.micro
      - t3.nano
      - t3.small
      - t3.xlarge
  DesiredCapacity:
    Type: Number
    Default: "0"
    Description: Number of EC2 instances to launch in your ECS cluster.
  MaxSize:
    Type: Number
    Default: "100"
    Description: Maximum number of EC2 instances that can be launched in your ECS cluster.
  ECSAMI:
    Description: The Amazon Machine Image ID used for the cluster
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ecs/optimized-ami/amazon-linux-2023/recommended/image_id
  VpcId:
    Type: AWS::EC2::VPC::Id
    Description: VPC ID where the ECS cluster is launched
    Default: vpc-1234567890abcdef0
  SubnetIds:
    Type: List<AWS::EC2::Subnet::Id>
    Description: List of subnet IDs where the EC2 instances will be launched
    Default: "subnet-021345abcdef67890"
Resources:
# This is authorizes ECS to manage resources on your
  # account on your behalf. This role is likely already created on your account
  # ECSRole:
  #  Type: AWS::IAM::ServiceLinkedRole
  #  Properties:
  #    AWSServiceName: 'ecs.amazonaws.com'
  
   # ECS Resources
  ECSCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterSettings:
        - Name: containerInsights
          Value: enabled
  
  # Autoscaling group. This launches the actual EC2 instances that will register
  # themselves as members of the cluster, and run the docker containers.
  ECSAutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    DependsOn:
      # This is to ensure that the ASG gets deleted first before these
    # resources, when it comes to stack teardown.
      - ECSCluster
      - EC2Role
    Properties:
      VPCZoneIdentifier:
        Ref: SubnetIds
      LaunchTemplate:
        LaunchTemplateId: !Ref ContainerInstances
        Version: !GetAtt ContainerInstances.LatestVersionNumber
      MinSize: 0
      MaxSize:
        Ref: MaxSize
      DesiredCapacity:
        Ref: DesiredCapacity
      NewInstancesProtectedFromScaleIn: true
    UpdatePolicy:
      AutoScalingReplacingUpdate:
        WillReplace: "true"
  # The config for each instance that is added to the cluster
  ContainerInstances:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateName: "asg-launch-template"
      LaunchTemplateData:
        ImageId:
          Ref: ECSAMI
        InstanceType:
          Ref: InstanceType
        IamInstanceProfile:
          Name: !Ref EC2InstanceProfile
        SecurityGroupIds:
          - !Ref ContainerHostSecurityGroup
        # This injected configuration file is how the EC2 instance
      # knows which ECS cluster on your AWS account it should be joining
        UserData:
          Fn::Base64: !Sub |
           #!/bin/bash -xe
            echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config
            yum install -y aws-cfn-bootstrap
            /opt/aws/bin/cfn-init -v --stack ${AWS::StackId} --resource ContainerInstances --configsets full_install --region ${AWS::Region} &
         # Disable IMDSv1, and require IMDSv2
        MetadataOptions:
          HttpEndpoint: enabled
          HttpTokens: required
  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles: 
      - !Ref EC2Role 
  # Create an ECS capacity provider to attach the ASG to the ECS cluster
  # so that it autoscales as we launch more containers
  CapacityProvider:
    Type: AWS::ECS::CapacityProvider
    Properties:
      AutoScalingGroupProvider:
        AutoScalingGroupArn: !Ref ECSAutoScalingGroup
        ManagedScaling:
          InstanceWarmupPeriod: 60
          MinimumScalingStepSize: 1
          MaximumScalingStepSize: 100
          Status: ENABLED
          # Percentage of cluster reservation to try to maintain
          TargetCapacity: 100
        ManagedTerminationProtection: ENABLED
   # Create a cluster capacity provider assocation so that the cluster
  # will use the capacity provider
  CapacityProviderAssociation:
    Type: AWS::ECS::ClusterCapacityProviderAssociations
    Properties:
      CapacityProviders:
        - !Ref CapacityProvider
      Cluster: !Ref ECSCluster
      DefaultCapacityProviderStrategy:
        - Base: 0
          CapacityProvider: !Ref CapacityProvider
          Weight: 1
  # A security group for the EC2 hosts that will run the containers.
  # This can be used to limit incoming traffic to or outgoing traffic
  # from the container's host EC2 instance.
  ContainerHostSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Access to the EC2 hosts that run containers
      VpcId:
        Ref: VpcId
  # Role for the EC2 hosts. This allows the ECS agent on the EC2 hosts
  # to communciate with the ECS control plane, as well as download the docker
  # images from ECR to run on your host.
  EC2Role:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
      # See reference: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/security-iam-awsmanpol.html#security-iam-awsmanpol-AmazonEC2ContainerServiceforEC2Role
        - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
      # This managed policy allows us to connect to the instance using SSM
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
  # This is a role which is used within Fargate to allow the Fargate agent
  # to download images, and upload logs.
  ECSTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ecs-tasks.amazonaws.com
            Action:
              - sts:AssumeRole
            Condition:
              ArnLike:
                aws:SourceArn: !Sub arn:${AWS::Partition}:ecs:${AWS::Region}:${AWS::AccountId}:*
              StringEquals:
                aws:SourceAccount: !Sub ${AWS::AccountId}
      Path: /
      # This role enables all features of ECS. See reference:
    # https://docs.aws.amazon.com/AmazonECS/latest/developerguide/security-iam-awsmanpol.html#security-iam-awsmanpol-AmazonECSTaskExecutionRolePolicy
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
Outputs:
  ClusterName:
    Description: The ECS cluster into which to launch resources
    Value: ECSCluster
  ECSTaskExecutionRole:
    Description: The role used to start up a task
    Value: ECSTaskExecutionRole
  CapacityProvider:
    Description: The cluster capacity provider that the service should use to
      request capacity when it wants to start up a task
    Value: CapacityProvider
```

## 部署服务
<a name="create-service"></a>

以下模板定义了一项服务，该服务使用容量提供程序请求运行 AL2023 容量。容器将在 AL2023 实例上线时随之启动：

### JSON
<a name="quickref-ecs-example-2.json"></a>

```
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "An example service that deploys in AWS VPC networking mode on EC2 capacity. Service uses a capacity provider to request EC2 instances to run on. Service runs with networking in private subnets, but still accessible to the internet via a load balancer hosted in public subnets.",
  "Parameters": {
      "VpcId": {
          "Type": "String",
          "Description": "The VPC that the service is running inside of"
      },
      "PublicSubnetIds": {
          "Type": "List<AWS::EC2::Subnet::Id>",
          "Description": "List of public subnet ID's to put the load balancer in"
      },
      "PrivateSubnetIds": {
          "Type": "List<AWS::EC2::Subnet::Id>",
          "Description": "List of private subnet ID's that the AWS VPC tasks are in"
      },
      "ClusterName": {
          "Type": "String",
          "Description": "The name of the ECS cluster into which to launch capacity."
      },
      "ECSTaskExecutionRole": {
          "Type": "String",
          "Description": "The role used to start up an ECS task"
      },
      "CapacityProvider": {
          "Type": "String",
          "Description": "The cluster capacity provider that the service should use to request capacity when it wants to start up a task"
      },
      "ServiceName": {
          "Type": "String",
          "Default": "web",
          "Description": "A name for the service"
      },
      "ImageUrl": {
          "Type": "String",
          "Default": "public.ecr.aws/docker/library/nginx:latest",
          "Description": "The url of a docker image that contains the application process that will handle the traffic for this service"
      },
      "ContainerCpu": {
          "Type": "Number",
          "Default": 256,
          "Description": "How much CPU to give the container. 1024 is 1 CPU"
      },
      "ContainerMemory": {
          "Type": "Number",
          "Default": 512,
          "Description": "How much memory in megabytes to give the container"
      },
      "ContainerPort": {
          "Type": "Number",
          "Default": 80,
          "Description": "What port that the application expects traffic on"
      },
      "DesiredCount": {
          "Type": "Number",
          "Default": 2,
          "Description": "How many copies of the service task to run"
      }
  },
  "Resources": {
      "TaskDefinition": {
          "Type": "AWS::ECS::TaskDefinition",
          "Properties": {
              "Family": {
                  "Ref": "ServiceName"
              },
              "Cpu": {
                  "Ref": "ContainerCpu"
              },
              "Memory": {
                  "Ref": "ContainerMemory"
              },
              "NetworkMode": "awsvpc",
              "RequiresCompatibilities": [
                  "EC2"
              ],
              "ExecutionRoleArn": {
                  "Ref": "ECSTaskExecutionRole"
              },
              "ContainerDefinitions": [
                  {
                      "Name": {
                          "Ref": "ServiceName"
                      },
                      "Cpu": {
                          "Ref": "ContainerCpu"
                      },
                      "Memory": {
                          "Ref": "ContainerMemory"
                      },
                      "Image": {
                          "Ref": "ImageUrl"
                      },
                      "PortMappings": [
                          {
                              "ContainerPort": {
                                  "Ref": "ContainerPort"
                              },
                              "HostPort": {
                                  "Ref": "ContainerPort"
                              }
                          }
                      ],
                      "LogConfiguration": {
                          "LogDriver": "awslogs",
                          "Options": {
                              "mode": "non-blocking",
                              "max-buffer-size": "25m",
                              "awslogs-group": {
                                  "Ref": "LogGroup"
                              },
                              "awslogs-region": {
                                  "Ref": "AWS::Region"
                              },
                              "awslogs-stream-prefix": {
                                  "Ref": "ServiceName"
                              }
                          }
                      }
                  }
              ]
          }
      },
      "Service": {
          "Type": "AWS::ECS::Service",
          "DependsOn": "PublicLoadBalancerListener",
          "Properties": {
              "ServiceName": {
                  "Ref": "ServiceName"
              },
              "Cluster": {
                  "Ref": "ClusterName"
              },
              "PlacementStrategies": [
                  {
                      "Field": "attribute:ecs.availability-zone",
                      "Type": "spread"
                  },
                  {
                      "Field": "cpu",
                      "Type": "binpack"
                  }
              ],
              "CapacityProviderStrategy": [
                  {
                      "Base": 0,
                      "CapacityProvider": {
                          "Ref": "CapacityProvider"
                      },
                      "Weight": 1
                  }
              ],
              "NetworkConfiguration": {
                  "AwsvpcConfiguration": {
                      "SecurityGroups": [
                          {
                              "Ref": "ServiceSecurityGroup"
                          }
                      ],
                      "Subnets": {
                          "Ref": "PrivateSubnetIds"
                      }
                  }
              },
              "DeploymentConfiguration": {
                  "MaximumPercent": 200,
                  "MinimumHealthyPercent": 75
              },
              "DesiredCount": {
                  "Ref": "DesiredCount"
              },
              "TaskDefinition": {
                  "Ref": "TaskDefinition"
              },
              "LoadBalancers": [
                  {
                      "ContainerName": {
                          "Ref": "ServiceName"
                      },
                      "ContainerPort": {
                          "Ref": "ContainerPort"
                      },
                      "TargetGroupArn": {
                          "Ref": "ServiceTargetGroup"
                      }
                  }
              ]
          }
      },
      "ServiceSecurityGroup": {
          "Type": "AWS::EC2::SecurityGroup",
          "Properties": {
              "GroupDescription": "Security group for service",
              "VpcId": {
                  "Ref": "VpcId"
              }
          }
      },
      "ServiceTargetGroup": {
          "Type": "AWS::ElasticLoadBalancingV2::TargetGroup",
          "Properties": {
              "HealthCheckIntervalSeconds": 6,
              "HealthCheckPath": "/",
              "HealthCheckProtocol": "HTTP",
              "HealthCheckTimeoutSeconds": 5,
              "HealthyThresholdCount": 2,
              "TargetType": "ip",
              "Port": {
                  "Ref": "ContainerPort"
              },
              "Protocol": "HTTP",
              "UnhealthyThresholdCount": 10,
              "VpcId": {
                  "Ref": "VpcId"
              },
              "TargetGroupAttributes": [
                  {
                      "Key": "deregistration_delay.timeout_seconds",
                      "Value": 0
                  }
              ]
          }
      },
      "PublicLoadBalancerSG": {
          "Type": "AWS::EC2::SecurityGroup",
          "Properties": {
              "GroupDescription": "Access to the public facing load balancer",
              "VpcId": {
                  "Ref": "VpcId"
              },
              "SecurityGroupIngress": [
                  {
                      "CidrIp": "0.0.0.0/0",
                      "IpProtocol": -1
                  }
              ]
          }
      },
      "PublicLoadBalancer": {
          "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
          "Properties": {
              "Scheme": "internet-facing",
              "LoadBalancerAttributes": [
                  {
                      "Key": "idle_timeout.timeout_seconds",
                      "Value": "30"
                  }
              ],
              "Subnets": {
                  "Ref": "PublicSubnetIds"
              },
              "SecurityGroups": [
                  {
                      "Ref": "PublicLoadBalancerSG"
                  }
              ]
          }
      },
      "PublicLoadBalancerListener": {
          "Type": "AWS::ElasticLoadBalancingV2::Listener",
          "Properties": {
              "DefaultActions": [
                  {
                      "Type": "forward",
                      "ForwardConfig": {
                          "TargetGroups": [
                              {
                                  "TargetGroupArn": {
                                      "Ref": "ServiceTargetGroup"
                                  },
                                  "Weight": 100
                              }
                          ]
                      }
                  }
              ],
              "LoadBalancerArn": {
                  "Ref": "PublicLoadBalancer"
              },
              "Port": 80,
              "Protocol": "HTTP"
          }
      },
      "ServiceIngressfromLoadBalancer": {
          "Type": "AWS::EC2::SecurityGroupIngress",
          "Properties": {
              "Description": "Ingress from the public ALB",
              "GroupId": {
                  "Ref": "ServiceSecurityGroup"
              },
              "IpProtocol": -1,
              "SourceSecurityGroupId": {
                  "Ref": "PublicLoadBalancerSG"
              }
          }
      },
      "LogGroup": {
          "Type": "AWS::Logs::LogGroup"
      }
  }
}
```

### YAML
<a name="quickref-ecs-example-2.yaml"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Description: >-
  An example service that deploys in AWS VPC networking mode on EC2 capacity.
  Service uses a capacity provider to request EC2 instances to run on. Service
  runs with networking in private subnets, but still accessible to the internet
  via a load balancer hosted in public subnets.
Parameters:
  VpcId:
    Type: String
    Description: The VPC that the service is running inside of
  PublicSubnetIds:
    Type: 'List<AWS::EC2::Subnet::Id>'
    Description: List of public subnet ID's to put the load balancer in
  PrivateSubnetIds:
    Type: 'List<AWS::EC2::Subnet::Id>'
    Description: List of private subnet ID's that the AWS VPC tasks are in
  ClusterName:
    Type: String
    Description: The name of the ECS cluster into which to launch capacity.
  ECSTaskExecutionRole:
    Type: String
    Description: The role used to start up an ECS task
  CapacityProvider:
    Type: String
    Description: >-
      The cluster capacity provider that the service should use to request
      capacity when it wants to start up a task
  ServiceName:
    Type: String
    Default: web
    Description: A name for the service
  ImageUrl:
    Type: String
    Default: 'public.ecr.aws/docker/library/nginx:latest'
    Description: >-
      The url of a docker image that contains the application process that will
      handle the traffic for this service
  ContainerCpu:
    Type: Number
    Default: 256
    Description: How much CPU to give the container. 1024 is 1 CPU
  ContainerMemory:
    Type: Number
    Default: 512
    Description: How much memory in megabytes to give the container
  ContainerPort:
    Type: Number
    Default: 80
    Description: What port that the application expects traffic on
  DesiredCount:
    Type: Number
    Default: 2
    Description: How many copies of the service task to run
Resources:
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Ref ServiceName
      Cpu: !Ref ContainerCpu
      Memory: !Ref ContainerMemory
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - EC2
      ExecutionRoleArn: !Ref ECSTaskExecutionRole
      ContainerDefinitions:
        - Name: !Ref ServiceName
          Cpu: !Ref ContainerCpu
          Memory: !Ref ContainerMemory
          Image: !Ref ImageUrl
          PortMappings:
            - ContainerPort: !Ref ContainerPort
              HostPort: !Ref ContainerPort
          LogConfiguration:
            LogDriver: awslogs
            Options:
              mode: non-blocking
              max-buffer-size: 25m
              awslogs-group: !Ref LogGroup
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: !Ref ServiceName
  Service:
    Type: AWS::ECS::Service
    DependsOn: PublicLoadBalancerListener
    Properties:
      ServiceName: !Ref ServiceName
      Cluster: !Ref ClusterName
      PlacementStrategies:
        - Field: 'attribute:ecs.availability-zone'
          Type: spread
        - Field: cpu
          Type: binpack
      CapacityProviderStrategy:
        - Base: 0
          CapacityProvider: !Ref CapacityProvider
          Weight: 1
      NetworkConfiguration:
        AwsvpcConfiguration:
          SecurityGroups:
            - !Ref ServiceSecurityGroup
          Subnets: !Ref PrivateSubnetIds
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 75
      DesiredCount: !Ref DesiredCount
      TaskDefinition: !Ref TaskDefinition
      LoadBalancers:
        - ContainerName: !Ref ServiceName
          ContainerPort: !Ref ContainerPort
          TargetGroupArn: !Ref ServiceTargetGroup
  ServiceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for service
      VpcId: !Ref VpcId
  ServiceTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 6
      HealthCheckPath: /
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 2
      TargetType: ip
      Port: !Ref ContainerPort
      Protocol: HTTP
      UnhealthyThresholdCount: 10
      VpcId: !Ref VpcId
      TargetGroupAttributes:
        - Key: deregistration_delay.timeout_seconds
          Value: 0
  PublicLoadBalancerSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Access to the public facing load balancer
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - CidrIp: 0.0.0.0/0
          IpProtocol: -1
  PublicLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      LoadBalancerAttributes:
        - Key: idle_timeout.timeout_seconds
          Value: '30'
      Subnets: !Ref PublicSubnetIds
      SecurityGroups:
        - !Ref PublicLoadBalancerSG
  PublicLoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          ForwardConfig:
            TargetGroups:
              - TargetGroupArn: !Ref ServiceTargetGroup
                Weight: 100
      LoadBalancerArn: !Ref PublicLoadBalancer
      Port: 80
      Protocol: HTTP
  ServiceIngressfromLoadBalancer:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      Description: Ingress from the public ALB
      GroupId: !Ref ServiceSecurityGroup
      IpProtocol: -1
      SourceSecurityGroupId: !Ref PublicLoadBalancerSG
  LogGroup:
    Type: AWS::Logs::LogGroup
```

# Amazon Elastic File System 示例模板
<a name="quickref-efs"></a>

Amazon Elastic File System (Amazon EFS) 是适用于 Amazon Elastic Compute Cloud (Amazon EC2) 实例的文件存储服务。借助 Amazon EFS，您的应用程序在需要存储时可获得存储，因为存储容量会在您添加和删除文件时自动增加和缩小。

以下示例模板部署 EC2 实例（位于自动扩缩组中），这些实例与 Amazon EFS 文件系统相关联。为了将实例与文件系统关联，这些实例运行 cfn-init 帮助程序脚本，以便下载和安装 `nfs-utils` yum 软件包，创建新目录，然后使用文件系统的 DNS 名称来在该目录下挂载文件系统。文件系统的 DNS 名称将解析为 Amazon EC2 实例的可用区中的挂载目标的 IP 地址。有关 DNS 名称结构的更多信息，请参阅《Amazon Elastic File System 用户指南》中的[挂载文件系统](https://docs.amazonaws.cn/efs/latest/ug/mounting-fs.html)。

要测量网络文件系统活动，模板应包含自定义 Amazon CloudWatch 指标。模板还创建 VPC、子网和安全组。要允许实例与文件系统通信，VPC 必须已启用 DNS，而且挂载目标和 EC2 实例必须位于子网指定的同一可用区 (AZ) 中。

挂载目标的安全组支持至 TCP 端口 2049 的网络连接，NFSv4 客户端挂载文件系统需要此连接。有关 EC2 实例和挂载目标的安全组的更多信息，请参阅[《Amazon Elastic File System 用户指南》](https://docs.amazonaws.cn/efs/latest/ug/)中的[安全性](https://docs.amazonaws.cn/efs/latest/ug/security-considerations.html)。

**注意**  
如果更新挂载目标导致了挂载目标被替换，则使用关联文件系统的实例或应用程序可能会中断。这可能会导致未提交的写入丢失。为了避免中断，请在您更新挂载目标时通过将所需容量设置为零来停止实例。这使得实例可以在删除挂载目标之前卸载文件系统。挂载更新完成之后，通过设置所需容量在后续更新中启动您的实例。

## JSON
<a name="quickref-efs-example-1.json"></a>

```
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "This template creates an Amazon EFS file system and mount target and associates it with Amazon EC2 instances in an Auto Scaling group. **WARNING** This template creates Amazon EC2 instances and related resources. You will be billed for the AWS resources used if you create a stack from this template.",
  "Parameters": {
    "InstanceType" : {
      "Description" : "WebServer EC2 instance type",
      "Type" : "String",
      "Default" : "t2.small",
      "AllowedValues" : [ 
        "t1.micro", 
        "t2.nano", 
        "t2.micro", 
        "t2.small", 
        "t2.medium", 
        "t2.large", 
        "m1.small", 
        "m1.medium", 
        "m1.large", 
        "m1.xlarge", 
        "m2.xlarge", 
        "m2.2xlarge", 
        "m2.4xlarge", 
        "m3.medium", 
        "m3.large", 
        "m3.xlarge", 
        "m3.2xlarge", 
        "m4.large", 
        "m4.xlarge", 
        "m4.2xlarge", 
        "m4.4xlarge", 
        "m4.10xlarge", 
        "c1.medium", 
        "c1.xlarge", 
        "c3.large", 
        "c3.xlarge", 
        "c3.2xlarge", 
        "c3.4xlarge", 
        "c3.8xlarge", 
        "c4.large", 
        "c4.xlarge", 
        "c4.2xlarge", 
        "c4.4xlarge", 
        "c4.8xlarge", 
        "g2.2xlarge", 
        "g2.8xlarge", 
        "r3.large", 
        "r3.xlarge", 
        "r3.2xlarge", 
        "r3.4xlarge", 
        "r3.8xlarge", 
        "i2.xlarge", 
        "i2.2xlarge", 
        "i2.4xlarge", 
        "i2.8xlarge", 
        "d2.xlarge", 
        "d2.2xlarge", 
        "d2.4xlarge", 
        "d2.8xlarge", 
        "hi1.4xlarge", 
        "hs1.8xlarge", 
        "cr1.8xlarge", 
        "cc2.8xlarge", 
        "cg1.4xlarge"
      ],
      "ConstraintDescription" : "must be a valid EC2 instance type."
    },
    "KeyName": {
      "Type": "AWS::EC2::KeyPair::KeyName",
      "Description": "Name of an existing EC2 key pair to enable SSH access to the EC2 instances"
    },
    "AsgMaxSize": {
      "Type": "Number",
      "Description": "Maximum size and initial desired capacity of Auto Scaling Group",
      "Default": "2"
    },
    "SSHLocation" : {
      "Description" : "The IP address range that can be used to connect to the EC2 instances by using SSH",
      "Type": "String",
      "MinLength": "9",
      "MaxLength": "18",
      "Default": "0.0.0.0/0",
      "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
      "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
    },
    "VolumeName" : {
      "Description" : "The name to be used for the EFS volume",
      "Type": "String",
      "MinLength": "1",
      "Default": "myEFSvolume"
    },
    "MountPoint" : {
      "Description" : "The Linux mount point for the EFS volume",
      "Type": "String",
      "MinLength": "1",
      "Default": "myEFSvolume"
    }
  },
  "Mappings" : {
    "AWSInstanceType2Arch" : {
      "t1.micro"    : { "Arch" : "HVM64"  },
      "t2.nano"     : { "Arch" : "HVM64"  },
      "t2.micro"    : { "Arch" : "HVM64"  },
      "t2.small"    : { "Arch" : "HVM64"  },
      "t2.medium"   : { "Arch" : "HVM64"  },
      "t2.large"    : { "Arch" : "HVM64"  },
      "m1.small"    : { "Arch" : "HVM64"  },
      "m1.medium"   : { "Arch" : "HVM64"  },
      "m1.large"    : { "Arch" : "HVM64"  },
      "m1.xlarge"   : { "Arch" : "HVM64"  },
      "m2.xlarge"   : { "Arch" : "HVM64"  },
      "m2.2xlarge"  : { "Arch" : "HVM64"  },
      "m2.4xlarge"  : { "Arch" : "HVM64"  },
      "m3.medium"   : { "Arch" : "HVM64"  },
      "m3.large"    : { "Arch" : "HVM64"  },
      "m3.xlarge"   : { "Arch" : "HVM64"  },
      "m3.2xlarge"  : { "Arch" : "HVM64"  },
      "m4.large"    : { "Arch" : "HVM64"  },
      "m4.xlarge"   : { "Arch" : "HVM64"  },
      "m4.2xlarge"  : { "Arch" : "HVM64"  },
      "m4.4xlarge"  : { "Arch" : "HVM64"  },
      "m4.10xlarge" : { "Arch" : "HVM64"  },
      "c1.medium"   : { "Arch" : "HVM64"  },
      "c1.xlarge"   : { "Arch" : "HVM64"  },
      "c3.large"    : { "Arch" : "HVM64"  },
      "c3.xlarge"   : { "Arch" : "HVM64"  },
      "c3.2xlarge"  : { "Arch" : "HVM64"  },
      "c3.4xlarge"  : { "Arch" : "HVM64"  },
      "c3.8xlarge"  : { "Arch" : "HVM64"  },
      "c4.large"    : { "Arch" : "HVM64"  },
      "c4.xlarge"   : { "Arch" : "HVM64"  },
      "c4.2xlarge"  : { "Arch" : "HVM64"  },
      "c4.4xlarge"  : { "Arch" : "HVM64"  },
      "c4.8xlarge"  : { "Arch" : "HVM64"  },
      "g2.2xlarge"  : { "Arch" : "HVMG2"  },
      "g2.8xlarge"  : { "Arch" : "HVMG2"  },
      "r3.large"    : { "Arch" : "HVM64"  },
      "r3.xlarge"   : { "Arch" : "HVM64"  },
      "r3.2xlarge"  : { "Arch" : "HVM64"  },
      "r3.4xlarge"  : { "Arch" : "HVM64"  },
      "r3.8xlarge"  : { "Arch" : "HVM64"  },
      "i2.xlarge"   : { "Arch" : "HVM64"  },
      "i2.2xlarge"  : { "Arch" : "HVM64"  },
      "i2.4xlarge"  : { "Arch" : "HVM64"  },
      "i2.8xlarge"  : { "Arch" : "HVM64"  },
      "d2.xlarge"   : { "Arch" : "HVM64"  },
      "d2.2xlarge"  : { "Arch" : "HVM64"  },
      "d2.4xlarge"  : { "Arch" : "HVM64"  },
      "d2.8xlarge"  : { "Arch" : "HVM64"  },
      "hi1.4xlarge" : { "Arch" : "HVM64"  },
      "hs1.8xlarge" : { "Arch" : "HVM64"  },
      "cr1.8xlarge" : { "Arch" : "HVM64"  },
      "cc2.8xlarge" : { "Arch" : "HVM64"  }
    },
    "AWSRegionArch2AMI" : {
      "us-east-1"        : {"HVM64" : "ami-0ff8a91507f77f867", "HVMG2" : "ami-0a584ac55a7631c0c"},
      "us-west-2"        : {"HVM64" : "ami-a0cfeed8", "HVMG2" : "ami-0e09505bc235aa82d"},
      "us-west-1"        : {"HVM64" : "ami-0bdb828fd58c52235", "HVMG2" : "ami-066ee5fd4a9ef77f1"},
      "eu-west-1"        : {"HVM64" : "ami-047bb4163c506cd98", "HVMG2" : "ami-0a7c483d527806435"},
      "eu-west-2"        : {"HVM64" : "ami-f976839e", "HVMG2" : "NOT_SUPPORTED"},
      "eu-west-3"        : {"HVM64" : "ami-0ebc281c20e89ba4b", "HVMG2" : "NOT_SUPPORTED"},
      "eu-central-1"     : {"HVM64" : "ami-0233214e13e500f77", "HVMG2" : "ami-06223d46a6d0661c7"},
      "ap-northeast-1"   : {"HVM64" : "ami-06cd52961ce9f0d85", "HVMG2" : "ami-053cdd503598e4a9d"},
      "ap-northeast-2"   : {"HVM64" : "ami-0a10b2721688ce9d2", "HVMG2" : "NOT_SUPPORTED"},
      "ap-northeast-3"   : {"HVM64" : "ami-0d98120a9fb693f07", "HVMG2" : "NOT_SUPPORTED"},
      "ap-southeast-1"   : {"HVM64" : "ami-08569b978cc4dfa10", "HVMG2" : "ami-0be9df32ae9f92309"},
      "ap-southeast-2"   : {"HVM64" : "ami-09b42976632b27e9b", "HVMG2" : "ami-0a9ce9fecc3d1daf8"},
      "ap-south-1"       : {"HVM64" : "ami-0912f71e06545ad88", "HVMG2" : "ami-097b15e89dbdcfcf4"},
      "us-east-2"        : {"HVM64" : "ami-0b59bfac6be064b78", "HVMG2" : "NOT_SUPPORTED"},
      "ca-central-1"     : {"HVM64" : "ami-0b18956f", "HVMG2" : "NOT_SUPPORTED"},
      "sa-east-1"        : {"HVM64" : "ami-07b14488da8ea02a0", "HVMG2" : "NOT_SUPPORTED"},
      "cn-north-1"       : {"HVM64" : "ami-0a4eaf6c4454eda75", "HVMG2" : "NOT_SUPPORTED"},
      "cn-northwest-1"   : {"HVM64" : "ami-6b6a7d09", "HVMG2" : "NOT_SUPPORTED"}
    }
  },
  "Resources": {
    "CloudWatchPutMetricsRole" : {
      "Type"  : "AWS::IAM::Role",
      "Properties" : {
          "AssumeRolePolicyDocument" : {
              "Statement" : [ {
                  "Effect" : "Allow",
                  "Principal" : {
                      "Service" : [ "ec2.amazonaws.com" ]
                  },
                  "Action" : [ "sts:AssumeRole" ]
              } ]
          },
          "Path" : "/"
      }
    },
    "CloudWatchPutMetricsRolePolicy" : {
        "Type" : "AWS::IAM::Policy",
        "Properties" : {
            "PolicyName" : "CloudWatch_PutMetricData",
            "PolicyDocument" : {
              "Version": "2012-10-17",		 	 	 
              "Statement": [
                {
                  "Sid": "CloudWatchPutMetricData",
                  "Effect": "Allow",
                  "Action": ["cloudwatch:PutMetricData"],
                  "Resource": ["*"]
                }
              ]
            },
            "Roles" : [ { "Ref" : "CloudWatchPutMetricsRole" } ]
        }
    },
    "CloudWatchPutMetricsInstanceProfile" : {
      "Type" : "AWS::IAM::InstanceProfile",
      "Properties" : {
        "Path" : "/",
        "Roles" : [ { "Ref" : "CloudWatchPutMetricsRole" } ]
      }
    },
    "VPC": {
      "Type": "AWS::EC2::VPC",
      "Properties": {
        "EnableDnsSupport" : "true",
        "EnableDnsHostnames" : "true",
        "CidrBlock": "10.0.0.0/16",
        "Tags": [ {"Key": "Application", "Value": { "Ref": "AWS::StackId"} } ]
      }
    },
    "InternetGateway" : {
      "Type" : "AWS::EC2::InternetGateway",
      "Properties" : {
        "Tags" : [
          { "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
          { "Key" : "Network", "Value" : "Public" }
        ]
      }
    },
    "GatewayToInternet" : {
      "Type" : "AWS::EC2::VPCGatewayAttachment",
      "Properties" : {
        "VpcId" : { "Ref" : "VPC" },
        "InternetGatewayId" : { "Ref" : "InternetGateway" }
      }
    },
    "RouteTable":{
      "Type":"AWS::EC2::RouteTable",
      "Properties":{
        "VpcId": {"Ref":"VPC"}
      }
    },
    "SubnetRouteTableAssoc": {
      "Type" : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties" : {
        "RouteTableId" : {"Ref":"RouteTable"},
        "SubnetId" : {"Ref":"Subnet"}
      }
    },
    "InternetGatewayRoute": {
        "Type":"AWS::EC2::Route",
        "Properties":{
            "DestinationCidrBlock":"0.0.0.0/0",
            "RouteTableId":{"Ref":"RouteTable"},
            "GatewayId":{"Ref":"InternetGateway"}
        }
    },
    "Subnet": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": { "Ref": "VPC" },
        "CidrBlock": "10.0.0.0/24",
        "Tags": [ { "Key": "Application", "Value": { "Ref": "AWS::StackId" } } ]
      }
    },    
    "InstanceSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "VpcId": { "Ref": "VPC" },
        "GroupDescription": "Enable SSH access via port 22",
        "SecurityGroupIngress": [
          { "IpProtocol": "tcp", "FromPort": 22, "ToPort": 22, "CidrIp": { "Ref": "SSHLocation" } },
          { "IpProtocol": "tcp", "FromPort": 80, "ToPort": 80, "CidrIp": "0.0.0.0/0" }
         ]
      }
    },
    "MountTargetSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "VpcId": { "Ref": "VPC" },
        "GroupDescription": "Security group for mount target",
        "SecurityGroupIngress": [
          {
            "IpProtocol": "tcp",
            "FromPort": 2049,
            "ToPort": 2049,
            "CidrIp": "0.0.0.0/0"
          }
        ]
      }
    },
    "FileSystem": {
      "Type": "AWS::EFS::FileSystem",
      "Properties": {
        "PerformanceMode": "generalPurpose",
        "FileSystemTags": [
          {
            "Key": "Name",
            "Value": { "Ref" : "VolumeName" }
          }
        ]
      }
    },
    "MountTarget": {
      "Type": "AWS::EFS::MountTarget",
      "Properties": {
        "FileSystemId": { "Ref": "FileSystem" },
        "SubnetId": { "Ref": "Subnet" },
        "SecurityGroups": [ { "Ref": "MountTargetSecurityGroup" } ]        
      }
    },
    "LaunchConfiguration": {
      "Type": "AWS::AutoScaling::LaunchConfiguration",
      "Metadata" : {
        "AWS::CloudFormation::Init" : {
          "configSets" : {
            "MountConfig" : [ "setup", "mount" ]
          },
          "setup" : {
            "packages" : {
              "yum" : {
                "nfs-utils" : []
              }
            },
            "files" : {
              "/home/ec2-user/post_nfsstat" : {
                "content" : { "Fn::Join" : [ "", [
                      "#!/bin/bash\n",
                      "\n",
                      "INPUT=\"$(cat)\"\n",
                      "CW_JSON_OPEN='{ \"Namespace\": \"EFS\", \"MetricData\": [ '\n",
                      "CW_JSON_CLOSE=' ] }'\n",
                      "CW_JSON_METRIC=''\n",
                      "METRIC_COUNTER=0\n",
                      "\n",
                      "for COL in 1 2 3 4 5 6; do\n",
                      "\n",
                      " COUNTER=0\n",
                      " METRIC_FIELD=$COL\n",
                      " DATA_FIELD=$(($COL+($COL-1)))\n",
                      "\n",
                      " while read line; do\n",
                      "   if [[ COUNTER -gt 0 ]]; then\n",
                      "\n",
                      "     LINE=`echo $line | tr -s ' ' `\n",
                      "     AWS_COMMAND=\"aws cloudwatch put-metric-data --region ", { "Ref": "AWS::Region" }, "\"\n",
                      "     MOD=$(( $COUNTER % 2))\n",
                      "\n",
                      "     if [ $MOD -eq 1 ]; then\n",
                      "       METRIC_NAME=`echo $LINE | cut -d ' ' -f $METRIC_FIELD`\n",
                      "     else\n",
                      "       METRIC_VALUE=`echo $LINE | cut -d ' ' -f $DATA_FIELD`\n",
                      "     fi\n",
                      "\n",
                      "     if [[ -n \"$METRIC_NAME\" && -n \"$METRIC_VALUE\" ]]; then\n",
                      "       INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)\n",
                      "       CW_JSON_METRIC=\"$CW_JSON_METRIC { \\\"MetricName\\\": \\\"$METRIC_NAME\\\", \\\"Dimensions\\\": [{\\\"Name\\\": \\\"InstanceId\\\", \\\"Value\\\": \\\"$INSTANCE_ID\\\"} ], \\\"Value\\\": $METRIC_VALUE },\"\n",
                      "       unset METRIC_NAME\n",
                      "       unset METRIC_VALUE\n",
                      "\n",
                      "       METRIC_COUNTER=$((METRIC_COUNTER+1))\n",
                      "       if [ $METRIC_COUNTER -eq 20 ]; then\n",
                      "         # 20 is max metric collection size, so we have to submit here\n",
                      "         aws cloudwatch put-metric-data --region ", { "Ref": "AWS::Region" }, " --cli-input-json \"`echo $CW_JSON_OPEN ${CW_JSON_METRIC%?} $CW_JSON_CLOSE`\"\n",
                      "\n",
                      "         # reset\n",
                      "         METRIC_COUNTER=0\n",
                      "         CW_JSON_METRIC=''\n",
                      "       fi\n",
                      "     fi  \n",
                      "\n",
                      "\n",
                      "\n",
                      "     COUNTER=$((COUNTER+1))\n",
                      "   fi\n",
                      "\n",
                      "   if [[ \"$line\" == \"Client nfs v4:\" ]]; then\n",
                      "     # the next line is the good stuff \n",
                      "     COUNTER=$((COUNTER+1))\n",
                      "   fi\n",
                      " done <<< \"$INPUT\"\n",
                      "done\n",
                      "\n",
                      "# submit whatever is left\n",
                      "aws cloudwatch put-metric-data --region ", { "Ref": "AWS::Region" }, " --cli-input-json \"`echo $CW_JSON_OPEN ${CW_JSON_METRIC%?} $CW_JSON_CLOSE`\""
                    ] ] },
                "mode": "000755",
                "owner": "ec2-user",
                "group": "ec2-user"
              },
              "/home/ec2-user/crontab" : {
                "content" : { "Fn::Join" : [ "", [
                  "* * * * * /usr/sbin/nfsstat | /home/ec2-user/post_nfsstat\n"
                ] ] },
                "owner": "ec2-user",
                "group": "ec2-user"
              }
            },
            "commands" : {
              "01_createdir" : {
                "command" : {"Fn::Join" : [ "", [ "mkdir /", { "Ref" : "MountPoint" }]]}
              }
            }
          },
          "mount" : {
            "commands" : {
              "01_mount" : {
                "command" : { "Fn::Sub": "sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 ${FileSystem}.efs.${AWS::Region}.amazonaws.com:/ /${MountPoint}"}
              },
              "02_permissions" : {
                "command" : {"Fn::Join" : [ "", [ "chown ec2-user:ec2-user /", { "Ref" : "MountPoint" }]]}
              }
            }
          }
        }
      },
      "Properties": {
        "AssociatePublicIpAddress" : true,
        "ImageId": {
          "Fn::FindInMap": [ "AWSRegionArch2AMI", { "Ref": "AWS::Region" }, {
            "Fn::FindInMap": [ "AWSInstanceType2Arch", { "Ref": "InstanceType" }, "Arch" ]
          } ]
        },
        "InstanceType": { "Ref": "InstanceType" },
        "KeyName": { "Ref": "KeyName" },
        "SecurityGroups": [ { "Ref": "InstanceSecurityGroup" } ],
        "IamInstanceProfile" : { "Ref" : "CloudWatchPutMetricsInstanceProfile" },
        "UserData"       : { "Fn::Base64" : { "Fn::Join" : ["", [
             "#!/bin/bash -xe\n",
             "yum install -y aws-cfn-bootstrap\n",

             "/opt/aws/bin/cfn-init -v ",
             "         --stack ", { "Ref" : "AWS::StackName" },
             "         --resource LaunchConfiguration ",
             "         --configsets MountConfig ",
             "         --region ", { "Ref" : "AWS::Region" }, "\n",

             "crontab /home/ec2-user/crontab\n",

             "/opt/aws/bin/cfn-signal -e $? ",
             "         --stack ", { "Ref" : "AWS::StackName" },
             "         --resource AutoScalingGroup ",
             "         --region ", { "Ref" : "AWS::Region" }, "\n"
        ]]}}
      }
    },
    "AutoScalingGroup": {
      "Type": "AWS::AutoScaling::AutoScalingGroup",
      "DependsOn": ["MountTarget", "GatewayToInternet"],
      "CreationPolicy" : {
        "ResourceSignal" : {
          "Timeout" : "PT15M",
          "Count"   : { "Ref": "AsgMaxSize" }
        }
      },
      "Properties": {
        "VPCZoneIdentifier": [ { "Ref": "Subnet" } ],
        "LaunchConfigurationName": { "Ref": "LaunchConfiguration" },
        "MinSize": "1",
        "MaxSize": { "Ref": "AsgMaxSize" },
        "DesiredCapacity": { "Ref": "AsgMaxSize" },
        "Tags": [ {
          "Key": "Name",
          "Value": "EFS FileSystem Mounted Instance",
          "PropagateAtLaunch": "true"
        } ]
      }
    }
  },
  "Outputs" : {
    "MountTargetID" : {
      "Description" : "Mount target ID",
      "Value" :  { "Ref" : "MountTarget" }
    },
    "FileSystemID" : {
      "Description" : "File system ID",
      "Value" :  { "Ref" : "FileSystem" }
    }
  }
}
```

## YAML
<a name="quickref-efs-example-1.yaml"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Description: This template creates an Amazon EFS file system and mount target and
  associates it with Amazon EC2 instances in an Auto Scaling group. **WARNING** This
  template creates Amazon EC2 instances and related resources. You will be billed
  for the AWS resources used if you create a stack from this template.
Parameters:
  InstanceType:
    Description: WebServer EC2 instance type
    Type: String
    Default: t2.small
    AllowedValues:
      - t1.micro
      - t2.nano
      - t2.micro
      - t2.small
      - t2.medium
      - t2.large
      - m1.small
      - m1.medium
      - m1.large
      - m1.xlarge
      - m2.xlarge
      - m2.2xlarge
      - m2.4xlarge
      - m3.medium
      - m3.large
      - m3.xlarge
      - m3.2xlarge
      - m4.large
      - m4.xlarge
      - m4.2xlarge
      - m4.4xlarge
      - m4.10xlarge
      - c1.medium
      - c1.xlarge
      - c3.large
      - c3.xlarge
      - c3.2xlarge
      - c3.4xlarge
      - c3.8xlarge
      - c4.large
      - c4.xlarge
      - c4.2xlarge
      - c4.4xlarge
      - c4.8xlarge
      - g2.2xlarge
      - g2.8xlarge
      - r3.large
      - r3.xlarge
      - r3.2xlarge
      - r3.4xlarge
      - r3.8xlarge
      - i2.xlarge
      - i2.2xlarge
      - i2.4xlarge
      - i2.8xlarge
      - d2.xlarge
      - d2.2xlarge
      - d2.4xlarge
      - d2.8xlarge
      - hi1.4xlarge
      - hs1.8xlarge
      - cr1.8xlarge
      - cc2.8xlarge
      - cg1.4xlarge
    ConstraintDescription: must be a valid EC2 instance type.
  KeyName:
    Type: AWS::EC2::KeyPair::KeyName
    Description: Name of an existing EC2 key pair to enable SSH access to the ECS
      instances
  AsgMaxSize:
    Type: Number
    Description: Maximum size and initial desired capacity of Auto Scaling Group
    Default: '2'
  SSHLocation:
    Description: The IP address range that can be used to connect to the EC2 instances
      by using SSH
    Type: String
    MinLength: '9'
    MaxLength: '18'
    Default: 0.0.0.0/0
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
  VolumeName:
    Description: The name to be used for the EFS volume
    Type: String
    MinLength: '1'
    Default: myEFSvolume
  MountPoint:
    Description: The Linux mount point for the EFS volume
    Type: String
    MinLength: '1'
    Default: myEFSvolume
Mappings:
  AWSInstanceType2Arch:
    t1.micro:
      Arch: HVM64
    t2.nano:
      Arch: HVM64
    t2.micro:
      Arch: HVM64
    t2.small:
      Arch: HVM64
    t2.medium:
      Arch: HVM64
    t2.large:
      Arch: HVM64
    m1.small:
      Arch: HVM64
    m1.medium:
      Arch: HVM64
    m1.large:
      Arch: HVM64
    m1.xlarge:
      Arch: HVM64
    m2.xlarge:
      Arch: HVM64
    m2.2xlarge:
      Arch: HVM64
    m2.4xlarge:
      Arch: HVM64
    m3.medium:
      Arch: HVM64
    m3.large:
      Arch: HVM64
    m3.xlarge:
      Arch: HVM64
    m3.2xlarge:
      Arch: HVM64
    m4.large:
      Arch: HVM64
    m4.xlarge:
      Arch: HVM64
    m4.2xlarge:
      Arch: HVM64
    m4.4xlarge:
      Arch: HVM64
    m4.10xlarge:
      Arch: HVM64
    c1.medium:
      Arch: HVM64
    c1.xlarge:
      Arch: HVM64
    c3.large:
      Arch: HVM64
    c3.xlarge:
      Arch: HVM64
    c3.2xlarge:
      Arch: HVM64
    c3.4xlarge:
      Arch: HVM64
    c3.8xlarge:
      Arch: HVM64
    c4.large:
      Arch: HVM64
    c4.xlarge:
      Arch: HVM64
    c4.2xlarge:
      Arch: HVM64
    c4.4xlarge:
      Arch: HVM64
    c4.8xlarge:
      Arch: HVM64
    g2.2xlarge:
      Arch: HVMG2
    g2.8xlarge:
      Arch: HVMG2
    r3.large:
      Arch: HVM64
    r3.xlarge:
      Arch: HVM64
    r3.2xlarge:
      Arch: HVM64
    r3.4xlarge:
      Arch: HVM64
    r3.8xlarge:
      Arch: HVM64
    i2.xlarge:
      Arch: HVM64
    i2.2xlarge:
      Arch: HVM64
    i2.4xlarge:
      Arch: HVM64
    i2.8xlarge:
      Arch: HVM64
    d2.xlarge:
      Arch: HVM64
    d2.2xlarge:
      Arch: HVM64
    d2.4xlarge:
      Arch: HVM64
    d2.8xlarge:
      Arch: HVM64
    hi1.4xlarge:
      Arch: HVM64
    hs1.8xlarge:
      Arch: HVM64
    cr1.8xlarge:
      Arch: HVM64
    cc2.8xlarge:
      Arch: HVM64
  AWSRegionArch2AMI:
    us-east-1:
      HVM64: ami-0ff8a91507f77f867
      HVMG2: ami-0a584ac55a7631c0c
    us-west-2:
      HVM64: ami-a0cfeed8
      HVMG2: ami-0e09505bc235aa82d
    us-west-1:
      HVM64: ami-0bdb828fd58c52235
      HVMG2: ami-066ee5fd4a9ef77f1
    eu-west-1:
      HVM64: ami-047bb4163c506cd98
      HVMG2: ami-0a7c483d527806435
    eu-west-2:
      HVM64: ami-f976839e
      HVMG2: NOT_SUPPORTED
    eu-west-3:
      HVM64: ami-0ebc281c20e89ba4b
      HVMG2: NOT_SUPPORTED
    eu-central-1:
      HVM64: ami-0233214e13e500f77
      HVMG2: ami-06223d46a6d0661c7
    ap-northeast-1:
      HVM64: ami-06cd52961ce9f0d85
      HVMG2: ami-053cdd503598e4a9d
    ap-northeast-2:
      HVM64: ami-0a10b2721688ce9d2
      HVMG2: NOT_SUPPORTED
    ap-northeast-3:
      HVM64: ami-0d98120a9fb693f07
      HVMG2: NOT_SUPPORTED
    ap-southeast-1:
      HVM64: ami-08569b978cc4dfa10
      HVMG2: ami-0be9df32ae9f92309
    ap-southeast-2:
      HVM64: ami-09b42976632b27e9b
      HVMG2: ami-0a9ce9fecc3d1daf8
    ap-south-1:
      HVM64: ami-0912f71e06545ad88
      HVMG2: ami-097b15e89dbdcfcf4
    us-east-2:
      HVM64: ami-0b59bfac6be064b78
      HVMG2: NOT_SUPPORTED
    ca-central-1:
      HVM64: ami-0b18956f
      HVMG2: NOT_SUPPORTED
    sa-east-1:
      HVM64: ami-07b14488da8ea02a0
      HVMG2: NOT_SUPPORTED
    cn-north-1:
      HVM64: ami-0a4eaf6c4454eda75
      HVMG2: NOT_SUPPORTED
    cn-northwest-1:
      HVM64: ami-6b6a7d09
      HVMG2: NOT_SUPPORTED
Resources:
  CloudWatchPutMetricsRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - ec2.amazonaws.com
          Action:
          - sts:AssumeRole
      Path: "/"
  CloudWatchPutMetricsRolePolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: CloudWatch_PutMetricData
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Sid: CloudWatchPutMetricData
          Effect: Allow
          Action:
          - cloudwatch:PutMetricData
          Resource:
          - "*"
      Roles:
      - Ref: CloudWatchPutMetricsRole
  CloudWatchPutMetricsInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: "/"
      Roles:
      - Ref: CloudWatchPutMetricsRole
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      EnableDnsSupport: 'true'
      EnableDnsHostnames: 'true'
      CidrBlock: 10.0.0.0/16
      Tags:
      - Key: Application
        Value:
          Ref: AWS::StackId
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
      - Key: Application
        Value:
          Ref: AWS::StackName
      - Key: Network
        Value: Public
  GatewayToInternet:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId:
        Ref: VPC
      InternetGatewayId:
        Ref: InternetGateway
  RouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: VPC
  SubnetRouteTableAssoc:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: RouteTable
      SubnetId:
        Ref: Subnet
  InternetGatewayRoute:
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      RouteTableId:
        Ref: RouteTable
      GatewayId:
        Ref: InternetGateway
  Subnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId:
        Ref: VPC
      CidrBlock: 10.0.0.0/24
      Tags:
      - Key: Application
        Value:
          Ref: AWS::StackId
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId:
        Ref: VPC
      GroupDescription: Enable SSH access via port 22
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp:
          Ref: SSHLocation
      - IpProtocol: tcp
        FromPort: 80
        ToPort: 80
        CidrIp: 0.0.0.0/0
  MountTargetSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId:
        Ref: VPC
      GroupDescription: Security group for mount target
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 2049
        ToPort: 2049
        CidrIp: 0.0.0.0/0
  FileSystem:
    Type: AWS::EFS::FileSystem
    Properties:
      PerformanceMode: generalPurpose
      FileSystemTags:
      - Key: Name
        Value:
          Ref: VolumeName
  MountTarget:
    Type: AWS::EFS::MountTarget
    Properties:
      FileSystemId:
        Ref: FileSystem
      SubnetId:
        Ref: Subnet
      SecurityGroups:
      - Ref: MountTargetSecurityGroup
  LaunchConfiguration:
    Type: AWS::AutoScaling::LaunchConfiguration
    Metadata:
      AWS::CloudFormation::Init:
        configSets:
          MountConfig:
          - setup
          - mount
        setup:
          packages:
            yum:
              nfs-utils: []
          files:
            "/home/ec2-user/post_nfsstat":
              content: !Sub |
                #!/bin/bash

                INPUT="$(cat)"
                CW_JSON_OPEN='{ "Namespace": "EFS", "MetricData": [ '
                CW_JSON_CLOSE=' ] }'
                CW_JSON_METRIC=''
                METRIC_COUNTER=0

                for COL in 1 2 3 4 5 6; do

                 COUNTER=0
                 METRIC_FIELD=$COL
                 DATA_FIELD=$(($COL+($COL-1)))

                 while read line; do
                   if [[ COUNTER -gt 0 ]]; then

                     LINE=`echo $line | tr -s ' ' `
                     AWS_COMMAND="aws cloudwatch put-metric-data --region ${AWS::Region}"
                     MOD=$(( $COUNTER % 2))

                     if [ $MOD -eq 1 ]; then
                       METRIC_NAME=`echo $LINE | cut -d ' ' -f $METRIC_FIELD`
                     else
                       METRIC_VALUE=`echo $LINE | cut -d ' ' -f $DATA_FIELD`
                     fi

                     if [[ -n "$METRIC_NAME" && -n "$METRIC_VALUE" ]]; then
                       INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
                       CW_JSON_METRIC="$CW_JSON_METRIC { \"MetricName\": \"$METRIC_NAME\", \"Dimensions\": [{\"Name\": \"InstanceId\", \"Value\": \"$INSTANCE_ID\"} ], \"Value\": $METRIC_VALUE },"
                       unset METRIC_NAME
                       unset METRIC_VALUE

                       METRIC_COUNTER=$((METRIC_COUNTER+1))
                       if [ $METRIC_COUNTER -eq 20 ]; then
                         # 20 is max metric collection size, so we have to submit here
                         aws cloudwatch put-metric-data --region ${AWS::Region} --cli-input-json "`echo $CW_JSON_OPEN ${!CW_JSON_METRIC%?} $CW_JSON_CLOSE`"

                         # reset
                         METRIC_COUNTER=0
                         CW_JSON_METRIC=''
                       fi
                     fi



                     COUNTER=$((COUNTER+1))
                   fi

                   if [[ "$line" == "Client nfs v4:" ]]; then
                     # the next line is the good stuff
                     COUNTER=$((COUNTER+1))
                   fi
                 done <<< "$INPUT"
                done

                # submit whatever is left
                aws cloudwatch put-metric-data --region ${AWS::Region} --cli-input-json "`echo $CW_JSON_OPEN ${!CW_JSON_METRIC%?} $CW_JSON_CLOSE`"
              mode: '000755'
              owner: ec2-user
              group: ec2-user
            "/home/ec2-user/crontab":
              content: "* * * * * /usr/sbin/nfsstat | /home/ec2-user/post_nfsstat\n"
              owner: ec2-user
              group: ec2-user
          commands:
            01_createdir:
              command: !Sub "mkdir /${MountPoint}"
        mount:
          commands:
            01_mount:
              command: !Sub >
                mount -t nfs4 -o nfsvers=4.1 ${FileSystem}.efs.${AWS::Region}.amazonaws.com:/ /${MountPoint}
            02_permissions:
              command: !Sub "chown ec2-user:ec2-user /${MountPoint}"
    Properties:
      AssociatePublicIpAddress: true
      ImageId:
        Fn::FindInMap:
        - AWSRegionArch2AMI
        - Ref: AWS::Region
        - Fn::FindInMap:
          - AWSInstanceType2Arch
          - Ref: InstanceType
          - Arch
      InstanceType:
        Ref: InstanceType
      KeyName:
        Ref: KeyName
      SecurityGroups:
      - Ref: InstanceSecurityGroup
      IamInstanceProfile:
        Ref: CloudWatchPutMetricsInstanceProfile
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash -xe
          yum install -y aws-cfn-bootstrap
          /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchConfiguration --configsets MountConfig --region ${AWS::Region}
          crontab /home/ec2-user/crontab
          /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource AutoScalingGroup --region ${AWS::Region}
  AutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    DependsOn:
    - MountTarget
    - GatewayToInternet
    CreationPolicy:
      ResourceSignal:
        Timeout: PT15M
        Count:
          Ref: AsgMaxSize
    Properties:
      VPCZoneIdentifier:
      - Ref: Subnet
      LaunchConfigurationName:
        Ref: LaunchConfiguration
      MinSize: '1'
      MaxSize:
        Ref: AsgMaxSize
      DesiredCapacity:
        Ref: AsgMaxSize
      Tags:
      - Key: Name
        Value: EFS FileSystem Mounted Instance
        PropagateAtLaunch: 'true'
Outputs:
  MountTargetID:
    Description: Mount target ID
    Value:
      Ref: MountTarget
  FileSystemID:
    Description: File system ID
    Value:
      Ref: FileSystem
```

# Elastic Beanstalk 模板代码段
<a name="quickref-elasticbeanstalk"></a>

通过 Elastic Beanstalk，您可以迅速在 Amazon 中部署和管理应用程序，而无需为运行这些应用程序的基础设施操心。以下示例模板可以帮助您在 Amazon CloudFormation 模板中描述 Elastic Beanstalk 资源。

## Elastic Beanstalk 示例 PHP
<a name="quickref-elasticbeanstalk-sampleenv"></a>

下面的示例模板部署一个存储在 Amazon S3 存储桶中的示例 PHP Web 应用程序。该环境也是一种自动扩缩的负载均衡环境，至少包含两个、最多包含六个 Amazon EC2 实例。它显示了一个使用传统启动配置的 Elastic Beanstalk 环境。有关改用启动模板的信息，请参阅《*Amazon Elastic Beanstalk开发者指南*》中的[启动模板](https://docs.amazonaws.cn/elasticbeanstalk/latest/dg/environments-cfg-autoscaling-launch-templates.html)。

使用解决方案堆栈名称替换 `solution-stack`（平台版本）。如需可用解决方案堆栈的列表，请使用 Amazon CLI 命令 **aws elasticbeanstalk list-available-solution-stacks**。

### JSON
<a name="quickref-elasticbeanstalk-example-1.json"></a>

```
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Resources": {
        "sampleApplication": {
            "Type": "AWS::ElasticBeanstalk::Application",
            "Properties": {
                "Description": "AWS Elastic Beanstalk Sample Application"
            }
        },
        "sampleApplicationVersion": {
            "Type": "AWS::ElasticBeanstalk::ApplicationVersion",
            "Properties": {
                "ApplicationName": {
                    "Ref": "sampleApplication"
                },
                "Description": "AWS ElasticBeanstalk Sample Application Version",
                "SourceBundle": {
                    "S3Bucket": {
                        "Fn::Sub": "elasticbeanstalk-samples-${AWS::Region}"
                    },
                    "S3Key": "php-newsample-app.zip"
                }
            }
        },
        "sampleConfigurationTemplate": {
            "Type": "AWS::ElasticBeanstalk::ConfigurationTemplate",
            "Properties": {
                "ApplicationName": {
                    "Ref": "sampleApplication"
                },
                "Description": "AWS ElasticBeanstalk Sample Configuration Template",
                "OptionSettings": [
                    {
                        "Namespace": "aws:autoscaling:asg",
                        "OptionName": "MinSize",
                        "Value": "2"
                    },
                    {
                        "Namespace": "aws:autoscaling:asg",
                        "OptionName": "MaxSize",
                        "Value": "6"
                    },
                    {
                        "Namespace": "aws:elasticbeanstalk:environment",
                        "OptionName": "EnvironmentType",
                        "Value": "LoadBalanced"
                    },
                    {
                        "Namespace": "aws:autoscaling:launchconfiguration",
                        "OptionName": "IamInstanceProfile",
                        "Value": {
                            "Ref": "MyInstanceProfile"
                        }
                    }
                ],
                "SolutionStackName": "solution-stack"
            }
        },
        "sampleEnvironment": {
            "Type": "AWS::ElasticBeanstalk::Environment",
            "Properties": {
                "ApplicationName": {
                    "Ref": "sampleApplication"
                },
                "Description": "AWS ElasticBeanstalk Sample Environment",
                "TemplateName": {
                    "Ref": "sampleConfigurationTemplate"
                },
                "VersionLabel": {
                    "Ref": "sampleApplicationVersion"
                }
            }
        },
        "MyInstanceRole": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",		 	 	 
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": {
                                "Service": [
                                    "ec2.amazonaws.com"
                                ]
                            },
                            "Action": [
                                "sts:AssumeRole"
                            ]
                        }
                    ]
                },
                "Description": "Beanstalk EC2 role",
                "ManagedPolicyArns": [
                    "arn:aws:iam::aws:policy/AWSElasticBeanstalkWebTier",
                    "arn:aws:iam::aws:policy/AWSElasticBeanstalkMulticontainerDocker",
                    "arn:aws:iam::aws:policy/AWSElasticBeanstalkWorkerTier"
                ]
            }
        },
        "MyInstanceProfile": {
            "Type": "AWS::IAM::InstanceProfile",
            "Properties": {
                "Roles": [
                    {
                        "Ref": "MyInstanceRole"
                    }
                ]
            }
        }
    }
}
```

### YAML
<a name="quickref-elasticbeanstalk-example-1.yaml"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  sampleApplication:
    Type: AWS::ElasticBeanstalk::Application
    Properties:
      Description: AWS Elastic Beanstalk Sample Application
  sampleApplicationVersion:
    Type: AWS::ElasticBeanstalk::ApplicationVersion
    Properties:
      ApplicationName:
        Ref: sampleApplication
      Description: AWS ElasticBeanstalk Sample Application Version
      SourceBundle:
        S3Bucket: !Sub "elasticbeanstalk-samples-${AWS::Region}"
        S3Key: php-newsample-app.zip
  sampleConfigurationTemplate:
    Type: AWS::ElasticBeanstalk::ConfigurationTemplate
    Properties:
      ApplicationName:
        Ref: sampleApplication
      Description: AWS ElasticBeanstalk Sample Configuration Template
      OptionSettings:
      - Namespace: aws:autoscaling:asg
        OptionName: MinSize
        Value: '2'
      - Namespace: aws:autoscaling:asg
        OptionName: MaxSize
        Value: '6'
      - Namespace: aws:elasticbeanstalk:environment
        OptionName: EnvironmentType
        Value: LoadBalanced
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value: !Ref MyInstanceProfile        
      SolutionStackName: solution-stack
  sampleEnvironment:
    Type: AWS::ElasticBeanstalk::Environment
    Properties:
      ApplicationName:
        Ref: sampleApplication
      Description: AWS ElasticBeanstalk Sample Environment
      TemplateName:
        Ref: sampleConfigurationTemplate
      VersionLabel:
        Ref: sampleApplicationVersion
  MyInstanceRole:
    Type: AWS::IAM::Role
    Properties: 
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      Description: Beanstalk EC2 role
      ManagedPolicyArns: 
        - arn:aws:iam::aws:policy/AWSElasticBeanstalkWebTier
        - arn:aws:iam::aws:policy/AWSElasticBeanstalkMulticontainerDocker
        - arn:aws:iam::aws:policy/AWSElasticBeanstalkWorkerTier
  MyInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties: 
      Roles:
        - !Ref MyInstanceRole
```

# Elastic Load Balancing 模板代码段
<a name="quickref-elb"></a>

要创建应用程序负载均衡器、网络负载均衡器或网关负载均衡器，请使用以 `AWS::ElasticLoadBalancingV2` 开头的 V2 资源类型。要创建经典负载均衡器，请使用以 `AWS::ElasticLoadBalancing` 开头的资源类型。

**Topics**
+ [

## ELBv2 资源
](#scenario-elbv2-load-balancer)
+ [

## 经典负载均衡器资源
](#scenario-elb-load-balancer)

## ELBv2 资源
<a name="scenario-elbv2-load-balancer"></a>

此示例定义了一个应用程序负载均衡器，该负载均衡器具有 HTTP 侦听器和用于将流量转发到目标组的默认操作。负载均衡器使用默认运行状况检查设置。目标组有两个注册的 EC2 实例。

------
#### [ YAML ]

```
Resources:
  myLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: my-alb
      Type: application
      Scheme: internal
      Subnets: 
        - !Ref subnet-AZ1
        - !Ref subnet-AZ2
      SecurityGroups: 
        - !Ref mySecurityGroup

  myHTTPlistener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref myLoadBalancer
      Protocol: HTTP
      Port: 80
      DefaultActions:
        - Type: "forward"
          TargetGroupArn: !Ref myTargetGroup
                        
  myTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: "my-target-group"
      Protocol: HTTP
      Port: 80
      TargetType: instance
      VpcId: !Ref myVPC
      Targets:
        - Id: !GetAtt Instance1.InstanceId
          Port: 80
        - Id: !GetAtt Instance2.InstanceId
          Port: 80
```

------
#### [ JSON ]

```
{
    "Resources": {
        "myLoadBalancer": {
            "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
            "Properties": {
                "Name": "my-alb",
                "Type": "application",
                "Scheme": "internal",
                "Subnets": [
                    {
                        "Ref": "subnet-AZ1"
                    },
                    {
                        "Ref": "subnet-AZ2"
                    }
                ],
                "SecurityGroups": [
                    {
                        "Ref": "mySecurityGroup"
                    }
                ]
            }
        },
        "myHTTPlistener": {
            "Type": "AWS::ElasticLoadBalancingV2::Listener",
            "Properties": {
                "LoadBalancerArn": {
                    "Ref": "myLoadBalancer"
                },
                "Protocol": "HTTP",
                "Port": 80,
                "DefaultActions": [
                    {
                        "Type": "forward",
                        "TargetGroupArn": {
                            "Ref": "myTargetGroup"
                        }
                    }
                ]
            }
        },
        "myTargetGroup": {
            "Type": "AWS::ElasticLoadBalancingV2::TargetGroup",
            "Properties": {
                "Name": "my-target-group",
                "Protocol": "HTTP",
                "Port": 80,
                "TargetType": "instance",
                "VpcId": {
                    "Ref": "myVPC"
                },
                "Targets": [
                    {
                        "Id": {
                            "Fn::GetAtt": [
                                "Instance1",
                                "InstanceId"
                            ]
                        },
                        "Port": 80
                    },
                    {
                        "Id": {
                            "Fn::GetAtt": [
                                "Instance2",
                                "InstanceId"
                            ]
                        },
                        "Port": 80
                    }
                ]
            }
        }
    }
}
```

------

## 经典负载均衡器资源
<a name="scenario-elb-load-balancer"></a>

此示例定义了一个经典负载均衡器，该负载均衡器具有 HTTP 侦听器且没有注册的 EC2 实例。负载均衡器使用默认运行状况检查设置。

------
#### [ YAML ]

```
myLoadBalancer:
  Type: AWS::ElasticLoadBalancing::LoadBalancer
  Properties:
    AvailabilityZones:
    - "cn-north-1a"
    Listeners:
    - LoadBalancerPort: '80'
      InstancePort: '80'
      Protocol: HTTP
```

------
#### [ JSON ]

```
"myLoadBalancer" : {
    "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
    "Properties" : {
        "AvailabilityZones" : [ "cn-north-1a" ],
        "Listeners" : [ {
            "LoadBalancerPort" : "80",
            "InstancePort" : "80",
            "Protocol" : "HTTP"
        } ]
    }
}
```

------

此示例定义了一个经典负载均衡器，该负载均衡器具有 HTTP 侦听器、两个注册的 EC2 实例和自定义运行状况检查设置。

------
#### [ YAML ]

```
myClassicLoadBalancer:
  Type: AWS::ElasticLoadBalancing::LoadBalancer
  Properties:
    AvailabilityZones:
    - "cn-north-1a"
    Instances:
    - Ref: Instance1
    - Ref: Instance2
    Listeners:
    - LoadBalancerPort: '80'
      InstancePort: '80'
      Protocol: HTTP
    HealthCheck:
      Target: HTTP:80/
      HealthyThreshold: '3'
      UnhealthyThreshold: '5'
      Interval: '30'
      Timeout: '5'
```

------
#### [ JSON ]

```
"myClassicLoadBalancer" : {
    "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
    "Properties" : {
        "AvailabilityZones" : [ "cn-north-1a" ],
        "Instances" : [
            { "Ref" : "Instance1" },
            { "Ref" : "Instance2" }
        ],
        "Listeners" : [ {
            "LoadBalancerPort" : "80",
            "InstancePort" : "80",
            "Protocol" : "HTTP"
        } ],

        "HealthCheck" : {
            "Target" : "HTTP:80/",
            "HealthyThreshold" : "3",
            "UnhealthyThreshold" : "5",
            "Interval" : "30",
            "Timeout" : "5"
        }
    }
}
```

------

# Amazon Identity and Access Management 模板代码段
<a name="quickref-iam"></a>

本部分包含 Amazon Identity and Access Management 模板代码段。

**Topics**
+ [

## 声明 IAM 用户资源
](#scenario-iam-user)
+ [

## 声明 IAM 访问密钥资源
](#scenario-iam-accesskey)
+ [

## 声明 IAM 组资源
](#scenario-iam-group)
+ [

## 将用户添加到组中
](#scenario-iam-addusertogroup)
+ [

## 声明 IAM policy
](#scenario-iam-policy)
+ [

## 声明 Amazon S3 存储桶策略
](#scenario-bucket-policy)
+ [

## 声明 Amazon SNS 主题策略
](#scenario-sns-policy)
+ [

## 声明 Amazon SQS 策略
](#scenario-sqs-policy)
+ [

## IAM 角色模板示例
](#scenarios-iamroles)

**重要**  
使用包含 IAM 资源的模板创建或更新堆栈时，您必须确认 IAM 功能的使用。有关更多信息，请参阅 [确认 CloudFormation 模板中的 IAM 资源](control-access-with-iam.md#using-iam-capabilities)。

## 声明 IAM 用户资源
<a name="scenario-iam-user"></a>

此代码段显示如何声明 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-user.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-user.html) 资源以创建 IAM 用户。此用户使用路径 `"/"` 和密码为 `myP@ssW0rd` 的登录配置文件进行声明。

名为 `giveaccesstoqueueonly` 的策略文档为用户授予权限以对 Amazon SQS 队列资源 `myqueue` 执行所有 Amazon SQS 操作，并拒绝对所有其他 Amazon SQS 队列资源进行访问。`Fn::GetAtt` 函数将获取 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sqs-queue.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sqs-queue.html) 资源 `myqueue` 的 Arn 属性。

可以在用户中添加名为 `giveaccesstotopiconly` 的策略文档，以便为用户授予权限以对 Amazon SNS 主题资源 `mytopic` 执行所有 Amazon SNS 操作，并拒绝对所有其他 Amazon SNS 资源进行访问。`Ref` 函数将获取 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sns-topic.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sns-topic.html) 资源 `mytopic` 的 ARN。

### JSON
<a name="quickref-iam-example-1.json"></a>

```
"myuser" : {
   "Type" : "AWS::IAM::User",
   "Properties" : {
      "Path" : "/",
      "LoginProfile" : {
         "Password" : "myP@ssW0rd"
      },
      "Policies" : [ {
         "PolicyName" : "giveaccesstoqueueonly",
         "PolicyDocument" : {
            "Version": "2012-10-17",		 	 	 
            "Statement" : [ {
               "Effect" : "Allow",
               "Action" : [ "sqs:*" ],
               "Resource" : [ {
                  "Fn::GetAtt" : [ "myqueue", "Arn" ]
               } ]
            }, {
               "Effect" : "Deny",
               "Action" : [ "sqs:*" ],
               "NotResource" : [ {
                  "Fn::GetAtt" : [ "myqueue", "Arn" ]
               } ]
            }
         ] }
      }, {
         "PolicyName" : "giveaccesstotopiconly",
         "PolicyDocument" : {
            "Version": "2012-10-17",		 	 	 
            "Statement" : [ {
               "Effect" : "Allow",
               "Action" : [ "sns:*" ],
               "Resource" : [ { "Ref" : "mytopic" } ]
            }, {
               "Effect" : "Deny",
               "Action" : [ "sns:*" ],
               "NotResource" : [ { "Ref" : "mytopic" } ]
            } ]
         }
      } ]
   }
}
```

### YAML
<a name="quickref-iam-example-1.yaml"></a>

```
myuser:
  Type: AWS::IAM::User
  Properties:
    Path: "/"
    LoginProfile:
      Password: myP@ssW0rd
    Policies:
    - PolicyName: giveaccesstoqueueonly
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Action:
          - sqs:*
          Resource:
          - !GetAtt myqueue.Arn
        - Effect: Deny
          Action:
          - sqs:*
          NotResource:
          - !GetAtt myqueue.Arn
    - PolicyName: giveaccesstotopiconly
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Action:
          - sns:*
          Resource:
          - !Ref mytopic
        - Effect: Deny
          Action:
          - sns:*
          NotResource:
          - !Ref mytopic
```

## 声明 IAM 访问密钥资源
<a name="scenario-iam-accesskey"></a>

### 
<a name="quickref-iam-access-key"></a>

此代码段显示的是 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-accesskey.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-accesskey.html) 资源。`myaccesskey` 资源创建访问密钥并将其分配给在模板中声明为 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-user.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-user.html) 资源的 IAM 用户。

#### JSON
<a name="quickref-iam-example-2.json"></a>

```
"myaccesskey" : {
   "Type" : "AWS::IAM::AccessKey",
   "Properties" : {
      "UserName" : { "Ref" : "myuser" }
   }
}
```

#### YAML
<a name="quickref-iam-example-2.yaml"></a>

```
myaccesskey:
  Type: AWS::IAM::AccessKey
  Properties:
    UserName:
      !Ref myuser
```

### 
<a name="quickref-iam-access-key-2"></a>

您可使用 `AWS::IAM::AccessKey` 函数获取 `Fn::GetAtt` 资源的私有密钥。检索密钥的一种方式是将其放入 `Output` 值中。您可使用 `Ref` 函数获取访问密钥。以下 `Output` 值声明获取 `myaccesskey` 的访问密钥和私有密钥。

#### JSON
<a name="quickref-iam-example-3.json"></a>

```
"AccessKeyformyaccesskey" : {
   "Value" : { "Ref" : "myaccesskey" }
},
"SecretKeyformyaccesskey" : {
   "Value" : {
      "Fn::GetAtt" : [ "myaccesskey", "SecretAccessKey" ]
   }
}
```

#### YAML
<a name="quickref-iam-example-3.yaml"></a>

```
AccessKeyformyaccesskey:
  Value:
    !Ref myaccesskey
SecretKeyformyaccesskey:
  Value: !GetAtt myaccesskey.SecretAccessKey
```

### 
<a name="quickref-iam-access-key-3"></a>

您还可以将 Amazon 访问密钥和私有密钥传输给在模板中定义的 Amazon EC2 实例或自动扩缩组。以下 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-instance.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-instance.html) 声明使用 `UserData` 属性传递 `myaccesskey` 资源的访问密钥和私有密钥。

#### JSON
<a name="quickref-iam-example-4.json"></a>

```
"myinstance" : {
   "Type" : "AWS::EC2::Instance",
   "Properties" : {
      "AvailabilityZone" : "cn-north-1a",
      "ImageId" : "ami-0ff8a91507f77f867",
      "UserData" : {
         "Fn::Base64" : {
            "Fn::Join" : [
               "", [
                  "ACCESS_KEY=", {
                     "Ref" : "myaccesskey"
                  },
                  "&",
                  "SECRET_KEY=",
                  {
                     "Fn::GetAtt" : [
                        "myaccesskey",
                        "SecretAccessKey"
                     ]
                  }
               ]
            ]
         }
      }
   }
}
```

#### YAML
<a name="quickref-iam-example-4.yaml"></a>

```
myinstance:
  Type: AWS::EC2::Instance
  Properties:
    AvailabilityZone: "cn-north-1a"
    ImageId: ami-0ff8a91507f77f867
    UserData:
      Fn::Base64: !Sub "ACCESS_KEY=${myaccesskey}&SECRET_KEY=${myaccesskey.SecretAccessKey}"
```

## 声明 IAM 组资源
<a name="scenario-iam-group"></a>

此代码段显示的是 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-group.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-group.html) 资源。该组有一个路径 (`"/myapplication/"`)。可以在组中添加名为 `myapppolicy` 的策略文档，以允许组的用户对 Amazon SQS 队列资源 myqueue 执行所有 Amazon SQS 操作，并拒绝对 `myqueue` 以外的所有其他 Amazon SQS 资源进行访问。

要分配一个策略给资源，IAM 需要该资源的 Amazon 资源名称（ARN）。在此代码段中，`Fn::GetAtt` 函数将获取 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sqs-queue.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sqs-queue.html) 资源队列的 ARN。

### JSON
<a name="quickref-iam-example-5.json"></a>

```
"mygroup" : {
   "Type" : "AWS::IAM::Group",
   "Properties" : {
      "Path" : "/myapplication/",
      "Policies" : [ {
         "PolicyName" : "myapppolicy",
         "PolicyDocument" : {
            "Version": "2012-10-17",		 	 	 
            "Statement" : [ {
               "Effect" : "Allow",
               "Action" : [ "sqs:*" ],
               "Resource" : [ {
                  "Fn::GetAtt" : [ "myqueue", "Arn" ]
               } ]
            },
            {
               "Effect" : "Deny",
               "Action" : [ "sqs:*" ],
               "NotResource" : [ { "Fn::GetAtt" : [ "myqueue", "Arn" ] } ]
            }
         ] }
      } ]
   }
}
```

### YAML
<a name="quickref-iam-example-5.yaml"></a>

```
mygroup:
  Type: AWS::IAM::Group
  Properties:
    Path: "/myapplication/"
    Policies:
    - PolicyName: myapppolicy
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Action:
          - sqs:*
          Resource: !GetAtt myqueue.Arn
        - Effect: Deny
          Action:
          - sqs:*
          NotResource: !GetAtt myqueue.Arn
```

## 将用户添加到组中
<a name="scenario-iam-addusertogroup"></a>

[https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-usertogroupaddition.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-usertogroupaddition.html) 资源会将用户添加到组。在以下代码段中，`addUserToGroup` 资源将以下用户添加到名为 `myexistinggroup2` 的现有组中：现有用户 `existinguser1` 和在模板中声明为 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-user.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-user.html) 资源的用户 `myuser`。

### JSON
<a name="quickref-iam-example-6.json"></a>

```
"addUserToGroup" : {
   "Type" : "AWS::IAM::UserToGroupAddition",
   "Properties" : {
      "GroupName" : "myexistinggroup2",
      "Users" : [ "existinguser1", { "Ref" : "myuser" } ]
   }
}
```

### YAML
<a name="quickref-iam-example-6.yaml"></a>

```
addUserToGroup:
  Type: AWS::IAM::UserToGroupAddition
  Properties:
    GroupName: myexistinggroup2
    Users:
    - existinguser1
    - !Ref myuser
```

## 声明 IAM policy
<a name="scenario-iam-policy"></a>

此代码段显示如何创建策略并使用名为 `mypolicy` 的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-policy.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-policy.html) 资源将该策略应用于多个组。`mypolicy` 资源包含一个 `PolicyDocument` 属性，该属性允许对 S3 存储桶 (由 ARN `GetObject` 表示) 中的对象执行 `PutObject`、`PutObjectAcl` 和 `arn:aws:s3:::myAWSBucket` 操作。`mypolicy` 资源将策略应用于名为 `myexistinggroup1` 的现有组以及在模板中声明为 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-group.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-group.html) 资源的组 `mygroup`。此示例显示如何使用 `Groups` 属性将策略应用于组；但您也可以使用 `Users` 属性将策略文档添加到用户列表。

### JSON
<a name="quickref-iam-example-7.json"></a>

```
"mypolicy" : {
   "Type" : "AWS::IAM::Policy",
   "Properties" : {
      "PolicyName" : "mygrouppolicy",
      "PolicyDocument" : {
         "Version": "2012-10-17",		 	 	 
         "Statement" : [ {
            "Effect" : "Allow",
            "Action" : [
               "s3:GetObject" , "s3:PutObject" , "s3:PutObjectAcl" ],
            "Resource" : "arn:aws:s3:::myAWSBucket/*"
         } ]
      },
      "Groups" : [ "myexistinggroup1", { "Ref" : "mygroup" } ]
   }
}
```

### YAML
<a name="quickref-iam-example-7.yaml"></a>

```
mypolicy:
  Type: AWS::IAM::Policy
  Properties:
    PolicyName: mygrouppolicy
    PolicyDocument:
      Version: '2012-10-17'
      Statement:
      - Effect: Allow
        Action:
        - s3:GetObject
        - s3:PutObject
        - s3:PutObjectAcl
        Resource: arn:aws:s3:::myAWSBucket/*
    Groups:
    - myexistinggroup1
    - !Ref mygroup
```

## 声明 Amazon S3 存储桶策略
<a name="scenario-bucket-policy"></a>

此代码段说明如何创建策略并将其应用于使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-s3-bucket.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-s3-bucket.html) 资源的 Amazon S3 存储桶。`mybucketpolicy` 资源声明一个策略文档，以允许 `user1` IAM 用户对应用了该策略的 S3 存储桶中的所有对象执行 `GetObject` 操作。在此代码段中，`Fn::GetAtt` 函数将获取 `user1` 资源的 ARN。`mybucketpolicy` 资源将此策略应用于 `AWS::S3::BucketPolicy` 资源 mybucket。`Ref``mybucket` function 获取 资源的存储桶名称。

### JSON
<a name="quickref-iam-example-8.json"></a>

```
"mybucketpolicy" : {
   "Type" : "AWS::S3::BucketPolicy",
   "Properties" : {
      "PolicyDocument" : {
         "Id" : "MyPolicy",
         "Version": "2012-10-17",		 	 	 
         "Statement" : [ {
            "Sid" : "ReadAccess",
            "Action" : [ "s3:GetObject" ],
            "Effect" : "Allow",
            "Resource" : { "Fn::Join" : [
                  "", [ "arn:aws:s3:::", { "Ref" : "mybucket" } , "/*" ]
               ] },
            "Principal" : {
               "AWS" : { "Fn::GetAtt" : [ "user1", "Arn" ] }
            }
         } ]
      },
      "Bucket" : { "Ref" : "mybucket" }
   }
}
```

### YAML
<a name="quickref-iam-example-8.yaml"></a>

```
mybucketpolicy:
  Type: AWS::S3::BucketPolicy
  Properties:
    PolicyDocument:
      Id: MyPolicy
      Version: '2012-10-17'
      Statement:
      - Sid: ReadAccess
        Action:
        - s3:GetObject
        Effect: Allow
        Resource: !Sub "arn:aws:s3:::${mybucket}/*"
        Principal:
          AWS: !GetAtt user1.Arn
    Bucket: !Ref mybucket
```

## 声明 Amazon SNS 主题策略
<a name="scenario-sns-policy"></a>

此代码段说明如何创建策略并将其应用于使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sns-topicpolicy.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sns-topicpolicy.html) 资源的 Amazon SNS 主题。`mysnspolicy` 资源包含一个 `PolicyDocument` 属性，该属性允许 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-user.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-user.html) 资源 `myuser` 对 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sns-topic.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sns-topic.html) 资源 `mytopic` 执行 `Publish` 操作。在此代码段中，`Fn::GetAtt` 函数将获取 `myuser` 资源的 ARN，而 `Ref` 函数将获取 `mytopic` 资源的 ARN。

### JSON
<a name="quickref-iam-example-9.json"></a>

```
"mysnspolicy" : {
   "Type" : "AWS::SNS::TopicPolicy",
   "Properties" : {
      "PolicyDocument" :  {
         "Id" : "MyTopicPolicy",
         "Version": "2012-10-17",		 	 	 
         "Statement" : [ {
            "Sid" : "My-statement-id",
            "Effect" : "Allow",
            "Principal" : {
               "AWS" : { "Fn::GetAtt" : [ "myuser", "Arn" ] }
            },
            "Action" : "sns:Publish",
            "Resource" : "*"
         } ]
      },
      "Topics" : [ { "Ref" : "mytopic" } ]
   }
}
```

### YAML
<a name="quickref-iam-example-9.yaml"></a>

```
mysnspolicy:
  Type: AWS::SNS::TopicPolicy
  Properties:
    PolicyDocument:
      Id: MyTopicPolicy
      Version: '2012-10-17'
      Statement:
      - Sid: My-statement-id
        Effect: Allow
        Principal:
          AWS: !GetAtt myuser.Arn
        Action: sns:Publish
        Resource: "*"
    Topics:
    - !Ref mytopic
```

## 声明 Amazon SQS 策略
<a name="scenario-sqs-policy"></a>

该代码段说明如何使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sqs-queuepolicy.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sqs-queuepolicy.html) 资源创建策略并将其应用于 Amazon SQS 队列。`PolicyDocument` 属性可使现有用户 `myapp`（由其 ARN 指定）对现有队列（按其 URL 指定）和 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sqs-queue.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-sqs-queue.html) 资源 myqueue 执行 `SendMessage` 操作。[Ref](resources-section-structure.md#resource-properties-ref) 函数获取 资源的 URL。`myqueue`

### JSON
<a name="quickref-iam-example-10.json"></a>

```
"mysqspolicy" : {
   "Type" : "AWS::SQS::QueuePolicy",
   "Properties" : {
      "PolicyDocument" : {
         "Id" : "MyQueuePolicy",
         "Version": "2012-10-17",		 	 	 
         "Statement" : [ {
            "Sid" : "Allow-User-SendMessage",
            "Effect" : "Allow",
            "Principal" : {
               "AWS" : "arn:aws:iam::123456789012:user/myapp"
            },
            "Action" : [ "sqs:SendMessage" ],
            "Resource" : "*"
         } ]
      },
      "Queues" : [
         "https://sqs.us-east-2aws-region.amazonaws.com/123456789012/myexistingqueue",
         { "Ref" : "myqueue" }
      ]
   }
}
```

### YAML
<a name="quickref-iam-example-10.yaml"></a>

```
mysqspolicy:
  Type: AWS::SQS::QueuePolicy
  Properties:
    PolicyDocument:
      Id: MyQueuePolicy
      Version: '2012-10-17'
      Statement:
      - Sid: Allow-User-SendMessage
        Effect: Allow
        Principal:
          AWS: arn:aws:iam::123456789012:user/myapp
        Action:
        - sqs:SendMessage
        Resource: "*"
    Queues:
    - https://sqs.aws-region.amazonaws.com/123456789012/myexistingqueue
    - !Ref myqueue
```

## IAM 角色模板示例
<a name="scenarios-iamroles"></a>

本部分提供 EC2 实例 IAM 角色的 CloudFormation 模板示例。

有关更多信息，请参阅《Amazon EC2 用户指南》**中的[适用于 Amazon EC2 的 IAM 角色](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)。

### 带 EC2 的 IAM 角色
<a name="scenario-iamrole-ec2"></a>

在此示例中，实例配置文件由 EC2 实例的 `IamInstanceProfile` 属性引用。实例策略和角色策略都引用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-role.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-role.html)。

#### JSON
<a name="quickref-iam-example-11.json"></a>

```
{
   "AWSTemplateFormatVersion": "2010-09-09",
   "Resources": {
      "myEC2Instance": {
         "Type": "AWS::EC2::Instance",
         "Version": "2009-05-15",
         "Properties": {
            "ImageId": "ami-0ff8a91507f77f867",
            "InstanceType": "m1.small",
            "Monitoring": "true",
            "DisableApiTermination": "false",
            "IamInstanceProfile": {
               "Ref": "RootInstanceProfile"
            }
         }
      },
      "RootRole": {
         "Type": "AWS::IAM::Role",
         "Properties": {
            "AssumeRolePolicyDocument": {
               "Version": "2012-10-17",		 	 	 
               "Statement": [ {
                  "Effect": "Allow",
                  "Principal": {
                     "Service": [ "ec2.amazonaws.com" ]
                  },
                  "Action": [ "sts:AssumeRole" ]
               } ]
            },
            "Path": "/"
         }
      },
      "RolePolicies": {
         "Type": "AWS::IAM::Policy",
         "Properties": {
            "PolicyName": "root",
            "PolicyDocument": {
               "Version": "2012-10-17",		 	 	 
               "Statement": [ {
                  "Effect": "Allow",
                  "Action": "*",
                  "Resource": "*"
               } ]
            },
            "Roles": [ { "Ref": "RootRole" } ]
         }
      },
      "RootInstanceProfile": {
         "Type": "AWS::IAM::InstanceProfile",
         "Properties": {
            "Path": "/",
            "Roles": [ { "Ref": "RootRole" } ]
         }
      }
   }
}
```

#### YAML
<a name="quickref-iam-example-11.yaml"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  myEC2Instance:
    Type: AWS::EC2::Instance
    Version: '2009-05-15'
    Properties:
      ImageId: ami-0ff8a91507f77f867
      InstanceType: m1.small
      Monitoring: 'true'
      DisableApiTermination: 'false'
      IamInstanceProfile:
        !Ref RootInstanceProfile
  RootRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - ec2.amazonaws.com
          Action:
          - sts:AssumeRole
      Path: "/"
  RolePolicies:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: root
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Action: "*"
          Resource: "*"
      Roles:
      - !Ref RootRole
  RootInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: "/"
      Roles:
      - !Ref RootRole
```

### 带自动扩缩组的 IAM 角色
<a name="scenario-iamrole-asg"></a>

在此示例中，实例配置文件由 Amazon EC2 Auto Scaling 启动配置的 `IamInstanceProfile` 属性引用。

#### JSON
<a name="quickref-iam-example-12.json"></a>

```
{
   "AWSTemplateFormatVersion": "2010-09-09",
   "Resources": {
      "myLCOne": {
         "Type": "AWS::AutoScaling::LaunchConfiguration",
         "Version": "2009-05-15",
         "Properties": {
            "ImageId": "ami-0ff8a91507f77f867",
            "InstanceType": "m1.small",
            "InstanceMonitoring": "true",
            "IamInstanceProfile": { "Ref": "RootInstanceProfile" }
         }
      },
      "myASGrpOne": {
         "Type": "AWS::AutoScaling::AutoScalingGroup",
         "Version": "2009-05-15",
         "Properties": {
            "AvailabilityZones": [ "cn-north-1a" ],
            "LaunchConfigurationName": { "Ref": "myLCOne" },
            "MinSize": "0",
            "MaxSize": "0",
            "HealthCheckType": "EC2",
            "HealthCheckGracePeriod": "120"
         }
      },
      "RootRole": {
         "Type": "AWS::IAM::Role",
         "Properties": {
            "AssumeRolePolicyDocument": {
               "Version": "2012-10-17",		 	 	 
               "Statement": [ {
                  "Effect": "Allow",
                  "Principal": {
                     "Service": [ "ec2.amazonaws.com" ]
                  },
                  "Action": [ "sts:AssumeRole" ]
               } ]
            },
            "Path": "/"
         }
      },
      "RolePolicies": {
         "Type": "AWS::IAM::Policy",
         "Properties": {
            "PolicyName": "root",
            "PolicyDocument": {
               "Version": "2012-10-17",		 	 	 
               "Statement": [ {
                  "Effect": "Allow",
                  "Action": "*",
                  "Resource": "*"
               } ]
            },
            "Roles": [ { "Ref": "RootRole" } ]
         }
      },
      "RootInstanceProfile": {
         "Type": "AWS::IAM::InstanceProfile",
         "Properties": {
            "Path": "/",
            "Roles": [ { "Ref": "RootRole" } ]
         }
      }
   }
}
```

#### YAML
<a name="quickref-iam-example-12.yaml"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  myLCOne:
    Type: AWS::AutoScaling::LaunchConfiguration
    Version: '2009-05-15'
    Properties:
      ImageId: ami-0ff8a91507f77f867
      InstanceType: m1.small
      InstanceMonitoring: 'true'
      IamInstanceProfile:
        !Ref RootInstanceProfile
  myASGrpOne:
    Type: AWS::AutoScaling::AutoScalingGroup
    Version: '2009-05-15'
    Properties:
      AvailabilityZones:
      - "cn-north-1a"
      LaunchConfigurationName:
        !Ref myLCOne
      MinSize: '0'
      MaxSize: '0'
      HealthCheckType: EC2
      HealthCheckGracePeriod: '120'
  RootRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - ec2.amazonaws.com
          Action:
          - sts:AssumeRole
      Path: "/"
  RolePolicies:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: root
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Action: "*"
          Resource: "*"
      Roles:
      - !Ref RootRole
  RootInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: "/"
      Roles:
      - !Ref RootRole
```

# Amazon Lambda 模板
<a name="quickref-lambda"></a>

以下模板使用 Amazon Lambda（Lambda）函数和自定义资源向现有安全组列表附加新的安全组。当您需要动态构建安全组列表以使列表同时包含新安全组及现有安全组时，此函数非常有用。例如，您可以将现有安全组列表作为参数值传递，向此列表追加一个新值，然后将您所有的值关联到一个 EC2 实例。有关 Lambda 函数资源类型的更多信息，请参阅 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html)。

在此示例中，当 CloudFormation 创建 `AllSecurityGroups` 自定义资源时，CloudFormation 会调用 `AppendItemToListFunction` Lambda 函数。CloudFormation 将现有的安全组列表以及一个新的安全组（`NewSecurityGroup`）传递给该函数，而该函数会将新的安全组附加到列表中，然后返回修改后的列表。CloudFormation 使用修改后的列表将所有安全组与 `MyEC2Instance` 资源关联起来。

## JSON
<a name="quickref-lambda-example-1.json"></a>

```
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Parameters": {
        "ExistingSecurityGroups": {
            "Type": "List<AWS::EC2::SecurityGroup::Id>"
        },
        "ExistingVPC": {
            "Type": "AWS::EC2::VPC::Id",
            "Description": "The VPC ID that includes the security groups in the ExistingSecurityGroups parameter."
        },
        "InstanceType": {
            "Type": "String",
            "Default": "t2.micro",
            "AllowedValues": [
                "t2.micro",
                "t3.micro"
            ]
        }
    },

    "Resources": {
        "SecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": "Allow HTTP traffic to the host",
                "VpcId": {
                    "Ref": "ExistingVPC"
                },
                "SecurityGroupIngress": [
                    {
                        "IpProtocol": "tcp",
                        "FromPort": 80,
                        "ToPort": 80,
                        "CidrIp": "0.0.0.0/0"
                    }
                ],
                "SecurityGroupEgress": [
                    {
                        "IpProtocol": "tcp",
                        "FromPort": 80,
                        "ToPort": 80,
                        "CidrIp": "0.0.0.0/0"
                    }
                ]
            }
        },
        "AllSecurityGroups": {
            "Type": "Custom::Split",
            "Properties": {
                "ServiceToken": {
                    "Fn::GetAtt": [
                        "AppendItemToListFunction",
                        "Arn"
                    ]
                },
                "List": {
                    "Ref": "ExistingSecurityGroups"
                },
                "AppendedItem": {
                    "Ref": "SecurityGroup"
                }
            }
        },
        "AppendItemToListFunction": {
            "Type": "AWS::Lambda::Function",
            "Properties": {
                "Handler": "index.handler",
                "Role": {
                    "Fn::GetAtt": [
                        "LambdaExecutionRole",
                        "Arn"
                    ]
                },
                "Code": {
                    "ZipFile": {
                        "Fn::Join": [
                            "",
                            [
                                "var response = require('cfn-response');",
                                "exports.handler = function(event, context) {",
                                "   var responseData = {Value: event.ResourceProperties.List};",
                                "   responseData.Value.push(event.ResourceProperties.AppendedItem);",
                                "   response.send(event, context, response.SUCCESS, responseData);",
                                "};"
                            ]
                        ]
                    }
                },
                "Runtime": "nodejs20.x"
            }
        },
        "MyEC2Instance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}",
                "SecurityGroupIds": {
                    "Fn::GetAtt": [
                        "AllSecurityGroups",
                        "Value"
                    ]
                },
                "InstanceType": {
                    "Ref": "InstanceType"
                }
            }
        },
        "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:*"
                                    ],
                                    "Resource": "arn:aws:logs:*:*:*"
                                }
                            ]
                        }
                    }
                ]
            }
        }
    },
    "Outputs": {
        "AllSecurityGroups": {
            "Description": "Security Groups that are associated with the EC2 instance",
            "Value": {
                "Fn::Join": [
                    ", ",
                    {
                        "Fn::GetAtt": [
                            "AllSecurityGroups",
                            "Value"
                        ]
                    }
                ]
            }
        }
    }
}
```

## YAML
<a name="quickref-lambda-example-1.yaml"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  ExistingSecurityGroups:
    Type: List<AWS::EC2::SecurityGroup::Id>
  ExistingVPC:
    Type: AWS::EC2::VPC::Id
    Description: The VPC ID that includes the security groups in the ExistingSecurityGroups parameter.
  InstanceType:
    Type: String
    Default: t2.micro
    AllowedValues:
      - t2.micro
      - t3.micro
Resources:
  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow HTTP traffic to the host
      VpcId: !Ref ExistingVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
  AllSecurityGroups:
    Type: Custom::Split
    Properties:
      ServiceToken: !GetAtt AppendItemToListFunction.Arn
      List: !Ref ExistingSecurityGroups
      AppendedItem: !Ref SecurityGroup
  AppendItemToListFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: !Join
          - ''
          - - var response = require('cfn-response');
            - exports.handler = function(event, context) {
            - '   var responseData = {Value: event.ResourceProperties.List};'
            - '   responseData.Value.push(event.ResourceProperties.AppendedItem);'
            - '   response.send(event, context, response.SUCCESS, responseData);'
            - '};'
      Runtime: nodejs20.x
  MyEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}'
      SecurityGroupIds: !GetAtt AllSecurityGroups.Value
      InstanceType: !Ref InstanceType
  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:*
                Resource: arn:aws:logs:*:*:*
Outputs:
  AllSecurityGroups:
    Description: Security Groups that are associated with the EC2 instance
    Value: !Join
      - ', '
      - !GetAtt AllSecurityGroups.Value
```

# Amazon Redshift 模板代码段
<a name="quickref-redshift"></a>

Amazon Redshift 是云中一种完全托管的 PB 级数据仓库服务。您可以使用 Amazon CloudFormation 预置和管理 Amazon Redshift 集群。

## Amazon Redshift 集群
<a name="quickref-redshift-samplecluster"></a>

下述示例模板根据在创建堆栈时指定的参数值创建 Amazon Redshift 集群。与 Amazon Redshift 集群关联的集群参数组可实现用户活动日志记录。该模板还在模板中定义的 Amazon VPC 中启动 Amazon Redshift 集群。VPC 包含一个 Internet 网关，以便您从 Internet 访问 Amazon Redshift 集群。然而，还必须启用集群与 Internet 网关之间的通信，这是通过路由表条目实现的。

**注意**  
该模板包含 `IsMultiNodeCluster` 条件，以便仅当 `NumberOfNodes` 参数值设置为 `ClusterType` 时才声明 `multi-node` 参数。

该示例定义了 `MysqlRootPassword` 参数，并将其 `NoEcho` 属性设置为 `true`。如果您将 `NoEcho` 属性设置为 `true`，则对于描述堆栈或堆栈事件的任何调用，CloudFormation 返回使用星号 (\$1\$1\$1\$1\$1) 遮蔽的参数值，但存储在下面指定位置的信息除外。

**重要**  
使用 `NoEcho` 属性不会遮蔽在以下各区段中存储的任何信息：  
`Metadata` 模板区段。CloudFormation 不会转换、修改或编辑您在 `Metadata` 部分中包含的任何信息。有关更多信息，请参阅 [Metadata](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html)。
`Outputs` 模板区段。有关更多信息，请参阅 [Outputs](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html)。
资源定义的 `Metadata` 属性。有关更多信息，请参阅 [`Metadata` 属性](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-attribute-metadata.html)。
强烈建议您不要使用这些机制来包含敏感信息，例如密码。

**重要**  
我们建议不要将敏感信息直接嵌入 CloudFormation 模板中，而应使用堆栈模板中的动态参数来引用在 CloudFormation 外部存储和管理的敏感信息，例如 Amazon Systems Manager Parameter Store 或 Amazon Secrets Manager 中的敏感信息。  
有关更多信息，请参阅[请勿将凭证嵌入您的模板](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/security-best-practices.html#creds)最佳实践。

### JSON
<a name="quickref-redshift-example-1.json"></a>

```
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Parameters" : {
    "DatabaseName" : {
      "Description" : "The name of the first database to be created when the cluster is created",
      "Type" : "String",
      "Default" : "dev",
      "AllowedPattern" : "([a-z]|[0-9])+"
    },
    "ClusterType" : {
      "Description" : "The type of cluster",
      "Type" : "String",
      "Default" : "single-node",
      "AllowedValues" : [ "single-node", "multi-node" ]
    },
    "NumberOfNodes" : {
      "Description" : "The number of compute nodes in the cluster. For multi-node clusters, the NumberOfNodes parameter must be greater than 1",
      "Type" : "Number",
      "Default" : "1"
    },
    "NodeType" : {
      "Description" : "The type of node to be provisioned",
      "Type" : "String",
      "Default" : "ds2.xlarge",
      "AllowedValues" : [ "ds2.xlarge", "ds2.8xlarge", "dc1.large", "dc1.8xlarge" ]
    }, 
    "MasterUsername" : {
      "Description" : "The user name that is associated with the master user account for the cluster that is being created",
      "Type" : "String",
      "Default" : "defaultuser",
      "AllowedPattern" : "([a-z])([a-z]|[0-9])*"
    },
    "MasterUserPassword" :  {
      "Description" : "The password that is associated with the master user account for the cluster that is being created.",
      "Type" : "String",
      "NoEcho" : "true"
    },
    "InboundTraffic" : {
      "Description" : "Allow inbound traffic to the cluster from this CIDR range.",
      "Type" : "String",
      "MinLength": "9",
      "MaxLength": "18",
      "Default" : "0.0.0.0/0",
      "AllowedPattern" : "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
      "ConstraintDescription" : "must be a valid CIDR range of the form x.x.x.x/x."
    },
    "PortNumber" : {
      "Description" : "The port number on which the cluster accepts incoming connections.",
      "Type" : "Number",
      "Default" : "5439"
    }
  },
  "Conditions" : {
    "IsMultiNodeCluster" : {
      "Fn::Equals" : [{ "Ref" : "ClusterType" }, "multi-node" ]        
    }
  },
  "Resources" : {
    "RedshiftCluster" : {
      "Type" : "AWS::Redshift::Cluster",
      "DependsOn" : "AttachGateway",
      "Properties" : {
        "ClusterType" : { "Ref" : "ClusterType" },
        "NumberOfNodes" : { "Fn::If" : [ "IsMultiNodeCluster",  { "Ref" : "NumberOfNodes" }, { "Ref" : "AWS::NoValue" }]},
        "NodeType" : { "Ref" : "NodeType" },
        "DBName" : { "Ref" : "DatabaseName" },
        "MasterUsername" : { "Ref" : "MasterUsername" },
        "MasterUserPassword" : { "Ref" : "MasterUserPassword" },               
        "ClusterParameterGroupName" : { "Ref" : "RedshiftClusterParameterGroup" },
        "VpcSecurityGroupIds" : [ { "Ref" : "SecurityGroup" } ],
        "ClusterSubnetGroupName" : { "Ref" : "RedshiftClusterSubnetGroup" },
        "PubliclyAccessible" : "true",
        "Port" : { "Ref" : "PortNumber" }
      }
    },
    "RedshiftClusterParameterGroup" : {
      "Type" : "AWS::Redshift::ClusterParameterGroup",
      "Properties" : {
        "Description" : "Cluster parameter group",
        "ParameterGroupFamily" : "redshift-1.0",
        "Parameters" : [{
          "ParameterName" : "enable_user_activity_logging",
          "ParameterValue" : "true"
        }]
      }
    },
    "RedshiftClusterSubnetGroup" : {
      "Type" : "AWS::Redshift::ClusterSubnetGroup",
      "Properties" : {
        "Description" : "Cluster subnet group",
        "SubnetIds" : [ { "Ref" : "PublicSubnet" } ]
      }
    },
    "VPC" : {
      "Type" : "AWS::EC2::VPC",
      "Properties" : {
        "CidrBlock" : "10.0.0.0/16"
      }
    },
    "PublicSubnet" : {
      "Type" : "AWS::EC2::Subnet",
      "Properties" : {
        "CidrBlock" : "10.0.0.0/24",
        "VpcId" : { "Ref" : "VPC" }
      }
    },
    "SecurityGroup" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription" : "Security group",
        "SecurityGroupIngress" : [ {
          "CidrIp" : { "Ref": "InboundTraffic" },
          "FromPort" : { "Ref" : "PortNumber" },
          "ToPort" : { "Ref" : "PortNumber" },
          "IpProtocol" : "tcp"
        } ],
        "VpcId" : { "Ref" : "VPC" }
      }
    },
    "myInternetGateway" : {
      "Type" : "AWS::EC2::InternetGateway"
    },
    "AttachGateway" : {
      "Type" : "AWS::EC2::VPCGatewayAttachment",
      "Properties" : {
        "VpcId" : { "Ref" : "VPC" },
        "InternetGatewayId" : { "Ref" : "myInternetGateway" }
      }
    },
    "PublicRouteTable" : {
      "Type" : "AWS::EC2::RouteTable",
      "Properties" : {
        "VpcId" : {
          "Ref" : "VPC"
        }
      }
    },
    "PublicRoute" : {
      "Type" : "AWS::EC2::Route",
      "DependsOn" : "AttachGateway",
      "Properties"  : {
        "RouteTableId" : {
          "Ref" : "PublicRouteTable"
        },
        "DestinationCidrBlock" : "0.0.0.0/0",
        "GatewayId" : {
          "Ref" : "myInternetGateway"
        }
      }
    },
    "PublicSubnetRouteTableAssociation" : {
      "Type" : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties" : {
        "SubnetId" : {
          "Ref" : "PublicSubnet"
        },
        "RouteTableId" : {
          "Ref" : "PublicRouteTable"
        }
      }
    }
  },
  "Outputs" : {
    "ClusterEndpoint" : {
      "Description" : "Cluster endpoint",
      "Value" : { "Fn::Join" : [ ":", [ { "Fn::GetAtt" : [ "RedshiftCluster", "Endpoint.Address" ] }, { "Fn::GetAtt" : [ "RedshiftCluster", "Endpoint.Port" ] } ] ] }
    },
    "ClusterName" : {
      "Description" : "Name of cluster",
      "Value" : { "Ref" : "RedshiftCluster" }
    },
    "ParameterGroupName" : {
      "Description" : "Name of parameter group",
      "Value" : { "Ref" : "RedshiftClusterParameterGroup" }
    },
    "RedshiftClusterSubnetGroupName" : {
      "Description" : "Name of cluster subnet group",
      "Value" : { "Ref" : "RedshiftClusterSubnetGroup" }
    },
    "RedshiftClusterSecurityGroupName" : {
      "Description" : "Name of cluster security group",
      "Value" : { "Ref" : "SecurityGroup" }
    }
  }
}
```

### YAML
<a name="quickref-redshift-example-1.yaml"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  DatabaseName:
    Description: The name of the first database to be created when the cluster is
      created
    Type: String
    Default: dev
    AllowedPattern: "([a-z]|[0-9])+"
  ClusterType:
    Description: The type of cluster
    Type: String
    Default: single-node
    AllowedValues:
    - single-node
    - multi-node
  NumberOfNodes:
    Description: The number of compute nodes in the cluster. For multi-node clusters,
      the NumberOfNodes parameter must be greater than 1
    Type: Number
    Default: '1'
  NodeType:
    Description: The type of node to be provisioned
    Type: String
    Default: ds2.xlarge
    AllowedValues:
    - ds2.xlarge
    - ds2.8xlarge
    - dc1.large
    - dc1.8xlarge
  MasterUsername:
    Description: The user name that is associated with the master user account for
      the cluster that is being created
    Type: String
    Default: defaultuser
    AllowedPattern: "([a-z])([a-z]|[0-9])*"
  MasterUserPassword:
    Description: The password that is associated with the master user account for
      the cluster that is being created.
    Type: String
    NoEcho: 'true'
  InboundTraffic:
    Description: Allow inbound traffic to the cluster from this CIDR range.
    Type: String
    MinLength: '9'
    MaxLength: '18'
    Default: 0.0.0.0/0
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    ConstraintDescription: must be a valid CIDR range of the form x.x.x.x/x.
  PortNumber:
    Description: The port number on which the cluster accepts incoming connections.
    Type: Number
    Default: '5439'
Conditions:
  IsMultiNodeCluster:
    Fn::Equals:
    - Ref: ClusterType
    - multi-node
Resources:
  RedshiftCluster:
    Type: AWS::Redshift::Cluster
    DependsOn: AttachGateway
    Properties:
      ClusterType:
        Ref: ClusterType
      NumberOfNodes:
        Fn::If:
        - IsMultiNodeCluster
        - Ref: NumberOfNodes
        - Ref: AWS::NoValue
      NodeType:
        Ref: NodeType
      DBName:
        Ref: DatabaseName
      MasterUsername:
        Ref: MasterUsername
      MasterUserPassword:
        Ref: MasterUserPassword
      ClusterParameterGroupName:
        Ref: RedshiftClusterParameterGroup
      VpcSecurityGroupIds:
      - Ref: SecurityGroup
      ClusterSubnetGroupName:
        Ref: RedshiftClusterSubnetGroup
      PubliclyAccessible: 'true'
      Port:
        Ref: PortNumber
  RedshiftClusterParameterGroup:
    Type: AWS::Redshift::ClusterParameterGroup
    Properties:
      Description: Cluster parameter group
      ParameterGroupFamily: redshift-1.0
      Parameters:
      - ParameterName: enable_user_activity_logging
        ParameterValue: 'true'
  RedshiftClusterSubnetGroup:
    Type: AWS::Redshift::ClusterSubnetGroup
    Properties:
      Description: Cluster subnet group
      SubnetIds:
      - Ref: PublicSubnet
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.0.0/24
      VpcId:
        Ref: VPC
  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group
      SecurityGroupIngress:
      - CidrIp:
          Ref: InboundTraffic
        FromPort:
          Ref: PortNumber
        ToPort:
          Ref: PortNumber
        IpProtocol: tcp
      VpcId:
        Ref: VPC
  myInternetGateway:
    Type: AWS::EC2::InternetGateway
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId:
        Ref: VPC
      InternetGatewayId:
        Ref: myInternetGateway
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: VPC
  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId:
        Ref: PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId:
        Ref: myInternetGateway
  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId:
        Ref: PublicSubnet
      RouteTableId:
        Ref: PublicRouteTable
Outputs:
  ClusterEndpoint:
    Description: Cluster endpoint
    Value: !Sub "${RedshiftCluster.Endpoint.Address}:${RedshiftCluster.Endpoint.Port}"
  ClusterName:
    Description: Name of cluster
    Value:
      Ref: RedshiftCluster
  ParameterGroupName:
    Description: Name of parameter group
    Value:
      Ref: RedshiftClusterParameterGroup
  RedshiftClusterSubnetGroupName:
    Description: Name of cluster subnet group
    Value:
      Ref: RedshiftClusterSubnetGroup
  RedshiftClusterSecurityGroupName:
    Description: Name of cluster security group
    Value:
      Ref: SecurityGroup
```

## 另请参阅
<a name="w2aac11c41c72b7"></a>

[AWS::Redshift::Cluster](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-redshift-cluster.html)

# Amazon RDS 模板代码段
<a name="quickref-rds"></a>

**Topics**
+ [

## Amazon RDS 数据库实例资源
](#scenario-rds-instance)
+ [

## Amazon RDS Oracle Database 数据库实例资源
](#scenario-rds-oracleinstance)
+ [

## 适用于 CIDR 范围的 Amazon RDS DBSecurityGroup 资源
](#scenario-rds-security-group-cidr)
+ [

## 带 Amazon EC2 安全组的 Amazon RDS DBSecurityGroup
](#scenario-rds-security-group-ec2)
+ [

## 多 VPC 安全组
](#scenario-multiple-vpc-security-groups)
+ [

## VPC 安全组中的 Amazon RDS 数据库实例
](#w2aac11c41c76c15)

## Amazon RDS 数据库实例资源
<a name="scenario-rds-instance"></a>

此示例显示了使用托管主用户密码的 Amazon RDS 数据库实例资源。有关更多信息，请参阅《Amazon RDS 用户指南》**中的[使用 Amazon Secrets Manager 管理密码](https://docs.amazonaws.cn/AmazonRDS/latest/UserGuide/rds-secrets-manager.html)和《Aurora 用户指南》**中的[使用 Amazon Secrets Manager 管理密码](https://docs.amazonaws.cn/AmazonRDS/latest/AuroraUserGuide/rds-secrets-manager.html)。由于没有指定可选的 `EngineVersion` 属性，因此会将默认引擎版本用于此数据库实例。有关默认引擎版本和其他默认设置的详细信息，请参阅 [CreateDBInstance](https://docs.amazonaws.cn/AmazonRDS/latest/APIReference/API_CreateDBInstance.html)。`DBSecurityGroups` 属性向名为 `MyDbSecurityByEC2SecurityGroup` 和 MyDbSecurityByCIDRIPGroup 的 `AWS::RDS::DBSecurityGroup` 资源授予网络入口权限。有关更多信息，请参阅 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbinstance.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbinstance.html)。数据库实例资源还有一个设置为 `Snapshot` 的 `DeletionPolicy` 属性。如果设置了 `Snapshot` `DeletionPolicy`，则在堆栈删除期间，Amazon CloudFormation 会首先拍摄该数据库实例的快照，然后再将其删除。

### JSON
<a name="quickref-rds-example-1.json"></a>

```
 1. "MyDB" : {
 2.  "Type" : "AWS::RDS::DBInstance",
 3.  "Properties" : {
 4.      "DBSecurityGroups" : [
 5.         {"Ref" : "MyDbSecurityByEC2SecurityGroup"}, {"Ref" : "MyDbSecurityByCIDRIPGroup"} ],
 6.      "AllocatedStorage" : "5",
 7.      "DBInstanceClass" : "db.t2.small",
 8.      "Engine" : "MySQL",
 9.      "MasterUsername" : "MyName",
10.      "ManageMasterUserPassword" : true,
11.      "MasterUserSecret" : {
12.         "KmsKeyId" : {"Ref" : "KMSKey"}
13.      }
14.  },
15.  "DeletionPolicy" : "Snapshot"
16. }
```

### YAML
<a name="quickref-rds-example-1.yaml"></a>

```
 1. MyDB:
 2.   Type: AWS::RDS::DBInstance
 3.   Properties:
 4.     DBSecurityGroups:
 5.     - Ref: MyDbSecurityByEC2SecurityGroup
 6.     - Ref: MyDbSecurityByCIDRIPGroup
 7.     AllocatedStorage: '5'
 8.     DBInstanceClass: db.t2.small
 9.     Engine: MySQL
10.     MasterUsername: MyName
11.     ManageMasterUserPassword: true
12.     MasterUserSecret:
13.       KmsKeyId: !Ref KMSKey
14.   DeletionPolicy: Snapshot
```

## Amazon RDS Oracle Database 数据库实例资源
<a name="scenario-rds-oracleinstance"></a>

此示例创建了使用托管主用户密码的 Oracle Database 数据库实例资源。有关更多信息，请参阅《Amazon RDS 用户指南》**中的[使用 Amazon Secrets Manager 管理密码](https://docs.amazonaws.cn/AmazonRDS/latest/UserGuide/rds-secrets-manager.html)。此示例将 `Engine` 指定为 `oracle-ee` 并使用“自带许可”许可模式。有关 Oracle Database 数据库实例设置的详细信息，请参阅 [CreateDBInstance](https://docs.amazonaws.cn/AmazonRDS/latest/APIReference/API_CreateDBInstance.html)。DBSecurityGroups 属性授权对名为 MyDbSecurityByEC2SecurityGroup 和 MyDbSecurityByCIDRIPGroup 的 `AWS::RDS::DBSecurityGroup` 资源的网络访问。有关更多信息，请参阅 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbinstance.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbinstance.html)。数据库实例资源还有一个设置为 `Snapshot` 的 `DeletionPolicy` 属性。如果设置了 `Snapshot` `DeletionPolicy`，则在堆栈删除期间，Amazon CloudFormation 会首先拍摄该数据库实例的快照，然后再将其删除。

### JSON
<a name="quickref-rds-example-2.json"></a>

```
 1. "MyDB" : {
 2.  "Type" : "AWS::RDS::DBInstance",
 3.  "Properties" : {
 4.      "DBSecurityGroups" : [
 5.         {"Ref" : "MyDbSecurityByEC2SecurityGroup"}, {"Ref" : "MyDbSecurityByCIDRIPGroup"} ],
 6.      "AllocatedStorage" : "5",
 7.      "DBInstanceClass" : "db.t2.small",
 8.      "Engine" : "oracle-ee",
 9.      "LicenseModel" : "bring-your-own-license",
10.      "MasterUsername" : "master",
11.      "ManageMasterUserPassword" : true,
12.      "MasterUserSecret" : {
13.         "KmsKeyId" : {"Ref" : "KMSKey"}
14.      }
15.  },
16.  "DeletionPolicy" : "Snapshot"
17. }
```

### YAML
<a name="quickref-rds-example-2.yaml"></a>

```
 1. MyDB:
 2.   Type: AWS::RDS::DBInstance
 3.   Properties:
 4.     DBSecurityGroups:
 5.     - Ref: MyDbSecurityByEC2SecurityGroup
 6.     - Ref: MyDbSecurityByCIDRIPGroup
 7.     AllocatedStorage: '5'
 8.     DBInstanceClass: db.t2.small
 9.     Engine: oracle-ee
10.     LicenseModel: bring-your-own-license
11.     MasterUsername: master
12.     ManageMasterUserPassword: true
13.     MasterUserSecret:
14.       KmsKeyId: !Ref KMSKey
15.   DeletionPolicy: Snapshot
```

## 适用于 CIDR 范围的 Amazon RDS DBSecurityGroup 资源
<a name="scenario-rds-security-group-cidr"></a>

此示例说明一个 Amazon RDS `DBSecurityGroup` 资源，该资源具有以 `ddd.ddd.ddd.ddd/dd` 格式指定的 CIDR 范围的入口授权。有关详细信息，请参阅 [AWS::RDS::DBSecurityGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbsecuritygroup.html) 和 [Ingress](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-rds-dbsecuritygroup-ingress.html)。

### JSON
<a name="quickref-rds-example-3.json"></a>

```
1. "MyDbSecurityByCIDRIPGroup" : {
2.  "Type" : "AWS::RDS::DBSecurityGroup",
3.  "Properties" : {
4.      "GroupDescription" : "Ingress for CIDRIP",
5.      "DBSecurityGroupIngress" : {
6.          "CIDRIP" : "192.168.0.0/32"
7.      }
8.  }
9. }
```

### YAML
<a name="quickref-rds-example-3.yaml"></a>

```
1. MyDbSecurityByCIDRIPGroup:
2.   Type: AWS::RDS::DBSecurityGroup
3.   Properties:
4.     GroupDescription: Ingress for CIDRIP
5.     DBSecurityGroupIngress:
6.       CIDRIP: "192.168.0.0/32"
```

## 带 Amazon EC2 安全组的 Amazon RDS DBSecurityGroup
<a name="scenario-rds-security-group-ec2"></a>

此示例展示的 [AWS::RDS::DBSecurityGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbsecuritygroup.html) 资源具有 `MyEc2SecurityGroup` 所引用 Amazon EC2 安全组中的入口授权。

要执行此操作，您需要定义一个 EC2 安全组，然后在 `DBSecurityGroup` 中使用 `Ref` 内置函数引用该 EC2 安全组。

### JSON
<a name="quickref-rds-example-4.json"></a>

```
"DBInstance" : {
   "Type": "AWS::RDS::DBInstance",
   "Properties": {
      "DBName"            : { "Ref" : "DBName" },
      "Engine"            : "MySQL",
      "MasterUsername"    : { "Ref" : "DBUsername" },
      "DBInstanceClass"   : { "Ref" : "DBClass" },
      "DBSecurityGroups"  : [ { "Ref" : "DBSecurityGroup" } ],
      "AllocatedStorage"  : { "Ref" : "DBAllocatedStorage" },
      "MasterUserPassword": { "Ref" : "DBPassword" }
   }
},

"DBSecurityGroup": {
   "Type": "AWS::RDS::DBSecurityGroup",
   "Properties": {
      "DBSecurityGroupIngress": {
         "EC2SecurityGroupName": {
            "Fn::GetAtt": ["WebServerSecurityGroup", "GroupName"]
         }
      },
      "GroupDescription" : "Frontend Access"
   }
},

"WebServerSecurityGroup" : {
   "Type" : "AWS::EC2::SecurityGroup",
   "Properties" : {
      "GroupDescription" : "Enable HTTP access via port 80 and SSH access",
      "SecurityGroupIngress" : [
         {"IpProtocol" : "tcp", "FromPort" : 80, "ToPort" : 80, "CidrIp" : "0.0.0.0/0"},
         {"IpProtocol" : "tcp", "FromPort" : 22, "ToPort" : 22, "CidrIp" : "0.0.0.0/0"}
      ]
   }
}
```

### YAML
<a name="quickref-rds-example-4.yaml"></a>

该示例提取自下面的完整示例：[Drupal\$1Single\$1Instance\$1With\$1RDS.template](https://s3.amazonaws.com/cloudformation-templates-us-east-1/Drupal_Single_Instance_With_RDS.template)

```
DBInstance:
  Type: AWS::RDS::DBInstance
  Properties:
    DBName:
      Ref: DBName
    Engine: MySQL
    MasterUsername:
      Ref: DBUsername
    DBInstanceClass:
      Ref: DBClass
    DBSecurityGroups:
    - Ref: DBSecurityGroup
    AllocatedStorage:
      Ref: DBAllocatedStorage
    MasterUserPassword:
      Ref: DBPassword
DBSecurityGroup:
  Type: AWS::RDS::DBSecurityGroup
  Properties:
    DBSecurityGroupIngress:
      EC2SecurityGroupName:
        Ref: WebServerSecurityGroup
    GroupDescription: Frontend Access
WebServerSecurityGroup:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupDescription: Enable HTTP access via port 80 and SSH access
    SecurityGroupIngress:
    - IpProtocol: tcp
      FromPort: 80
      ToPort: 80
      CidrIp: 0.0.0.0/0
    - IpProtocol: tcp
      FromPort: 22
      ToPort: 22
      CidrIp: 0.0.0.0/0
```

## 多 VPC 安全组
<a name="scenario-multiple-vpc-security-groups"></a>

此示例显示的是具有 [AWS::RDS::DBSecurityGroupIngress](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbsecuritygroupingress.html) 中的多个 Amazon EC2 VPC 安全组的入口授权的 [AWS::RDS::DBSecurityGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbsecuritygroup.html) 资源。

### JSON
<a name="quickref-rds-example-5.json"></a>

```
{
   "Resources" : {
      "DBinstance" : {
         "Type" : "AWS::RDS::DBInstance",
         "Properties" : {
            "AllocatedStorage" : "5",
            "DBInstanceClass" : "db.t2.small",
           "DBName" : {"Ref": "MyDBName" },
            "DBSecurityGroups" : [ { "Ref" : "DbSecurityByEC2SecurityGroup" } ],
            "DBSubnetGroupName" : { "Ref" : "MyDBSubnetGroup" },
            "Engine" : "MySQL",
           "MasterUserPassword": { "Ref" : "MyDBPassword" },
           "MasterUsername"    : { "Ref" : "MyDBUsername" }
        },
         "DeletionPolicy" : "Snapshot"
      },
      "DbSecurityByEC2SecurityGroup" : {
         "Type" : "AWS::RDS::DBSecurityGroup",
         "Properties" : {
            "GroupDescription" : "Ingress for Amazon EC2 security group",
           "EC2VpcId" : { "Ref" : "MyVPC" },
            "DBSecurityGroupIngress" : [ {
               "EC2SecurityGroupId" : "sg-b0ff1111",
               "EC2SecurityGroupOwnerId" : "111122223333"
            }, {
               "EC2SecurityGroupId" : "sg-ffd722222",
               "EC2SecurityGroupOwnerId" : "111122223333"
            } ]
         }
      }
   }
}
```

### YAML
<a name="quickref-rds-example-5.yaml"></a>

```
Resources:
  DBinstance:
    Type: AWS::RDS::DBInstance
    Properties:
      AllocatedStorage: '5'
      DBInstanceClass: db.t2.small
      DBName:
        Ref: MyDBName
      DBSecurityGroups:
      - Ref: DbSecurityByEC2SecurityGroup
      DBSubnetGroupName:
        Ref: MyDBSubnetGroup
      Engine: MySQL
      MasterUserPassword:
        Ref: MyDBPassword
      MasterUsername:
        Ref: MyDBUsername
    DeletionPolicy: Snapshot
  DbSecurityByEC2SecurityGroup:
    Type: AWS::RDS::DBSecurityGroup
    Properties:
      GroupDescription: Ingress for Amazon EC2 security group
      EC2VpcId:
        Ref: MyVPC
      DBSecurityGroupIngress:
      - EC2SecurityGroupId: sg-b0ff1111
        EC2SecurityGroupOwnerId: '111122223333'
      - EC2SecurityGroupId: sg-ffd722222
        EC2SecurityGroupOwnerId: '111122223333'
```

## VPC 安全组中的 Amazon RDS 数据库实例
<a name="w2aac11c41c76c15"></a>

该示例显示一个与 Amazon EC2 VPC 安全组关联的 Amazon RDS 数据库实例。

### JSON
<a name="quickref-rds-example-6.json"></a>

```
{
  "DBEC2SecurityGroup": {
    "Type": "AWS::EC2::SecurityGroup",
    "Properties" : {
      "GroupDescription": "Open database for access",
      "SecurityGroupIngress" : [{
        "IpProtocol" : "tcp",
        "FromPort" : 3306,
        "ToPort" : 3306,
        "SourceSecurityGroupName" : { "Ref" : "WebServerSecurityGroup" }
      }]
    }
  },
  "DBInstance" : {
    "Type": "AWS::RDS::DBInstance",
    "Properties": {
      "DBName"            : { "Ref" : "DBName" },
      "Engine"            : "MySQL",
      "MultiAZ"           : { "Ref": "MultiAZDatabase" },
      "MasterUsername"    : { "Ref" : "DBUser" },
      "DBInstanceClass"   : { "Ref" : "DBClass" },
      "AllocatedStorage"  : { "Ref" : "DBAllocatedStorage" },
      "MasterUserPassword": { "Ref" : "DBPassword" },
      "VPCSecurityGroups" : [ { "Fn::GetAtt": [ "DBEC2SecurityGroup", "GroupId" ] } ]
    }
  }
}
```

### YAML
<a name="quickref-rds-example-6.yaml"></a>

```
DBEC2SecurityGroup:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupDescription: Open database for access
    SecurityGroupIngress:
    - IpProtocol: tcp
      FromPort: 3306
      ToPort: 3306
      SourceSecurityGroupName:
        Ref: WebServerSecurityGroup
DBInstance:
  Type: AWS::RDS::DBInstance
  Properties:
    DBName:
      Ref: DBName
    Engine: MySQL
    MultiAZ:
      Ref: MultiAZDatabase
    MasterUsername:
      Ref: DBUser
    DBInstanceClass:
      Ref: DBClass
    AllocatedStorage:
      Ref: DBAllocatedStorage
    MasterUserPassword:
      Ref: DBPassword
    VPCSecurityGroups:
    - !GetAtt DBEC2SecurityGroup.GroupId
```

# Route 53 模板代码段
<a name="quickref-route53"></a>

**Topics**
+ [

## 使用托管区名称或 ID 的 Amazon Route 53 资源记录集
](#scenario-route53-recordset-by-host)
+ [

## 使用 RecordSetGroup 设置加权资源记录集
](#scenario-recordsetgroup-weighted)
+ [

## 使用 RecordSetGroup 设置别名资源记录集
](#scenario-recordsetgroup-zoneapex)
+ [

## CloudFront 分配的别名资源记录集
](#scenario-user-friendly-url-for-cloudfront-distribution)

## 使用托管区名称或 ID 的 Amazon Route 53 资源记录集
<a name="scenario-route53-recordset-by-host"></a>

创建 Amazon Route 53 资源记录集时，必须指定要添加该记录集的托管区。CloudFormation 提供了两种指定托管区的方法：
+ 您可以使用 `HostedZoneId` 属性明确指定托管区域。
+ 您可以使用 `HostedZoneName` 属性让 CloudFormation 查找托管区。如果使用 `HostedZoneName` 属性且存在多个名称相同的托管区，则 CloudFormation 不会创建堆栈。

### 使用 HostedZoneId 添加 RecordSet
<a name="scenario-recordset-using-id"></a>

此示例添加了一个 Amazon Route 53 资源记录集，其中包含域名 `mysite.example.com` 的 `SPF` 记录（使用 `HostedZoneId` 属性指定托管区）。

#### JSON
<a name="quickref-route53-example-1.json"></a>

```
 1. "myDNSRecord" : {
 2.   "Type" : "AWS::Route53::RecordSet",
 3.   "Properties" : 
 4.   {
 5.     "HostedZoneId" : "Z3DG6IL3SJCGPX",
 6.     "Name" : "mysite.example.com.",
 7.     "Type" : "SPF",
 8.     "TTL" : "900",
 9.     "ResourceRecords" : [ "\"v=spf1 ip4:192.168.0.1/16 -all\"" ]
10.   }
11. }
```

#### YAML
<a name="quickref-route53-example-1.yaml"></a>

```
1. myDNSRecord:
2.   Type: AWS::Route53::RecordSet
3.   Properties:
4.     HostedZoneId: Z3DG6IL3SJCGPX
5.     Name: mysite.example.com.
6.     Type: SPF
7.     TTL: '900'
8.     ResourceRecords:
9.     - '"v=spf1 ip4:192.168.0.1/16 -all"'
```

### 使用 HostedZoneName 添加 RecordSet
<a name="scenario-recordset-using-name"></a>

此示例使用 `HostedZoneName` 属性为域名“mysite.example.com”添加 Amazon Route 53 资源记录集，以指定托管区。

#### JSON
<a name="quickref-route53-example-2.json"></a>

```
 1. "myDNSRecord2" : {
 2.             "Type" : "AWS::Route53::RecordSet",
 3.             "Properties" : {
 4.                 "HostedZoneName" : "example.com.",
 5.                 "Name" : "mysite.example.com.",
 6.                 "Type" : "A",
 7.                 "TTL" : "900",
 8.                 "ResourceRecords" : [
 9.                     "192.168.0.1",
10.                     "192.168.0.2"
11.                 ]
12.             }
13.         }
```

#### YAML
<a name="quickref-route53-example-2.yaml"></a>

```
 1. myDNSRecord2:
 2.   Type: AWS::Route53::RecordSet
 3.   Properties:
 4.     HostedZoneName: example.com.
 5.     Name: mysite.example.com.
 6.     Type: A
 7.     TTL: '900'
 8.     ResourceRecords:
 9.     - 192.168.0.1
10.     - 192.168.0.2
```

## 使用 RecordSetGroup 设置加权资源记录集
<a name="scenario-recordsetgroup-weighted"></a>

此示例使用 [AWS::Route53::RecordSetGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-route53-recordsetgroup.html) 为“example.com.”托管区域设置两条 CNAME 记录。`RecordSets` 属性中含有 "mysite.example.com" DNS 名称的 CNAME 记录集。每个记录集都含有一个标识符 (`SetIdentifier`) 和权重 (`Weight`)。路由到资源的 Internet 流量比例基于以下计算：
+ `Frontend One`: `140/(140+60)` = `140/200` = 70%
+ `Frontend Two`: `60/(140+60)` = `60/200` = 30%

有关加权资源记录集的更多信息，请参阅《Amazon Route 53 开发人员指南》中的[加权路由](https://docs.amazonaws.cn/Route53/latest/DeveloperGuide/routing-policy-weighted.html)。

### JSON
<a name="quickref-route53-example-3.json"></a>

```
 1.         "myDNSOne" : {
 2.             "Type" : "AWS::Route53::RecordSetGroup",
 3.             "Properties" : {
 4.                 "HostedZoneName" : "example.com.",
 5.                 "Comment" : "Weighted RR for my frontends.",
 6.                 "RecordSets" : [
 7.                   {
 8.                     "Name" : "mysite.example.com.",
 9.                     "Type" : "CNAME",
10.                     "TTL" : "900",
11.                     "SetIdentifier" : "Frontend One",
12.                     "Weight" : "140",
13.                     "ResourceRecords" : ["example-ec2.amazonaws.com"]
14.                   },
15.                   {
16.                     "Name" : "mysite.example.com.",
17.                     "Type" : "CNAME",
18.                     "TTL" : "900",
19.                     "SetIdentifier" : "Frontend Two",
20.                     "Weight" : "60",
21.                     "ResourceRecords" : ["example-ec2-larger.amazonaws.com"]
22.                   }
23.                   ]
24.             }
25.         }
```

### YAML
<a name="quickref-route53-example-3.yaml"></a>

```
 1. myDNSOne:
 2.   Type: AWS::Route53::RecordSetGroup
 3.   Properties:
 4.     HostedZoneName: example.com.
 5.     Comment: Weighted RR for my frontends.
 6.     RecordSets:
 7.     - Name: mysite.example.com.
 8.       Type: CNAME
 9.       TTL: '900'
10.       SetIdentifier: Frontend One
11.       Weight: '140'
12.       ResourceRecords:
13.       - example-ec2.amazonaws.com
14.     - Name: mysite.example.com.
15.       Type: CNAME
16.       TTL: '900'
17.       SetIdentifier: Frontend Two
18.       Weight: '60'
19.       ResourceRecords:
20.       - example-ec2-larger.amazonaws.com
```

## 使用 RecordSetGroup 设置别名资源记录集
<a name="scenario-recordsetgroup-zoneapex"></a>

以下示例使用 [AWS::Route53::RecordSetGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-route53-recordsetgroup.html) 设置名为 `example.com` 的别名资源记录集，将流量路由到 ELB 版本 1（经典）负载均衡器和版本 2（应用程序或网络）负载均衡器。[AliasTarget](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-properties-route53-recordset-aliastarget.html) 属性使用 `GetAtt` 内置函数指定 `myELB` `LoadBalancer` 的托管区 ID 和 DNS 名称。`GetAtt` 将根据是要将流量路由到版本 1 还是版本 2 的负载均衡器来检索 `myELB` 资源的不同属性：
+ 版本 1 负载均衡器：`CanonicalHostedZoneNameID` 和 `DNSName`
+ 版本 2 负载均衡器：`CanonicalHostedZoneID` 和 `DNSName`

有关别名资源记录集的更多信息，请参阅《Route 53 开发人员指南》**中的[在别名记录和非别名记录之间进行选择](https://docs.amazonaws.cn/Route53/latest/DeveloperGuide/resource-record-sets-choosing-alias-non-alias.html)。

### 适用于版本 1 负载均衡器的 JSON
<a name="quickref-route53-example-4.json"></a>

```
 1.       "myELB" : {
 2.         "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
 3.         "Properties" : {
 4.             "AvailabilityZones" : [ "cn-north-1a" ],
 5.             "Listeners" : [ {
 6.                 "LoadBalancerPort" : "80",
 7.                 "InstancePort" : "80",
 8.                 "Protocol" : "HTTP"
 9.             } ]
10.         }
11.       },
12.       "myDNS" : {
13.         "Type" : "AWS::Route53::RecordSetGroup",
14.         "Properties" : {
15.           "HostedZoneName" : "example.com.",
16.           "Comment" : "Zone apex alias targeted to myELB LoadBalancer.",
17.           "RecordSets" : [
18.             {
19.               "Name" : "example.com.",
20.               "Type" : "A",
21.               "AliasTarget" : {
22.                   "HostedZoneId" : { "Fn::GetAtt" : ["myELB", "CanonicalHostedZoneNameID"] },
23.                   "DNSName" : { "Fn::GetAtt" : ["myELB","DNSName"] }
24.               }
25.             }
26.           ]
27.         }
28.     }
```

### 适用于版本 1 负载均衡器的 YAML
<a name="quickref-route53-example-4.yaml"></a>

```
 1. myELB:
 2.   Type: AWS::ElasticLoadBalancing::LoadBalancer
 3.   Properties:
 4.     AvailabilityZones:
 5.     - "cn-north-1a"
 6.     Listeners:
 7.     - LoadBalancerPort: '80'
 8.       InstancePort: '80'
 9.       Protocol: HTTP
10. myDNS:
11.   Type: AWS::Route53::RecordSetGroup
12.   Properties:
13.     HostedZoneName: example.com.
14.     Comment: Zone apex alias targeted to myELB LoadBalancer.
15.     RecordSets:
16.     - Name: example.com.
17.       Type: A
18.       AliasTarget:
19.         HostedZoneId: !GetAtt 'myELB.CanonicalHostedZoneNameID'
20.         DNSName: !GetAtt 'myELB.DNSName'
```

### 适用于版本 2 负载均衡器的 JSON
<a name="quickref-route53-example-4-v2.json"></a>

```
 1.       "myELB" : {
 2.         "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
 3.         "Properties" : {
 4.             "Subnets" : [ 
 5.                 {"Ref": "SubnetAZ1"}, 
 6.                 {"Ref" : "SubnetAZ2"}
 7.             ]
 8.         }
 9.       },
10.       "myDNS" : {
11.         "Type" : "AWS::Route53::RecordSetGroup",
12.         "Properties" : {
13.           "HostedZoneName" : "example.com.",
14.           "Comment" : "Zone apex alias targeted to myELB LoadBalancer.",
15.           "RecordSets" : [
16.             {
17.               "Name" : "example.com.",
18.               "Type" : "A",
19.               "AliasTarget" : {
20.                   "HostedZoneId" : { "Fn::GetAtt" : ["myELB", "CanonicalHostedZoneID"] },
21.                   "DNSName" : { "Fn::GetAtt" : ["myELB","DNSName"] }
22.               }
23.             }
24.           ]
25.         }
26.     }
```

### 适用于版本 2 负载均衡器的 YAML
<a name="quickref-route53-example-4-v2.yaml"></a>

```
 1. myELB:
 2.   Type: AWS::ElasticLoadBalancingV2::LoadBalancer
 3.   Properties:
 4.     Subnets:
 5.     - Ref: SubnetAZ1
 6.     - Ref: SubnetAZ2
 7. myDNS:
 8.   Type: AWS::Route53::RecordSetGroup
 9.   Properties:
10.     HostedZoneName: example.com.
11.     Comment: Zone apex alias targeted to myELB LoadBalancer.
12.     RecordSets:
13.     - Name: example.com.
14.       Type: A
15.       AliasTarget:
16.         HostedZoneId: !GetAtt 'myELB.CanonicalHostedZoneID'
17.         DNSName: !GetAtt 'myELB.DNSName'
```

## CloudFront 分配的别名资源记录集
<a name="scenario-user-friendly-url-for-cloudfront-distribution"></a>

下面的示例创建了将自定义域名指向 CloudFront 分发的别名 A 记录。`myHostedZoneID` 假定要么是引用同一模板中的实际 `AWS::Route53::HostedZone` 资源，要么是参数。`myCloudFrontDistribution` 指同一模板中的 `AWS::CloudFront::Distribution` 资源。别名记录会使用标准的 CloudFront 托管区 ID (`Z2FDTNDATAQYW2`)，并使用 `Fn::GetAtt` 自动解析分发的域名。此设置允许在不需要 IP 地址的情况下将网络流量从自定义域路由到 CloudFront 分发。

**注意**  
在创建别名资源记录集时，必须为 `Z2FDTNDATAQYW2` 属性指定 `HostedZoneId`。无法在私有区域中创建 CloudFront 的别名资源记录集。

### JSON
<a name="quickref-route53-example-5.json"></a>

```
 1. {
 2.     "myDNS": {
 3.         "Type": "AWS::Route53::RecordSetGroup",
 4.         "Properties": {
 5.             "HostedZoneId": {
 6.                 "Ref": "myHostedZoneID"
 7.             },
 8.             "RecordSets": [
 9.                 {
10.                     "Name": {
11.                         "Ref": "myRecordSetDomainName"
12.                     },
13.                     "Type": "A",
14.                     "AliasTarget": {
15.                         "HostedZoneId": "Z2FDTNDATAQYW2",
16.                         "DNSName": {
17.                             "Fn::GetAtt": [
18.                                 "myCloudFrontDistribution",
19.                                 "DomainName"
20.                             ]
21.                         },
22.                         "EvaluateTargetHealth": false
23.                     }
24.                 }
25.             ]
26.         }
27.     }
28. }
```

### YAML
<a name="quickref-route53-example-5.yaml"></a>

```
 1. myDNS:
 2.   Type: AWS::Route53::RecordSetGroup
 3.   Properties:
 4.     HostedZoneId: !Ref myHostedZoneID
 5.     RecordSets:
 6.       - Name: !Ref myRecordSetDomainName
 7.         Type: A
 8.         AliasTarget:
 9.           HostedZoneId: Z2FDTNDATAQYW2
10.           DNSName: !GetAtt 
11.             - myCloudFrontDistribution
12.             - DomainName
13.           EvaluateTargetHealth: false
```

# Amazon S3 模板代码段
<a name="quickref-s3"></a>

可以使用这些 Amazon S3 示例模板帮助在 CloudFormation 中描述 Amazon S3 存储桶。有关更多示例，请参阅 `AWS::S3::Bucket` 资源中的[示例](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-s3-bucket.html#aws-resource-s3-bucket--examples)部分。

**Topics**
+ [

## 使用默认值创建 Amazon S3 存储桶
](#scenario-s3-bucket)
+ [

## 为虚拟主机创建一个带 `DeletionPolicy` 的 Amazon S3 存储桶
](#scenario-s3-bucket-website)
+ [

## 使用自定义域创建静态网站
](#scenario-s3-bucket-website-customdomain)

## 使用默认值创建 Amazon S3 存储桶
<a name="scenario-s3-bucket"></a>

此示例使用 [AWS::S3::Bucket](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-s3-bucket.html) 创建带默认设置的桶。

### JSON
<a name="quickref-s3-example-1.json"></a>

```
1. "myS3Bucket" : {
2.       "Type" : "AWS::S3::Bucket"
3.       }
```

### YAML
<a name="quickref-s3-example-1.yaml"></a>

```
1. MyS3Bucket:
2.     Type: AWS::S3::Bucket
```

## 为虚拟主机创建一个带 `DeletionPolicy` 的 Amazon S3 存储桶
<a name="scenario-s3-bucket-website"></a>

此示例将创建一个存储桶作为网站，并禁用阻止公有访问（为网站托管设置的存储桶需要公有读取权限）。然后，将公有存储桶策略添加到存储桶。由于此存储桶资源有一个设置为 `Retain` 的 `DeletionPolicy` 属性，因此 CloudFormation 不会在其删除堆栈时删除此存储桶。`Output` 部分使用 `Fn::GetAtt` 检索 `S3Bucket` 资源的 `WebsiteURL` 属性和 `DomainName` 属性。

**注意**  
以下示例假设 `BlockPublicPolicy` 和 `RestrictPublicBuckets` 阻止公有访问设置已在账户级别禁用。

### JSON
<a name="quickref-s3-example-2.json"></a>

```
 1. {
 2.     "AWSTemplateFormatVersion": "2010-09-09",
 3.     "Resources": {
 4.         "S3Bucket": {
 5.             "Type": "AWS::S3::Bucket",
 6.             "Properties": {
 7.                 "PublicAccessBlockConfiguration": {
 8.                     "BlockPublicAcls": false,
 9.                     "BlockPublicPolicy": false,
10.                     "IgnorePublicAcls": false,
11.                     "RestrictPublicBuckets": false
12.                 },
13.                 "WebsiteConfiguration": {
14.                     "IndexDocument": "index.html",
15.                     "ErrorDocument": "error.html"
16.                 }
17.             },
18.             "DeletionPolicy": "Retain",
19.             "UpdateReplacePolicy": "Retain"
20.         },
21.         "BucketPolicy": {
22.             "Type": "AWS::S3::BucketPolicy",
23.             "Properties": {
24.                 "PolicyDocument": {
25.                     "Id": "MyPolicy",
26.                     "Version": "2012-10-17", 		 	 	 
27.                     "Statement": [
28.                         {
29.                             "Sid": "PublicReadForGetBucketObjects",
30.                             "Effect": "Allow",
31.                             "Principal": "*",
32.                             "Action": "s3:GetObject",
33.                             "Resource": {
34.                                 "Fn::Join": [
35.                                     "",
36.                                     [
37.                                         "arn:aws:s3:::",
38.                                         {
39.                                             "Ref": "S3Bucket"
40.                                         },
41.                                         "/*"
42.                                     ]
43.                                 ]
44.                             }
45.                         }
46.                     ]
47.                 },
48.                 "Bucket": {
49.                     "Ref": "S3Bucket"
50.                 }
51.             }
52.         }
53.     },
54.     "Outputs": {
55.         "WebsiteURL": {
56.             "Value": {
57.                 "Fn::GetAtt": [
58.                     "S3Bucket",
59.                     "WebsiteURL"
60.                 ]
61.             },
62.             "Description": "URL for website hosted on S3"
63.         },
64.         "S3BucketSecureURL": {
65.             "Value": {
66.                 "Fn::Join": [
67.                     "",
68.                     [
69.                         "https://",
70.                         {
71.                             "Fn::GetAtt": [
72.                                 "S3Bucket",
73.                                 "DomainName"
74.                             ]
75.                         }
76.                     ]
77.                 ]
78.             },
79.             "Description": "Name of S3 bucket to hold website content"
80.         }
81.     }
82. }
```

### YAML
<a name="quickref-s3-example-2.yaml"></a>

```
 1. AWSTemplateFormatVersion: 2010-09-09
 2. Resources:
 3.   S3Bucket:
 4.     Type: AWS::S3::Bucket
 5.     Properties:
 6.       PublicAccessBlockConfiguration:
 7.         BlockPublicAcls: false
 8.         BlockPublicPolicy: false
 9.         IgnorePublicAcls: false
10.         RestrictPublicBuckets: false
11.       WebsiteConfiguration:
12.         IndexDocument: index.html
13.         ErrorDocument: error.html
14.     DeletionPolicy: Retain
15.     UpdateReplacePolicy: Retain
16.   BucketPolicy:
17.     Type: AWS::S3::BucketPolicy
18.     Properties:
19.       PolicyDocument:
20.         Id: MyPolicy
21.         Version: 2012-10-17 		 	 	 
22.         Statement:
23.           - Sid: PublicReadForGetBucketObjects
24.             Effect: Allow
25.             Principal: '*'
26.             Action: 's3:GetObject'
27.             Resource: !Join 
28.               - ''
29.               - - 'arn:aws:s3:::'
30.                 - !Ref S3Bucket
31.                 - /*
32.       Bucket: !Ref S3Bucket
33. Outputs:
34.   WebsiteURL:
35.     Value: !GetAtt 
36.       - S3Bucket
37.       - WebsiteURL
38.     Description: URL for website hosted on S3
39.   S3BucketSecureURL:
40.     Value: !Join 
41.       - ''
42.       - - 'https://'
43.         - !GetAtt 
44.           - S3Bucket
45.           - DomainName
46.     Description: Name of S3 bucket to hold website content
```

## 使用自定义域创建静态网站
<a name="scenario-s3-bucket-website-customdomain"></a>

可以将 Route 53 和已注册的域一起使用。以下示例假设您已在 Route 53 中为您的域创建了托管区域。该示例创建两个用于网站托管的存储桶。根存储桶托管内容，另一个存储桶将 `www.domainname.com` 请求重定向到根存储桶。该记录集将您的域名映射到 Amazon S3 端点。

您还需要添加存储桶策略，如上面的示例所示。

有关使用自定义域的更多信息，请参阅《Amazon Simple Storage Service 用户指南**》中的[教程：使用注册到 Route 53 的自定义域配置静态网站](https://docs.amazonaws.cn/AmazonS3/latest/userguide/website-hosting-custom-domain-walkthrough.html)。

**注意**  
以下示例假设 `BlockPublicPolicy` 和 `RestrictPublicBuckets` 阻止公有访问设置已在账户级别禁用。

### JSON
<a name="quickref-s3-example-3.json"></a>

```
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Mappings" : {
        "RegionMap" : {
            "us-east-1" : { "S3hostedzoneID" : "Z3AQBSTGFYJSTF", "websiteendpoint" : "s3-website-us-east-1.amazonaws.com" },
            "us-west-1" : { "S3hostedzoneID" : "Z2F56UZL2M1ACD", "websiteendpoint" : "s3-website-us-west-1.amazonaws.com" },
            "us-west-2" : { "S3hostedzoneID" : "Z3BJ6K6RIION7M", "websiteendpoint" : "s3-website-us-west-2.amazonaws.com" },            
            "eu-west-1" : { "S3hostedzoneID" : "Z1BKCTXD74EZPE", "websiteendpoint" : "s3-website-eu-west-1.amazonaws.com" },
            "ap-southeast-1" : { "S3hostedzoneID" : "Z3O0J2DXBE1FTB", "websiteendpoint" : "s3-website-ap-southeast-1.amazonaws.com" },
            "ap-southeast-2" : { "S3hostedzoneID" : "Z1WCIGYICN2BYD", "websiteendpoint" : "s3-website-ap-southeast-2.amazonaws.com" },
            "ap-northeast-1" : { "S3hostedzoneID" : "Z2M4EHUR26P7ZW", "websiteendpoint" : "s3-website-ap-northeast-1.amazonaws.com" },
            "sa-east-1" : { "S3hostedzoneID" : "Z31GFT0UA1I2HV", "websiteendpoint" : "s3-website-sa-east-1.amazonaws.com" }
        }
    },
    "Parameters": {
        "RootDomainName": {
            "Description": "Domain name for your website (example.com)",
            "Type": "String"
        }
    },
    "Resources": {
        "RootBucket": {
            "Type": "AWS::S3::Bucket",
            "Properties": {
                "BucketName" : {"Ref":"RootDomainName"},
                "PublicAccessBlockConfiguration": {
                    "BlockPublicAcls": false,
                    "BlockPublicPolicy": false,
                    "IgnorePublicAcls": false,
                    "RestrictPublicBuckets": false
                },
                "WebsiteConfiguration": {
                    "IndexDocument":"index.html",
                    "ErrorDocument":"404.html"
                }
            }
        },
        "WWWBucket": {
            "Type": "AWS::S3::Bucket",
            "Properties": {
                "BucketName": {
                    "Fn::Join": ["", ["www.", {"Ref":"RootDomainName"}]]
                },
                "AccessControl": "BucketOwnerFullControl",
                "WebsiteConfiguration": {
                    "RedirectAllRequestsTo": {
                        "HostName": {"Ref": "RootBucket"}
                    }
                }
            }
        },
        "myDNS": {
            "Type": "AWS::Route53::RecordSetGroup",
            "Properties": {
                "HostedZoneName": {
                    "Fn::Join": ["", [{"Ref": "RootDomainName"}, "."]]
                },
                "Comment": "Zone apex alias.",
                "RecordSets": [
                    {
                        "Name": {"Ref": "RootDomainName"},
                        "Type": "A",
                        "AliasTarget": {
                            "HostedZoneId": {"Fn::FindInMap" : [ "RegionMap", { "Ref" : "AWS::Region" }, "S3hostedzoneID"]},
                            "DNSName": {"Fn::FindInMap" : [ "RegionMap", { "Ref" : "AWS::Region" }, "websiteendpoint"]}
                        }
                    },
                    {
                        "Name": {
                            "Fn::Join": ["", ["www.", {"Ref":"RootDomainName"}]]
                        },
                        "Type": "CNAME",
                        "TTL" : "900",
                        "ResourceRecords" : [
                            {"Fn::GetAtt":["WWWBucket", "DomainName"]}
                        ]
                    }
                ]
            }
        }
    },
    "Outputs": {
        "WebsiteURL": {
            "Value": {"Fn::GetAtt": ["RootBucket", "WebsiteURL"]},
            "Description": "URL for website hosted on S3"
        }
    }
}
```

### YAML
<a name="quickref-s3-example-3.yaml"></a>

```
Parameters:
  RootDomainName:
    Description: Domain name for your website (example.com)
    Type: String
Mappings:
  RegionMap:
    us-east-1:
      S3hostedzoneID: Z3AQBSTGFYJSTF
      websiteendpoint: s3-website-us-east-1.amazonaws.com
    us-west-1:
      S3hostedzoneID: Z2F56UZL2M1ACD
      websiteendpoint: s3-website-us-west-1.amazonaws.com
    us-west-2:
      S3hostedzoneID: Z3BJ6K6RIION7M
      websiteendpoint: s3-website-us-west-2.amazonaws.com
    eu-west-1:
      S3hostedzoneID: Z1BKCTXD74EZPE
      websiteendpoint: s3-website-eu-west-1.amazonaws.com
    ap-southeast-1:
      S3hostedzoneID: Z3O0J2DXBE1FTB
      websiteendpoint: s3-website-ap-southeast-1.amazonaws.com
    ap-southeast-2:
      S3hostedzoneID: Z1WCIGYICN2BYD
      websiteendpoint: s3-website-ap-southeast-2.amazonaws.com
    ap-northeast-1:
      S3hostedzoneID: Z2M4EHUR26P7ZW
      websiteendpoint: s3-website-ap-northeast-1.amazonaws.com
    sa-east-1:
      S3hostedzoneID: Z31GFT0UA1I2HV
      websiteendpoint: s3-website-sa-east-1.amazonaws.com
Resources:
  RootBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref RootDomainName
      PublicAccessBlockConfiguration:
        BlockPublicAcls: false
        BlockPublicPolicy: false
        IgnorePublicAcls: false
        RestrictPublicBuckets: false
      WebsiteConfiguration:
        IndexDocument: index.html
        ErrorDocument: 404.html
  WWWBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub
        - www.${Domain}
        - Domain: !Ref RootDomainName
      AccessControl: BucketOwnerFullControl
      WebsiteConfiguration:
        RedirectAllRequestsTo:
          HostName: !Ref RootBucket
  myDNS:
    Type: AWS::Route53::RecordSetGroup
    Properties:
      HostedZoneName: !Sub 
        - ${Domain}.
        - Domain: !Ref RootDomainName
      Comment: Zone apex alias.
      RecordSets:
        - Name: !Ref RootDomainName
          Type: A
          AliasTarget:
            HostedZoneId: !FindInMap [ RegionMap, !Ref 'AWS::Region', S3hostedzoneID]
            DNSName: !FindInMap [ RegionMap, !Ref 'AWS::Region', websiteendpoint]
        - Name: !Sub
            - www.${Domain}
            - Domain: !Ref RootDomainName
          Type: CNAME
          TTL: 900
          ResourceRecords:
            - !GetAtt WWWBucket.DomainName
Outputs:
  WebsiteURL:
    Value: !GetAtt RootBucket.WebsiteURL
    Description: URL for website hosted on S3
```

# Amazon SNS 模板代码段
<a name="quickref-sns"></a>

此示例显示 Amazon SNS 主题资源。它需要有效的电子邮件地址。

## JSON
<a name="quickref-sns-example-1.json"></a>

```
1. "MySNSTopic" : {
2.     "Type" : "AWS::SNS::Topic",
3.     "Properties" : {
4.         "Subscription" : [ {
5.             "Endpoint" : "add valid email address",
6.             "Protocol" : "email"
7.         } ]
8.     }
9. }
```

## YAML
<a name="quickref-sns-example-1.yaml"></a>

```
1. MySNSTopic:
2.   Type: AWS::SNS::Topic
3.   Properties:
4.     Subscription:
5.     - Endpoint: "add valid email address"
6.       Protocol: email
```

# Amazon SQS 模板代码段
<a name="scenario-sqs-queue"></a>

此示例显示的是 Amazon SQS 队列。

## JSON
<a name="scenario-sqs-queue-example-1.json"></a>

```
1. "MyQueue" : {
2.     "Type" : "AWS::SQS::Queue",
3.     "Properties" : {
4.         "VisibilityTimeout" : "value"
5.     }
6. }
```

## YAML
<a name="scenario-sqs-queue-example-1.yaml"></a>

```
1. MyQueue:
2.   Type: AWS::SQS::Queue
3.   Properties:
4.     VisibilityTimeout: value
```

# Amazon Timestream 模板代码片段
<a name="scenario-timestream-queue"></a>

借助适用于 InfluxDB 的 Amazon Timestream，应用程序开发人员和 DevOps 团队可以在 Amazon 上轻松使用开源 API 为实时时间序列应用程序运行完全托管的 InfluxDB 数据库。您可以快速创建 InfluxDB 数据库，用来处理要求严格的时间序列工作负载。只需几个简单的 API 调用，就可以在 Amazon 上安装、迁移、操作和扩展具有自动软件修补、备份和恢复功能的 InfluxDB 数据库。此外还可以在 GitHub 中的 [awslabs/amazon-timestream-tools/tree/mainline/integrations/cloudformation/timestream-influxdb](https://github.com/awslabs/amazon-timestream-tools/tree/mainline/integrations/cloudformation/timestream-influxdb) 页面上找到这些示例。

**Topics**
+ [

## 使用默认值的精简样本
](#scenario-timestream-influxdb-example-1)
+ [

## 带参数的更完整示例
](#scenario-timestream-influxdb-example-2)

这些 Amazon CloudFormation 模板将创建下列所需的资源，以成功创建、连接到和监控适用于 InfluxDB 的 Amazon Timestream 实例：

**Amazon VPC**
+ `VPC`
+ 一个或多个 `Subnet`
+ `InternetGateway`
+ `RouteTable`
+ `SecurityGroup`

**Amazon S3**
+ `Bucket`

**Amazon Timestream**
+ `InfluxDBInstance`

## 使用默认值的精简样本
<a name="scenario-timestream-influxdb-example-1"></a>

此示例会尽可能使用默认值部署多可用区和可公开访问的实例。

### JSON
<a name="scenario-timestream-influxdb-example-1.json"></a>

```
{
  "Metadata": {
    "AWS::CloudFormation::Interface": {
      "ParameterGroups": [
        {
          "Label": {"default": "Amazon Timestream for InfluxDB Configuration"},
          "Parameters": [
            "DbInstanceName",
            "InfluxDBPassword"
          ]
        }
      ],
      "ParameterLabels": {
        "VPCCIDR": {"default": "VPC CIDR"}
      }
    }
  },
  "Parameters": {
    "DbInstanceName": {
      "Description": "The name that uniquely identifies the DB instance when interacting with the Amazon Timestream for InfluxDB API and CLI commands. This name will also be a prefix included in the endpoint. DB instance names must be unique per customer and per Region.",
      "Type": "String",
      "Default": "mydbinstance",
      "MinLength": 3,
      "MaxLength": 40,
      "AllowedPattern": "^[a-zA-z][a-zA-Z0-9]*(-[a-zA-Z0-9]+)*$"
    },
    "InfluxDBPassword": {
      "Description": "The password of the initial admin user created in InfluxDB. This password will allow you to access the InfluxDB UI to perform various administrative tasks and also use the InfluxDB CLI to create an operator token. These attributes will be stored in a Secret created in Amazon Secrets Manager in your account.",
      "Type": "String",
      "NoEcho": true,
      "MinLength": 8,
      "MaxLength": 64,
      "AllowedPattern": "^[a-zA-Z0-9]+$"
    }
  },
  "Resources": {
    "VPC": {
      "Type": "AWS::EC2::VPC",
      "Properties": {"CidrBlock": "10.0.0.0/16"}
    },
    "InternetGateway": {"Type": "AWS::EC2::InternetGateway"},
    "InternetGatewayAttachment": {
      "Type": "AWS::EC2::VPCGatewayAttachment",
      "Properties": {
        "InternetGatewayId": {"Ref": "InternetGateway"},
        "VpcId": {"Ref": "VPC"}
      }
    },
    "Subnet1": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {"Ref": "VPC"},
        "AvailabilityZone": {
          "Fn::Select": [
            0,
            {"Fn::GetAZs": ""}
          ]
        },
        "CidrBlock": {
          "Fn::Select": [
            0,
            {
              "Fn::Cidr": [
                {
                  "Fn::GetAtt": [
                    "VPC",
                    "CidrBlock"
                  ]
                },
                2,
                12
              ]
            }
          ]
        },
        "MapPublicIpOnLaunch": true
      }
    },
    "Subnet2": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {"Ref": "VPC"},
        "AvailabilityZone": {
          "Fn::Select": [
            1,
            {"Fn::GetAZs": ""}
          ]
        },
        "CidrBlock": {
          "Fn::Select": [
            1,
            {
              "Fn::Cidr": [
                {
                  "Fn::GetAtt": [
                    "VPC",
                    "CidrBlock"
                  ]
                },
                2,
                12
              ]
            }
          ]
        },
        "MapPublicIpOnLaunch": true
      }
    },
    "RouteTable": {
      "Type": "AWS::EC2::RouteTable",
      "Properties": {
        "VpcId": {"Ref": "VPC"}
      }
    },
    "DefaultRoute": {
      "Type": "AWS::EC2::Route",
      "DependsOn": "InternetGatewayAttachment",
      "Properties": {
        "RouteTableId": {"Ref": "RouteTable"},
        "DestinationCidrBlock": "0.0.0.0/0",
        "GatewayId": {"Ref": "InternetGateway"}
      }
    },
    "Subnet1RouteTableAssociation": {
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "RouteTableId": {"Ref": "RouteTable"},
        "SubnetId": {"Ref": "Subnet1"}
      }
    },
    "Subnet2RouteTableAssociation": {
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "RouteTableId": {"Ref": "RouteTable"},
        "SubnetId": {"Ref": "Subnet2"}
      }
    },
    "InfluxDBSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupName": "influxdb-sg",
        "GroupDescription": "Security group allowing port 8086 ingress for InfluxDB",
        "VpcId": {"Ref": "VPC"}
      }
    },
    "InfluxDBSecurityGroupIngress": {
      "Type": "AWS::EC2::SecurityGroupIngress",
      "Properties": {
        "GroupId": {"Ref": "InfluxDBSecurityGroup"},
        "IpProtocol": "tcp",
        "CidrIp": "0.0.0.0/0",
        "FromPort": 8086,
        "ToPort": 8086
      }
    },
    "InfluxDBLogsS3Bucket": {
      "Type": "AWS::S3::Bucket",
      "DeletionPolicy": "Retain"
    },
    "InfluxDBLogsS3BucketPolicy": {
      "Type": "AWS::S3::BucketPolicy",
      "Properties": {
        "Bucket": {"Ref": "InfluxDBLogsS3Bucket"},
        "PolicyDocument": {
          "Version": "2012-10-17",		 	 	 
          "Statement": [
            {
              "Action": "s3:PutObject",
              "Effect": "Allow",
              "Resource": {"Fn::Sub": "arn:aws:s3:::${InfluxDBLogsS3Bucket}/InfluxLogs/*"},
              "Principal": {"Service": "timestream-influxdb.amazonaws.com"}
            },
            {
              "Action": "s3:*",
              "Effect": "Deny",
              "Resource": [
                {"Fn::Sub": "arn:aws:s3:::${InfluxDBLogsS3Bucket}/*"},
                {"Fn::Sub": "arn:aws:s3:::${InfluxDBLogsS3Bucket}"}
              ],
              "Principal": "*",
              "Condition": {
                "Bool": {"aws:SecureTransport": false}
              }
            }
          ]
        }
      }
    },
    "DbInstance": {
      "Type": "AWS::Timestream::InfluxDBInstance",
      "DependsOn": "InfluxDBLogsS3BucketPolicy",
      "Properties": {
        "AllocatedStorage": 20,
        "DbInstanceType": "db.influx.medium",
        "Name": {"Ref": "DbInstanceName"},
        "Password": {"Ref": "InfluxDBPassword"},
        "PubliclyAccessible": true,
        "DeploymentType": "WITH_MULTIAZ_STANDBY",
        "VpcSecurityGroupIds": [
          {"Ref": "InfluxDBSecurityGroup"}
        ],
        "VpcSubnetIds": [
          {"Ref": "Subnet1"},
          {"Ref": "Subnet2"}
        ],
        "LogDeliveryConfiguration": {
          "S3Configuration": {
            "BucketName": {"Ref": "InfluxDBLogsS3Bucket"},
            "Enabled": true
          }
        }
      }
    }
  },
  "Outputs": {
    "VPC": {
      "Description": "A reference to the VPC used to create network resources",
      "Value": {"Ref": "VPC"}
    },
    "Subnets": {
      "Description": "A list of the subnets created",
      "Value": {
        "Fn::Join": [
          ",",
          [
            {"Ref": "Subnet1"},
            {"Ref": "Subnet2"}
          ]
        ]
      }
    },
    "Subnet1": {
      "Description": "A reference to the subnet in the 1st Availability Zone",
      "Value": {"Ref": "Subnet1"}
    },
    "Subnet2": {
      "Description": "A reference to the subnet in the 2nd Availability Zone",
      "Value": {"Ref": "Subnet2"}
    },
    "InfluxDBSecurityGroup": {
      "Description": "Security group with port 8086 ingress rule",
      "Value": {"Ref": "InfluxDBSecurityGroup"}
    },
    "InfluxDBLogsS3Bucket": {
      "Description": "S3 Bucket containing InfluxDB logs from the DB instance",
      "Value": {"Ref": "InfluxDBLogsS3Bucket"}
    },
    "DbInstance": {
      "Description": "A reference to the Timestream for InfluxDB DB instance",
      "Value": {"Ref": "DbInstance"}
    },
    "InfluxAuthParametersSecretArn": {
      "Description": "The Amazon Resource Name (ARN) of the Amazon Secrets Manager secret containing the initial InfluxDB authorization parameters. The secret value is a JSON formatted key-value pair holding InfluxDB authorization values: organization, bucket, username, and password.",
      "Value": {
        "Fn::GetAtt": [
          "DbInstance",
          "InfluxAuthParametersSecretArn"
        ]
      }
    },
    "Endpoint": {
      "Description": "The endpoint URL to connect to InfluxDB",
      "Value": {
        "Fn::Join": [
          "",
          [
            "https://",
            {
              "Fn::GetAtt": [
                "DbInstance",
                "Endpoint"
              ]
            },
            ":8086"
          ]
        ]
      }
    }
  }
}
```

### YAML
<a name="scenario-timestream-influxdb-example-1.yaml"></a>

```
Metadata: 
  AWS::CloudFormation::Interface:
    ParameterGroups:
      -
        Label:
          default: "Amazon Timestream for InfluxDB Configuration"
        Parameters:
          - DbInstanceName
          - InfluxDBPassword
    ParameterLabels:
      VPCCIDR:
        default: VPC CIDR

Parameters:
  DbInstanceName:
    Description: The name that uniquely identifies the DB instance when interacting with the Amazon Timestream for InfluxDB API and CLI commands. This name will also be a prefix included in the endpoint. DB instance names must be unique per customer and per Region.
    Type: String
    Default: mydbinstance
    MinLength: 3
    MaxLength: 40
    AllowedPattern: ^[a-zA-z][a-zA-Z0-9]*(-[a-zA-Z0-9]+)*$
  InfluxDBPassword:
    Description: The password of the initial admin user created in InfluxDB. This password will allow you to access the InfluxDB UI to perform various administrative tasks and also use the InfluxDB CLI to create an operator token. These attributes will be stored in a Secret created in Amazon Secrets Manager in your account.
    Type: String
    NoEcho: true
    MinLength: 8
    MaxLength: 64
    AllowedPattern: ^[a-zA-Z0-9]+$

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
  InternetGateway:
    Type: AWS::EC2::InternetGateway
  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC
  Subnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [0, !GetAZs '']
      CidrBlock: !Select [0, !Cidr [!GetAtt VPC.CidrBlock, 2, 12 ]]
      MapPublicIpOnLaunch: true
  Subnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [1, !GetAZs  '']
      CidrBlock: !Select [1, !Cidr [!GetAtt VPC.CidrBlock, 2, 12 ]]
      MapPublicIpOnLaunch: true
  RouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
  DefaultRoute:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref RouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  Subnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref RouteTable
      SubnetId: !Ref Subnet1
  Subnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref RouteTable
      SubnetId: !Ref Subnet2
  InfluxDBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: "influxdb-sg"
      GroupDescription: "Security group allowing port 8086 ingress for InfluxDB"
      VpcId: !Ref VPC
  InfluxDBSecurityGroupIngress:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !Ref InfluxDBSecurityGroup
      IpProtocol: tcp
      CidrIp: 0.0.0.0/0
      FromPort: 8086
      ToPort: 8086
  InfluxDBLogsS3Bucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
  InfluxDBLogsS3BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref InfluxDBLogsS3Bucket
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Action: "s3:PutObject"
            Effect: Allow
            Resource: !Sub arn:aws:s3:::${InfluxDBLogsS3Bucket}/InfluxLogs/*
            Principal:
              Service: timestream-influxdb.amazonaws.com
          - Action: "s3:*"
            Effect: Deny
            Resource:
              - !Sub arn:aws:s3:::${InfluxDBLogsS3Bucket}/*
              - !Sub arn:aws:s3:::${InfluxDBLogsS3Bucket}
            Principal: "*"
            Condition:
              Bool:
                aws:SecureTransport: false
  DbInstance:
    Type: AWS::Timestream::InfluxDBInstance
    DependsOn: InfluxDBLogsS3BucketPolicy
    Properties:
      AllocatedStorage: 20
      DbInstanceType: db.influx.medium
      Name: !Ref DbInstanceName
      Password: !Ref InfluxDBPassword
      PubliclyAccessible: true
      DeploymentType: WITH_MULTIAZ_STANDBY
      VpcSecurityGroupIds: 
        - !Ref InfluxDBSecurityGroup
      VpcSubnetIds:
        - !Ref Subnet1
        - !Ref Subnet2
      LogDeliveryConfiguration:
        S3Configuration:
          BucketName: !Ref InfluxDBLogsS3Bucket
          Enabled: true

Outputs:
  # Network Resources
  VPC:
    Description: A reference to the VPC used to create network resources
    Value: !Ref VPC
  Subnets:
    Description: A list of the subnets created
    Value: !Join [",", [!Ref Subnet1, !Ref Subnet2]]
  Subnet1:
    Description: A reference to the subnet in the 1st Availability Zone
    Value: !Ref Subnet1
  Subnet2:
    Description: A reference to the subnet in the 2nd Availability Zone
    Value: !Ref Subnet2
  InfluxDBSecurityGroup:
    Description: Security group with port 8086 ingress rule
    Value: !Ref InfluxDBSecurityGroup

  # Timestream for InfluxDB Resources
  InfluxDBLogsS3Bucket:
    Description: S3 Bucket containing InfluxDB logs from the DB instance
    Value: !Ref InfluxDBLogsS3Bucket
  DbInstance:
    Description: A reference to the Timestream for InfluxDB DB instance
    Value: !Ref DbInstance
  InfluxAuthParametersSecretArn:
    Description: "The Amazon Resource Name (ARN) of the Amazon Secrets Manager secret containing the initial InfluxDB authorization parameters. The secret value is a JSON formatted key-value pair holding InfluxDB authorization values: organization, bucket, username, and password."
    Value: !GetAtt DbInstance.InfluxAuthParametersSecretArn
  Endpoint:
    Description: The endpoint URL to connect to InfluxDB
    Value: !Join ["", ["https://", !GetAtt DbInstance.Endpoint, ":8086"]]
```

## 带参数的更完整示例
<a name="scenario-timestream-influxdb-example-2"></a>

此示例模板会根据提供的参数动态更改网络资源。参数包括 `PubliclyAccessible` 和 `DeploymentType`。

### JSON
<a name="scenario-timestream-influxdb-example-2.json"></a>

```
{
  "Metadata": {
    "AWS::CloudFormation::Interface": {
      "ParameterGroups": [
        {
          "Label": {"default": "Network Configuration"},
          "Parameters": ["VPCCIDR"]
        },
        {
          "Label": {"default": "Amazon Timestream for InfluxDB Configuration"},
          "Parameters": [
            "DbInstanceName",
            "InfluxDBUsername",
            "InfluxDBPassword",
            "InfluxDBOrganization",
            "InfluxDBBucket",
            "DbInstanceType",
            "DbStorageType",
            "AllocatedStorage",
            "PubliclyAccessible",
            "DeploymentType"
          ]
        }
      ],
      "ParameterLabels": {
        "VPCCIDR": {"default": "VPC CIDR"}
      }
    }
  },
  "Parameters": {
    "VPCCIDR": {
      "Description": "Please enter the IP range (CIDR notation) for the new VPC",
      "Type": "String",
      "Default": "10.0.0.0/16"
    },
    "DbInstanceName": {
      "Description": "The name that uniquely identifies the DB instance when interacting with the Amazon Timestream for InfluxDB API and CLI commands. This name will also be a prefix included in the endpoint. DB instance names must be unique per customer and per Region.",
      "Type": "String",
      "Default": "mydbinstance",
      "MinLength": 3,
      "MaxLength": 40,
      "AllowedPattern": "^[a-zA-z][a-zA-Z0-9]*(-[a-zA-Z0-9]+)*$"
    },
    "InfluxDBUsername": {
      "Description": "The username of the initial admin user created in InfluxDB. Must start with a letter and can't end with a hyphen or contain two consecutive hyphens. For example, my-user1. This username will allow you to access the InfluxDB UI to perform various administrative tasks and also use the InfluxDB CLI to create an operator token. These attributes will be stored in a Secret created in Amazon Secrets Manager in your account.",
      "Type": "String",
      "Default": "admin",
      "MinLength": 1,
      "MaxLength": 64
    },
    "InfluxDBPassword": {
      "Description": "The password of the initial admin user created in InfluxDB. This password will allow you to access the InfluxDB UI to perform various administrative tasks and also use the InfluxDB CLI to create an operator token. These attributes will be stored in a Secret created in Amazon Secrets Manager in your account.",
      "Type": "String",
      "NoEcho": true,
      "MinLength": 8,
      "MaxLength": 64,
      "AllowedPattern": "^[a-zA-Z0-9]+$"
    },
    "InfluxDBOrganization": {
      "Description": "The name of the initial organization for the initial admin user in InfluxDB. An InfluxDB organization is a workspace for a group of users.",
      "Type": "String",
      "Default": "org",
      "MinLength": 1,
      "MaxLength": 64
    },
    "InfluxDBBucket": {
      "Description": "The name of the initial InfluxDB bucket. All InfluxDB data is stored in a bucket. A bucket combines the concept of a database and a retention period (the duration of time that each data point persists). A bucket belongs to an organization.",
      "Type": "String",
      "Default": "bucket",
      "MinLength": 2,
      "MaxLength": 64,
      "AllowedPattern": "^[^_\\\"][^\\\"]*$"
    },
    "DeploymentType": {
      "Description": "Specifies whether the Timestream for InfluxDB is deployed as Single-AZ or with a MultiAZ Standby for High availability",
      "Type": "String",
      "Default": "WITH_MULTIAZ_STANDBY",
      "AllowedValues": [
        "SINGLE_AZ",
        "WITH_MULTIAZ_STANDBY"
      ]
    },
    "AllocatedStorage": {
      "Description": "The amount of storage to allocate for your DB storage type in GiB (gibibytes).",
      "Type": "Number",
      "Default": 400,
      "MinValue": 20,
      "MaxValue": 16384
    },
    "DbInstanceType": {
      "Description": "The Timestream for InfluxDB DB instance type to run InfluxDB on.",
      "Type": "String",
      "Default": "db.influx.medium",
      "AllowedValues": [
        "db.influx.medium",
        "db.influx.large",
        "db.influx.xlarge",
        "db.influx.2xlarge",
        "db.influx.4xlarge",
        "db.influx.8xlarge",
        "db.influx.12xlarge",
        "db.influx.16xlarge"
      ]
    },
    "DbStorageType": {
      "Description": "The Timestream for InfluxDB DB storage type to read and write InfluxDB data.",
      "Type": "String",
      "Default": "InfluxIOIncludedT1",
      "AllowedValues": [
        "InfluxIOIncludedT1",
        "InfluxIOIncludedT2",
        "InfluxIOIncludedT3"
      ]
    },
    "PubliclyAccessible": {
      "Description": "Configures the DB instance with a public IP to facilitate access.",
      "Type": "String",
      "Default": true,
      "AllowedValues": [
        true,
        false
      ]
    }
  },
  "Conditions": {
    "IsMultiAZ": {
      "Fn::Equals": [
        {"Ref": "DeploymentType"},
        "WITH_MULTIAZ_STANDBY"
      ]
    },
    "IsPublic": {
      "Fn::Equals": [
        {"Ref": "PubliclyAccessible"},
        true
      ]
    }
  },
  "Resources": {
    "VPC": {
      "Type": "AWS::EC2::VPC",
      "Properties": {
        "CidrBlock": {"Ref": "VPCCIDR"}
      }
    },
    "InternetGateway": {
      "Type": "AWS::EC2::InternetGateway",
      "Condition": "IsPublic"
    },
    "InternetGatewayAttachment": {
      "Type": "AWS::EC2::VPCGatewayAttachment",
      "Condition": "IsPublic",
      "Properties": {
        "InternetGatewayId": {"Ref": "InternetGateway"},
        "VpcId": {"Ref": "VPC"}
      }
    },
    "Subnet1": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {"Ref": "VPC"},
        "AvailabilityZone": {
          "Fn::Select": [
            0,
            {"Fn::GetAZs": ""}
          ]
        },
        "CidrBlock": {
          "Fn::Select": [
            0,
            {
              "Fn::Cidr": [
                {
                  "Fn::GetAtt": [
                    "VPC",
                    "CidrBlock"
                  ]
                },
                2,
                12
              ]
            }
          ]
        },
        "MapPublicIpOnLaunch": {
          "Fn::If": [
            "IsPublic",
            true,
            false
          ]
        }
      }
    },
    "Subnet2": {
      "Type": "AWS::EC2::Subnet",
      "Condition": "IsMultiAZ",
      "Properties": {
        "VpcId": {"Ref": "VPC"},
        "AvailabilityZone": {
          "Fn::Select": [
            1,
            {"Fn::GetAZs": ""}
          ]
        },
        "CidrBlock": {
          "Fn::Select": [
            1,
            {
              "Fn::Cidr": [
                {
                  "Fn::GetAtt": [
                    "VPC",
                    "CidrBlock"
                  ]
                },
                2,
                12
              ]
            }
          ]
        },
        "MapPublicIpOnLaunch": {
          "Fn::If": [
            "IsPublic",
            true,
            false
          ]
        }
      }
    },
    "RouteTable": {
      "Type": "AWS::EC2::RouteTable",
      "Properties": {
        "VpcId": {"Ref": "VPC"}
      }
    },
    "DefaultRoute": {
      "Type": "AWS::EC2::Route",
      "Condition": "IsPublic",
      "DependsOn": "InternetGatewayAttachment",
      "Properties": {
        "RouteTableId": {"Ref": "RouteTable"},
        "DestinationCidrBlock": "0.0.0.0/0",
        "GatewayId": {"Ref": "InternetGateway"}
      }
    },
    "Subnet1RouteTableAssociation": {
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "RouteTableId": {"Ref": "RouteTable"},
        "SubnetId": {"Ref": "Subnet1"}
      }
    },
    "Subnet2RouteTableAssociation": {
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Condition": "IsMultiAZ",
      "Properties": {
        "RouteTableId": {"Ref": "RouteTable"},
        "SubnetId": {"Ref": "Subnet2"}
      }
    },
    "InfluxDBSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupName": "influxdb-sg",
        "GroupDescription": "Security group allowing port 8086 ingress for InfluxDB",
        "VpcId": {"Ref": "VPC"}
      }
    },
    "InfluxDBSecurityGroupIngress": {
      "Type": "AWS::EC2::SecurityGroupIngress",
      "Properties": {
        "GroupId": {"Ref": "InfluxDBSecurityGroup"},
        "IpProtocol": "tcp",
        "CidrIp": "0.0.0.0/0",
        "FromPort": 8086,
        "ToPort": 8086
      }
    },
    "InfluxDBLogsS3Bucket": {
      "Type": "AWS::S3::Bucket",
      "DeletionPolicy": "Retain"
    },
    "InfluxDBLogsS3BucketPolicy": {
      "Type": "AWS::S3::BucketPolicy",
      "Properties": {
        "Bucket": {"Ref": "InfluxDBLogsS3Bucket"},
        "PolicyDocument": {
          "Version": "2012-10-17",		 	 	 
          "Statement": [
            {
              "Action": "s3:PutObject",
              "Effect": "Allow",
              "Resource": {"Fn::Sub": "arn:aws:s3:::${InfluxDBLogsS3Bucket}/InfluxLogs/*"},
              "Principal": {"Service": "timestream-influxdb.amazonaws.com"}
            },
            {
              "Action": "s3:*",
              "Effect": "Deny",
              "Resource": [
                {"Fn::Sub": "arn:aws:s3:::${InfluxDBLogsS3Bucket}/*"},
                {"Fn::Sub": "arn:aws:s3:::${InfluxDBLogsS3Bucket}"}
              ],
              "Principal": "*",
              "Condition": {
                "Bool": {"aws:SecureTransport": false}
              }
            }
          ]
        }
      }
    },
    "DbInstance": {
      "Type": "AWS::Timestream::InfluxDBInstance",
      "DependsOn": "InfluxDBLogsS3BucketPolicy",
      "Properties": {
        "DbStorageType": {"Ref": "DbStorageType"},
        "AllocatedStorage": {"Ref": "AllocatedStorage"},
        "DbInstanceType": {"Ref": "DbInstanceType"},
        "Name": {"Ref": "DbInstanceName"},
        "Username": {"Ref": "InfluxDBUsername"},
        "Password": {"Ref": "InfluxDBPassword"},
        "Organization": {"Ref": "InfluxDBOrganization"},
        "Bucket": {"Ref": "InfluxDBBucket"},
        "PubliclyAccessible": {
          "Fn::If": [
            "IsPublic",
            true,
            false
          ]
        },
        "DeploymentType": {"Ref": "DeploymentType"},
        "VpcSecurityGroupIds": [
          {"Ref": "InfluxDBSecurityGroup"}
        ],
        "VpcSubnetIds": {
          "Fn::If": [
            "IsMultiAZ",
            [
              {"Ref": "Subnet1"},
              {"Ref": "Subnet2"}
            ],
            [
              {"Ref": "Subnet1"}
            ]
          ]
        },
        "LogDeliveryConfiguration": {
          "S3Configuration": {
            "BucketName": {"Ref": "InfluxDBLogsS3Bucket"},
            "Enabled": true
          }
        }
      }
    }
  },
  "Outputs": {
    "VPC": {
      "Description": "A reference to the VPC used to create network resources",
      "Value": {"Ref": "VPC"}
    },
    "Subnets": {
      "Description": "A list of the subnets created",
      "Value": {
        "Fn::If": [
          "IsMultiAZ",
          {
            "Fn::Join": [
              ",",
              [
                {"Ref": "Subnet1"},
                {"Ref": "Subnet2"}
              ]
            ]
          },
          {"Ref": "Subnet1"}
        ]
      }
    },
    "Subnet1": {
      "Description": "A reference to the subnet in the 1st Availability Zone",
      "Value": {"Ref": "Subnet1"}
    },
    "Subnet2": {
      "Condition": "IsMultiAZ",
      "Description": "A reference to the subnet in the 2nd Availability Zone",
      "Value": {"Ref": "Subnet2"}
    },
    "InfluxDBSecurityGroup": {
      "Description": "Security group with port 8086 ingress rule",
      "Value": {"Ref": "InfluxDBSecurityGroup"}
    },
    "InfluxDBLogsS3Bucket": {
      "Description": "S3 Bucket containing InfluxDB logs from the DB instance",
      "Value": {"Ref": "InfluxDBLogsS3Bucket"}
    },
    "DbInstance": {
      "Description": "A reference to the Timestream for InfluxDB DB instance",
      "Value": {"Ref": "DbInstance"}
    },
    "InfluxAuthParametersSecretArn": {
      "Description": "The Amazon Resource Name (ARN) of the Amazon Secrets Manager secret containing the initial InfluxDB authorization parameters. The secret value is a JSON formatted key-value pair holding InfluxDB authorization values: organization, bucket, username, and password.",
      "Value": {
        "Fn::GetAtt": [
          "DbInstance",
          "InfluxAuthParametersSecretArn"
        ]
      }
    },
    "Endpoint": {
      "Description": "The endpoint URL to connect to InfluxDB",
      "Value": {
        "Fn::Join": [
          "",
          [
            "https://",
            {
              "Fn::GetAtt": [
                "DbInstance",
                "Endpoint"
              ]
            },
            ":8086"
          ]
        ]
      }
    }
  }
}
```

### YAML
<a name="scenario-timestream-influxdb-example-2.yaml"></a>

```
Metadata: 
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - 
        Label:
          default: "Network Configuration"
        Parameters:
          - VPCCIDR
      -
        Label:
          default: "Amazon Timestream for InfluxDB Configuration"
        Parameters:
          - DbInstanceName
          - InfluxDBUsername
          - InfluxDBPassword
          - InfluxDBOrganization
          - InfluxDBBucket
          - DbInstanceType
          - DbStorageType
          - AllocatedStorage
          - PubliclyAccessible
          - DeploymentType
    ParameterLabels:
      VPCCIDR:
        default: VPC CIDR

Parameters:
  # Network Configuration
  VPCCIDR:
    Description: Please enter the IP range (CIDR notation) for the new VPC
    Type: String
    Default: 10.0.0.0/16
  # Timestream for InfluxDB Configuration
  DbInstanceName:
    Description: The name that uniquely identifies the DB instance when interacting with the Amazon Timestream for InfluxDB API and CLI commands. This name will also be a prefix included in the endpoint. DB instance names must be unique per customer and per Region.
    Type: String
    Default: mydbinstance
    MinLength: 3
    MaxLength: 40    
    AllowedPattern: ^[a-zA-z][a-zA-Z0-9]*(-[a-zA-Z0-9]+)*$
  # InfluxDB initial user configurations
  InfluxDBUsername:
    Description: The username of the initial admin user created in InfluxDB. Must start with a letter and can't end with a hyphen or contain two consecutive hyphens. For example, my-user1. This username will allow you to access the InfluxDB UI to perform various administrative tasks and also use the InfluxDB CLI to create an operator token. These attributes will be stored in a Secret created in Amazon Secrets Manager in your account.
    Type: String
    Default: admin
    MinLength: 1
    MaxLength: 64
  InfluxDBPassword:
    Description: The password of the initial admin user created in InfluxDB. This password will allow you to access the InfluxDB UI to perform various administrative tasks and also use the InfluxDB CLI to create an operator token. These attributes will be stored in a Secret created in Amazon in your account.
    Type: String
    NoEcho: true
    MinLength: 8
    MaxLength: 64
    AllowedPattern: ^[a-zA-Z0-9]+$
  InfluxDBOrganization:
    Description: The name of the initial organization for the initial admin user in InfluxDB. An InfluxDB organization is a workspace for a group of users.
    Type: String
    Default: org
    MinLength: 1
    MaxLength: 64
  InfluxDBBucket:
    Description: The name of the initial InfluxDB bucket. All InfluxDB data is stored in a bucket. A bucket combines the concept of a database and a retention period (the duration of time that each data point persists). A bucket belongs to an organization.
    Type: String
    Default: bucket
    MinLength: 2
    MaxLength: 64
    AllowedPattern: ^[^_\"][^\"]*$
  DeploymentType:
    Description: Specifies whether the Timestream for InfluxDB is deployed as Single-AZ or with a MultiAZ Standby for High availability
    Type: String
    Default: WITH_MULTIAZ_STANDBY
    AllowedValues:
      - SINGLE_AZ
      - WITH_MULTIAZ_STANDBY
  AllocatedStorage:
    Description: The amount of storage to allocate for your DB storage type in GiB (gibibytes).
    Type: Number
    Default: 400
    MinValue: 20
    MaxValue: 16384
  DbInstanceType:
    Description: The Timestream for InfluxDB DB instance type to run InfluxDB on.
    Type: String
    Default: db.influx.medium
    AllowedValues:
      - db.influx.medium
      - db.influx.large
      - db.influx.xlarge
      - db.influx.2xlarge
      - db.influx.4xlarge
      - db.influx.8xlarge
      - db.influx.12xlarge
      - db.influx.16xlarge
  DbStorageType:
    Description: The Timestream for InfluxDB DB storage type to read and write InfluxDB data.
    Type: String
    Default: InfluxIOIncludedT1
    AllowedValues:
      - InfluxIOIncludedT1
      - InfluxIOIncludedT2
      - InfluxIOIncludedT3
  PubliclyAccessible:
    Description: Configures the DB instance with a public IP to facilitate access.
    Type: String
    Default: true
    AllowedValues:
      - true
      - false

Conditions:
  IsMultiAZ: !Equals [!Ref DeploymentType, WITH_MULTIAZ_STANDBY]
  IsPublic: !Equals [!Ref PubliclyAccessible, true]

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VPCCIDR
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Condition: IsPublic
  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Condition: IsPublic
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC
  Subnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [0, !GetAZs '']
      CidrBlock: !Select [0, !Cidr [!GetAtt VPC.CidrBlock, 2, 12 ]]
      MapPublicIpOnLaunch: !If [IsPublic, true, false]
  Subnet2:
    Type: AWS::EC2::Subnet
    Condition: IsMultiAZ
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [1, !GetAZs  '']
      CidrBlock: !Select [1, !Cidr [!GetAtt VPC.CidrBlock, 2, 12 ]]
      MapPublicIpOnLaunch: !If [IsPublic, true, false]
  RouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
  DefaultRoute:
    Type: AWS::EC2::Route
    Condition: IsPublic
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref RouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  Subnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref RouteTable
      SubnetId: !Ref Subnet1
  Subnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Condition: IsMultiAZ
    Properties:
      RouteTableId: !Ref RouteTable
      SubnetId: !Ref Subnet2
  InfluxDBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: "influxdb-sg"
      GroupDescription: "Security group allowing port 8086 ingress for InfluxDB"
      VpcId: !Ref VPC
  InfluxDBSecurityGroupIngress:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !Ref InfluxDBSecurityGroup
      IpProtocol: tcp
      CidrIp: 0.0.0.0/0
      FromPort: 8086
      ToPort: 8086
  InfluxDBLogsS3Bucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
  InfluxDBLogsS3BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref InfluxDBLogsS3Bucket
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Action: "s3:PutObject"
            Effect: Allow
            Resource: !Sub arn:aws:s3:::${InfluxDBLogsS3Bucket}/InfluxLogs/*
            Principal:
              Service: timestream-influxdb.amazonaws.com
          - Action: "s3:*"
            Effect: Deny
            Resource:
              - !Sub arn:aws:s3:::${InfluxDBLogsS3Bucket}/*
              - !Sub arn:aws:s3:::${InfluxDBLogsS3Bucket}
            Principal: "*"
            Condition:
              Bool:
                aws:SecureTransport: false
  DbInstance:
    Type: AWS::Timestream::InfluxDBInstance
    DependsOn: InfluxDBLogsS3BucketPolicy
    Properties:
      DbStorageType: !Ref DbStorageType
      AllocatedStorage: !Ref AllocatedStorage
      DbInstanceType: !Ref DbInstanceType
      Name: !Ref DbInstanceName
      Username: !Ref InfluxDBUsername
      Password: !Ref InfluxDBPassword
      Organization: !Ref InfluxDBOrganization
      Bucket: !Ref InfluxDBBucket
      PubliclyAccessible: !If [IsPublic, true, false]
      DeploymentType: !Ref DeploymentType
      VpcSecurityGroupIds: 
        - !Ref InfluxDBSecurityGroup
      VpcSubnetIds: !If
        - IsMultiAZ
        -
          - !Ref Subnet1
          - !Ref Subnet2
        -
          - !Ref Subnet1
      LogDeliveryConfiguration:
        S3Configuration:
          BucketName: !Ref InfluxDBLogsS3Bucket
          Enabled: true

Outputs:
  # Network Resources
  VPC:
    Description: A reference to the VPC used to create network resources
    Value: !Ref VPC
  Subnets:
    Description: A list of the subnets created
    Value: !If
      - IsMultiAZ
      - !Join [",", [!Ref Subnet1, !Ref Subnet2]]
      - !Ref Subnet1
  Subnet1:
    Description: A reference to the subnet in the 1st Availability Zone
    Value: !Ref Subnet1
  Subnet2:
    Condition: IsMultiAZ
    Description: A reference to the subnet in the 2nd Availability Zone
    Value: !Ref Subnet2
  InfluxDBSecurityGroup:
    Description: Security group with port 8086 ingress rule
    Value: !Ref InfluxDBSecurityGroup

  # Timestream for InfluxDB Resources
  InfluxDBLogsS3Bucket:
    Description: S3 Bucket containing InfluxDB logs from the DB instance
    Value: !Ref InfluxDBLogsS3Bucket
  DbInstance:
    Description: A reference to the Timestream for InfluxDB DB instance
    Value: !Ref DbInstance
  InfluxAuthParametersSecretArn:
    Description: "The Amazon Resource Name (ARN) of the Amazon Secrets Manager secret containing the initial InfluxDB authorization parameters. The secret value is a JSON formatted key-value pair holding InfluxDB authorization values: organization, bucket, username, and password."
    Value: !GetAtt DbInstance.InfluxAuthParametersSecretArn
  Endpoint:
    Description: The endpoint URL to connect to InfluxDB
    Value: !Join ["", ["https://", !GetAtt DbInstance.Endpoint, ":8086"]]
```

# 使用 CloudFormation 部署基于 Windows 的堆栈
<a name="cfn-windows-stacks"></a>

本页面提供指向基于 Windows 的部署中常用 CloudFormation 资源技术参考文档的链接。

CloudFormation 支持通过 Infrastructure as Code (IaC) 部署和管理 MicrosoftWindows 堆栈。您可以使用 CloudFormation 自动预置基于 Windows 的 EC2 实例、Amazon RDS 上的 SQL Server，以及通过 Amazon Directory Service 部署的 Microsoft Active Directory。

Amazon 提供专为 Windows 平台设计的预配置亚马逊机器映像（AMI），可帮助您在 Amazon EC2 上快速部署应用程序。这些 AMI 包括默认的 Microsoft 设置和 Amazon 特定的自定义设置。使用 CloudFormation，您可以选择适当的 AMI，启动实例，然后使用远程桌面连接访问该实例，就如同访问任何其他 Windows Server 一样。AMI 包含必要的软件组件，包括 EC2Launch（版本因 Windows Server 版本而异）、Amazon Systems Manager、CloudFormation、Amazon Tools for PowerShell 以及各种网络、存储和图形驱动程序，以确保最佳性能并与 Amazon 服务兼容。有关更多信息，请参阅 [Amazon Windows AMI Reference](https://docs.amazonaws.cn/ec2/latest/windows-ami-reference/windows-amis.html)。

CloudFormation 还支持软件配置工具，例如 `UserData` 脚本，这些工具可以在 EC2 实例首次启动时运行 PowerShell 或批处理命令。它还提供帮助程序脚本（`cfn-init`、`cfn-signal`、`cfn-get-metadata` 和 `cfn-hup`），并支持用于管理 Windows 实例上的包、文件和服务的 `AWS::CloudFormation::Init` 元数据。

对于企业环境，CloudFormation 支持域加入、通过 EC2 许可模式管理 Windows 许可证以及使用 Amazon Secrets Manager 进行安全凭证处理。结合版本控制的模板和可重复的部署，CloudFormation 可帮助组织跨多个 Amazon Web Services 区域和账户维护一致、安全和可扩展的 Windows 环境。

有关基于 Windows 的部署中常用 CloudFormation 资源的详细信息，请参阅以下技术参考主题。


| 资源类型 | 说明 | 
| --- | --- | 
|  [AWS::EC2::Instance](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-instance.html)  |  用于启动 Windows EC2 实例。  | 
|  [AWS::EC2::SecurityGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html)  |  为 Windows 工作负载定义防火墙规则。  | 
|  [AWS::AutoScaling::AutoScalingGroup](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html) [AWS::EC2::LaunchTemplate](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html)  |  用于扩展 Windows EC2 实例。  | 
|  [AWS::DirectoryService::MicrosoftAD](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-directoryservice-microsoftad.html)  |  用于部署 Microsoft Active Directory。  | 
|  [AWS::FSx::FileSystem](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-fsx-filesystem.html)  |  用于部署 FSx for Windows File Server。  | 
|  [AWS::RDS::DBInstance](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-rds-dbinstance.html)  |  用于在 Amazon RDS 上预置 SQL Server。  | 
|  [AWS::CloudFormation::Init](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-init.html)  |  在 EC2 元数据中用于配置实例。 有关更多信息，请参阅 [引导基于 Windows 的 CloudFormation 堆栈](cfn-windows-stacks-bootstrapping.md)。  | 
|  [AWS::SecretsManager::Secret](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-secretsmanager-secret.html)  |  用于安全地管理凭证和 Windows 密码。  | 
|  [AWS::SSM::Parameter](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ssm-parameter.html)  |  用于安全地存储配置值。  | 
|  [AWS::IAM::InstanceProfile](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-instanceprofile.html) [AWS::IAM::Role](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-role.html)  |  用于向在 EC2 实例上运行的应用程序授予权限。  | 

# 引导基于 Windows 的 CloudFormation 堆栈
<a name="cfn-windows-stacks-bootstrapping"></a>

本主题将介绍如何引导 Windows 堆栈并排除堆栈创建问题。

**Topics**
+ [

## EC2 实例中的用户数据功能
](#cfn-windows-bootstrapping-user-data)
+ [

## CloudFormation 帮助程序脚本
](#cfn-windows-bootstrapping-helper-scripts)
+ [

## 启动 Windows 堆栈的示例
](#cfn-windows-bootstrapping-example)
+ [

## 转义文件路径中的 Windows 反斜杠
](#cfn-windows-stacks-escape-backslashes)
+ [

## 管理 Windows 服务
](#cfn-windows-stacks-manage-windows-services)
+ [

## 解决堆栈创建故障问题
](#cfn-windows-stacks-troubleshooting)

## EC2 实例中的用户数据功能
<a name="cfn-windows-bootstrapping-user-data"></a>

使用 Amazon EC2 的用户数据功能，可以在启动 EC2 实例时将脚本或配置信息传递至实例。

对于 Windows EC2 实例：
+ 您可以使用批处理脚本（通过 `<script>` 标签）或 PowerShell 脚本（通过 `<powershell>` 标签）。
+ 脚本执行由 EC2Launch 处理。

**重要**  
如果您要创建自己的 Windows AMI 以用于 CloudFormation，请确保正确配置 EC2Launch v2。CloudFormation 引导工具需要使用 EC2Launch v2 才能在创建堆栈期间正确初始化和配置 Windows 实例。有关更多信息，请参阅《Amazon EC2 用户指南》**中的[使用 EC2Launch v2 代理在 EC2 Windows 实例启动期间执行任务](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/ec2launch-v2.html)。  
有关 Amazon Windows AMI 的信息，请参阅《[Amazon Windows AMI Reference](https://docs.amazonaws.cn/ec2/latest/windows-ami-reference/windows-amis.html)》。

## CloudFormation 帮助程序脚本
<a name="cfn-windows-bootstrapping-helper-scripts"></a>

帮助程序脚本是一种实用工具，用于在引导过程中配置实例。它们可与 Amazon EC2 用户数据功能配合使用，提供强大的配置选项。

CloudFormation 提供以下 Python 帮助程序脚本，用于在您在堆栈中创建的 Amazon EC2 实例上安装软件和启动服务：
+  `cfn-init` – 用于检索和解释资源元数据、安装软件包、创建文件和启动服务。
+  `cfn-signal` – 用于通过 `CreationPolicy` 发送信号，因此您能够在先决条件资源或应用程序准备就绪时同步堆栈中的其他资源。
+  `cfn-get-metadata` – 用于检索资源的元数据或特定密钥的路径。
+  `cfn-hup` – 用于检查元数据更新，并在检测到更改时，执行自定义挂钩。

您可以从您的模板中直接调用脚本。该脚本可与在同一模板中定义的资源元数据共同运行。脚本可在堆栈创建过程中的 Amazon EC2 实例上运行。

有关更多信息，请参阅《Amazon CloudFormation 模板参考指南**》中的 [CloudFormation 帮助程序脚本参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/cfn-helper-scripts-reference.html)。

## 启动 Windows 堆栈的示例
<a name="cfn-windows-bootstrapping-example"></a>

让我们检查一下执行以下操作的 Windows Server 模板中的示例代码段：
+ 从 Windows Server 2022 AMI 启动名为 `TestInstance` 的 EC2 实例。
+ 创建一个简单的测试文件来验证 `cfn-init` 是否正常工作。
+ 配置 `cfn-hup` 以进行持续的配置管理。
+ 使用 `CreationPolicy` 确保实例发出成功完成的信号。

`cfn-init` 帮助程序脚本可用于根据模板中 `AWS::CloudFormation::Init` 资源的信息来执行上述各种操作。

`AWS::CloudFormation::Init` 部分名为 `TestInstance`，以以下声明开头。

```
TestInstance:
  Type: AWS::EC2::Instance
  Metadata:
    AWS::CloudFormation::Init:
      configSets:
        default:
          - create_files
          - start_services
```

在此之后，声明 `AWS::CloudFormation::Init` 的 `files` 部分。

```
      create_files:
        files:
          c:\cfn\test.txt:
            content: !Sub |
              Hello from ${AWS::StackName}
          c:\cfn\cfn-hup.conf:
            content: !Sub |
              [main]
              stack=${AWS::StackName}
              region=${AWS::Region}
              interval=2
          c:\cfn\hooks.d\cfn-auto-reloader.conf:
            content: !Sub |
              [cfn-auto-reloader-hook]
              triggers=post.update
              path=Resources.TestInstance.Metadata.AWS::CloudFormation::Init
              action=cfn-init.exe -v -s ${AWS::StackName} -r TestInstance -c default --region ${AWS::Region}
```

将在此处创建这三个文件，并将其置于服务器实例上的 `C:\cfn` 目录中：
+ `test.txt`，一个简单的测试文件，用于验证 `cfn-init` 是否正常工作以及是否可以创建包含动态内容的文件。
+ `cfn-hup.conf`，`cfn-hup` 的配置文件，检查间隔为 2 分钟。
+ `cfn-auto-reloader.conf` 为挂钩的配置文件，当 `AWS::CloudFormation::Init` 中的元数据发生变化时，`cfn-hup` 将用其初始化更新（调用 `cfn-init`）。

接下来是 `start_services` 部分，它配置 Windows 服务。

```
      start_services:
        services:
          windows:
            cfn-hup:
              enabled: true
              ensureRunning: true
              files:
                - c:\cfn\cfn-hup.conf
                - c:\cfn\hooks.d\cfn-auto-reloader.conf
```

本节确保 `cfn-hup` 服务已启动，并在配置文件经修改时自动重启。该服务会监控 CloudFormation 元数据的更改，并在检测到更新时重新运行 `cfn-init`。

下面是 `Properties` 部分。

```
TestInstance:
  Type: AWS::EC2::Instance
  CreationPolicy:
    ResourceSignal:
      Timeout: PT20M
  Metadata:
    AWS::CloudFormation::Init:
      # ... metadata configuration ...
  Properties:
    InstanceType: t2.large
    ImageId: '{{resolve:ssm:/aws/service/ami-windows-latest/Windows_Server-2022-English-Full-Base}}'
    SecurityGroupIds:
      - !Ref InstanceSecurityGroup
    KeyName: !Ref KeyPairName
    UserData:
      Fn::Base64: !Sub |
        <powershell>
        cfn-init.exe -v -s ${AWS::StackName} -r TestInstance -c default --region ${AWS::Region}
        cfn-signal.exe -e $lastexitcode --stack ${AWS::StackName} --resource TestInstance --region ${AWS::Region}
        </powershell>
```

在本部分中，`UserData` 属性包含一个 PowerShell 脚本，该脚本通过将 EC2Launch 用 `<powershell>` 标记括起得以执行。该脚本使用 `default` configSet 运行 `cfn-init`，然后使用 `cfn-signal` 将退出代码报告给 CloudFormation。`CreationPolicy` 用于确保在堆栈创建完成之前实例已正确配置。

`ImageId` 属性使用 Systems Manager Parameter Store 公共参数自动检索最新的 Windows Server 2022 AMI ID。此方法无需特定于区域的 AMI 映射，并确保您始终获取最新的 AMI。使用 Systems Manager 参数作为 AMI ID 是维护最新 AMI 引用的最佳实践。如果您计划连接到实例，请确保 `SecurityGroupIds` 属性引用允许 RDP 访问的安全组。

`CreationPolicy` 声明为资源属性的一部分，并指定超时期限。用户数据中的 `cfn-signal` 命令会在实例配置完成时发出信号：

```
TestInstance:
  Type: AWS::EC2::Instance
  CreationPolicy:
    ResourceSignal:
      Timeout: PT20M
  Properties:
    # ... other properties ...
```

由于引导过程很少，仅创建文件并启动服务，因此 `CreationPolicy` 会等待 20 分钟 (PT20M) 后才会超时。超时时间采用 ISO 8601 持续时间格式指定。请注意，Windows 实例的启动时间通常比 Linux 实例更长，因此请进行全面测试以确定最符合您需求的超时值。

如果一切顺利，`CreationPolicy` 将成功完成，您可以使用其公有 IP 地址访问 Windows Server 实例。堆栈创建完成后，实例 ID 和公有 IP 地址将显示在 CloudFormation 控制台的**输出**选项卡中。

```
Outputs:
  InstanceId:
    Value: !Ref TestInstance
    Description: Instance ID of the Windows Server
  PublicIP:
    Value: !GetAtt TestInstance.PublicIp
    Description: Public IP address of the Windows Server
```

您还可以手动验证引导是否正确运行，方法是通过 RDP 连接到实例并检查文件 `C:\cfn\test.txt` 是否存在且包含预期内容。有关连接 Windows 实例的更多信息，请参阅《Amazon EC2 用户指南》中的[使用 RDP 连接到 Windows 实例](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/connecting_to_windows_instance.html)**。

## 转义文件路径中的 Windows 反斜杠
<a name="cfn-windows-stacks-escape-backslashes"></a>

在 CloudFormation 模板中引用 Windows 路径时，请务必根据所使用的模板格式正确转义反斜杠 (`\`)。
+ 对于 JSON 模板，您必须在 Windows 文件路径中使用双反斜杠，因为 JSON 将反斜杠视为转义字符。第一个反斜杠会转义第二个反斜杠，因此会被解释为单个字面反斜杠。

  ```
  "commands" : {
    "1-extract" : {
      "command" : "C:\\SharePoint\\SharePointFoundation2010.exe /extract:C:\\SharePoint\\SPF2010 /quiet /log:C:\\SharePoint\\SharePointFoundation2010-extract.log"
    }
  }
  ```
+ 对于 YAML 模板，单反斜杠通常足够了。

  ```
  commands:
    1-extract:
      command: C:\SharePoint\SharePointFoundation2010.exe /extract:C:\SharePoint\SPF2010 /quiet /log:C:\SharePoint\SharePointFoundation2010-extract.log
  ```

## 管理 Windows 服务
<a name="cfn-windows-stacks-manage-windows-services"></a>

除了使用 `windows` 密钥而不使用 `sysvinit` 之外，管理 Windows 服务的方式与管理 Linux 服务的方式相同。以下示例将启动 `cfn-hup` 服务，将其设置为“自动”，并在 `cfn-init` 修改 `c:\cfn\cfn-hup.conf` 或 `c:\cfn\hooks.d\cfn-auto-reloader.conf` 配置文件时重启服务。

```
        services:
          windows:
            cfn-hup:
              enabled: true
              ensureRunning: true
              files:
                - c:\cfn\cfn-hup.conf
                - c:\cfn\hooks.d\cfn-auto-reloader.conf
```

您可以使用名称（而不是显示名称）来引用服务，以相同方式管理其他 Windows 服务。

## 解决堆栈创建故障问题
<a name="cfn-windows-stacks-troubleshooting"></a>

如果您的堆栈在创建过程中出现问题，默认行为将为失败时回滚。正常情况下，这属于一项良好默认，因为它免除了不必要的收费，但是它会让调试堆栈创建失败的原因变得非常困难。

要在使用 CloudFormation 控制台创建或更新堆栈时关闭此行为，请在**堆栈故障选项**下选择**保留成功预置的资源**选项。有关更多信息，请参阅 [选择预置资源时如何处理失败](stack-failure-options.md)。通过此操作，您可以登录您的实例，并查看日志文件，以精确找出运行启动脚本时出现的问题。

须查看的重要日志文件包括：
+ EC2 配置日志位于：`%ProgramData%\Amazon\EC2Launch\log\agent.log`
+ `C:\cfn\log\cfn-init.log` 处的 **cfn-init** 日志（检查退出代码和错误消息以了解具体故障点）

有关更多日志，请参阅《Amazon EC2 用户指南》**中的以下主题：
+ [EC2Launch 目录结构](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/ec2config-service.html#UsingConfigXML_WinAMI)
+ [EC2Launch v2 目录结构](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/ec2launch-v2.html#ec2launch-v2-directory)

有关排查引导问题的更多信息，请参阅[如何排查无法在具有 Windows 实例的 CloudFormation 堆栈中引导的帮助程序脚本的问题？](https://repost.aws/knowledge-center/cloudformation-helper-scripts-windows)。

# 使用 CloudFormation 提供的资源类型扩展模板的功能
<a name="cloudformation-supplied-resource-types"></a>

CloudFormation 提供了多种资源类型，您可以在堆栈模板中使用这些资源类型来扩展其功能，超越简单的堆栈模板。

这些资源类型包括：


| 资源类型 | 说明 | 文档 | 
| --- | --- | --- | 
|  自定义资源  |  您可以利用此 `AWS::CloudFormation::CustomResource` 资源类型来创建自定义资源，从而执行特定的预置任务或包含不能通过 CloudFormation 资源类型提供的资源。  |  [自定义资源](template-custom-resources.md) | 
|  宏  |  此 `AWS::CloudFormation::Macro` 资源类型定义了可以在 CloudFormation 模板上执行自定义处理的可复用代码片段。宏可以在堆栈创建或更新期间修改模板、生成其他资源或执行其他自定义操作。  | [模板宏](template-macros.md) | 
|  嵌套堆栈  |  借助此 `AWS::CloudFormation::Stack` 资源类型，您可以在 CloudFormation 模板中创建嵌套堆栈，从而提高堆栈架构的模块化和可复用性水平。  | [嵌套堆栈](using-cfn-nested-stacks.md) | 
|  堆栈集  |  此 `AWS::CloudFormation::StackSet` 资源类型会创建或更新一种 CloudFormation 堆栈集，也就是一个可以跨多个 Amazon Web Services 账户 和区域部署的堆栈容器。  | [使用 StackSets 管理堆栈](what-is-cfnstacksets.md) | 
|  等待条件  |  在满足特定条件之前（例如，长时间运行进程的成功完成或外部资源的可用性），该 `AWS::CloudFormation::WaitCondition` 资源类型会暂停堆栈的创建或更新。  | [等待条件](using-cfn-waitcondition.md) | 
|  等待条件句柄  |  该 `AWS::CloudFormation::WaitConditionHandle` 资源类型可与 `AWS::CloudFormation::WaitCondition` 资源类型配合使用，它提供了预签名 URL，用于发送表示特定条件已得到满足的信号。这些信号允许堆栈创建或更新过程继续进行下去。  | [等待条件](using-cfn-waitcondition.md) | 

# 使用自定义资源创建自定义预置逻辑
<a name="template-custom-resources"></a>

自定义资源为您提供了一种将自定义预置逻辑写入 CloudFormation 模板，并让 CloudFormation 在创建、更新（如果更改了自定义资源）或删除堆栈期间运行该逻辑的方式。预置要求涉及无法使用 CloudFormation 的内置资源类型表达的复杂逻辑或工作流程时，这会很有帮助。

例如，您可能需要包含不可作为 CloudFormation 资源类型的资源。您可以使用自定义资源包含这些资源。这样，您仍然可以在一个堆栈中管理所有相关资源。

要在 CloudFormation 模板中定义自定义资源，可以使用 `AWS::CloudFormation::CustomResource` 或 `Custom::MyCustomResourceTypeName` 资源类型。自定义资源需要一个属性，即服务令牌，它指定 CloudFormation 发送请求的目标，如 Amazon SNS 主题或 Lambda 函数。

以下主题提供有关如何使用自定义资源的信息。

**Topics**
+ [

## 自定义资源的工作原理
](#how-custom-resources-work)
+ [

## 响应超时
](#response-timeout)
+ [

# CloudFormation 自定义资源请求和响应参考
](crpg-ref.md)
+ [

# Amazon SNS 支持的自定义资源
](template-custom-resources-sns.md)
+ [

# Lambda 支持的自定义资源
](template-custom-resources-lambda.md)

**注意**  
CloudFormation 注册表和自定义资源各有其优点。自定义资源具有以下优点：  
您不需要注册资源。
您无需注册即可将整个资源作为模板的一部分。
支持 `Create`、`Update` 和 `Delete` 操作
基于注册表的资源具有以下优点：  
支持对第三方应用程序资源进行建模、预置和管理
支持 `Create`、`Read`、`Update`、`Delete` 和 `List` (`CRUDL`) 操作
支持对私有和第三方资源类型的偏差检测
与自定义资源不同，基于注册表的资源不需要关联 Amazon SNS 主题或 Lambda 函数即可执行 `CRUDL` 操作。有关更多信息，请参阅 [通过 CloudFormation 注册表管理扩展](registry.md)。

## 自定义资源的工作原理
<a name="how-custom-resources-work"></a>

设置新自定义资源的一般过程包括以下步骤。这些步骤涉及两个角色：拥有该自定义资源的*自定义资源提供者*和创建包含某个自定义资源类型的模板的*模板开发者*。这两个角色可以是同一个人，但如果不是同一个人，自定义资源提供者应该与模板开发者合作。

1. 自定义资源提供者编写的逻辑决定了如何处理来自 CloudFormation 的请求以及如何对自定义资源执行操作。

1. 自定义资源提供者可创建 Amazon SNS 主题或 Lambda 函数，然后 CloudFormation 可向该主题或函数发送请求。该 Amazon SNS 主题或 Lambda 函数必须位于堆栈所在区域。

1. 自定义资源提供者将 Amazon SNS 主题 ARN 或 Lambda 函数 ARN 提供给模板开发者。

1. 模板开发者定义其 CloudFormation 模板中的自定义资源。这包括服务令牌和任何输入数据参数。服务令牌和输入数据的结构由自定义资源提供者定义。服务令牌指定了 Amazon SNS 主题 ARN 或 Lambda 函数 ARN，并且始终为必填项，而输入数据是可选的，具体取决于自定义资源。

现在，每当有人使用模板创建、更新或删除该自定义资源时，CloudFormation 都会向指定的服务令牌发送请求并等待响应，然后才会执行堆栈操作。

以下总结了使用该模板创建堆栈的流程：

1. CloudFormation 向指定的服务令牌发送请求。该请求包含请求类型以及自定义资源用于向其发送请求的预签名 Amazon S3 存储桶 URL 等信息。有关请求中包含的内容的更多信息，请参阅[CloudFormation 自定义资源请求和响应参考](crpg-ref.md)。

   以下示例数据演示了 CloudFormation 在 `Create` 请求中包含的内容：在本示例中，`ResourceProperties` 允许 CloudFormation 创建发送到 Lambda 函数的自定义负载。

   ```
   {
      "RequestType" : "Create",
      "RequestId" : "unique id for this create request",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "ResponseURL" : "http://pre-signed-S3-url-for-response",
      "ResourceType" : "Custom::TestResource",
      "LogicalResourceId" : "MyTestResource",
      "ResourceProperties" : {
         "Name" : "Value",
         "List" : [ "1", "2", "3" ]
      }
   }
   ```

1. 自定义资源提供商处理 CloudFormation 请求并向预签名 URL 返回 `SUCCESS` 或 `FAILED` 响应。custom resource provider 提供采用 JSON 格式文件的响应并将响应上传到预签名的 S3 URL。有关更多信息，请参阅*《Amazon Simple Storage Service 用户指南》*中的[使用预签名 URL 上传对象](https://docs.amazonaws.cn/AmazonS3/latest/userguide/PresignedUrlUploadObject.html)。

   在响应中，custom resource provider还可以包含template developer可以访问的名称-值对。例如，如果请求成功，响应可以包含输出数据，如果请求失败，可以包含错误消息。有关响应的更多信息，请参阅[CloudFormation 自定义资源请求和响应参考](crpg-ref.md)。
**重要**  
如果名称值对包含敏感信息，应使用 `NoEcho` 字段遮蔽自定义资源的输出。否则，这些值通过显示属性值的 API（例如 `DescribeStackEvents`）可见。  
有关使用 `NoEcho` 遮蔽敏感信息的更多信息，请参阅 [请勿将凭证嵌入您的模板](security-best-practices.md#creds) 最佳实践。

   custom resource provider负责侦听和响应请求。例如，对于 Amazon SNS 通知，自定义资源提供商必须侦听并响应发送到特定主题 ARN 的通知。CloudFormation 在预签名 URL 位置等待并侦听响应。

   以下示例数据说明自定义资源在响应中可以包含的内容：

   ```
   {
      "Status" : "SUCCESS",
      "RequestId" : "unique id for this create request",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "LogicalResourceId" : "MyTestResource",
      "PhysicalResourceId" : "TestResource1",
      "Data" : {
         "OutputName1" : "Value1",
         "OutputName2" : "Value2",
      }
   }
   ```

1. 获得 `SUCCESS` 响应后，CloudFormation 继续堆栈操作。如果收到 `FAILED` 响应或未返回任何响应，则操作失败。来自自定义资源的所有输出数据都存储在预签名 URL 位置。模板开发人员可使用 [Fn::GetAtt](resources-section-structure.md#resource-properties-getatt) 函数检索该数据。

**注意**  
如果您使用 Amazon PrivateLink，则 VPC 中的自定义资源必须能够访问特定于 CloudFormation 的 S3 存储桶。自定义资源必须将响应发送到预签名的 Amazon S3 URL。如果这些资源不能向 Amazon S3 发送响应，则 CloudFormation 将不会收到响应，并且堆栈操作会失败。有关更多信息，请参阅 [使用接口端点 (Amazon PrivateLink) 访问 Amazon CloudFormation](vpc-interface-endpoints.md)。

## 响应超时
<a name="response-timeout"></a>

自定义资源的默认超时为 3600 秒（1 小时）。如果在此期间内没有收到任何响应，则该堆栈操作将会失败。

您可以根据预期从自定义资源收到响应将需要的时间来调整超时值。例如，在预置将调用某个 Lambda 函数的自定义资源并且预期会在五分钟内收到响应时，您可以在堆栈模板中通过指定 `ServiceTimeout` 属性将超时设置为五分钟。有关更多信息，请参阅 [CloudFormation 自定义资源请求和响应参考](crpg-ref.md)。这样，如果 Lambda 函数出现错误导致其停滞，CloudFormation 将在五分钟后使堆栈操作失败，而不是等待整整一个小时。

但是，请注意不要将超时值设置得过低。为避免意外超时，请确保您的自定义资源有足够的时间来执行必要的操作并返回响应。

# CloudFormation 自定义资源请求和响应参考
<a name="crpg-ref"></a>

Amazon CloudFormation 通过与您的自定义资源提供商通信的请求-响应协议管理自定义资源。每个请求都包含一个请求类型（`Create`、`Update` 或 `Delete`），并遵循这一高级工作流：

1. 模板开发者在模板中使用 `ServiceToken` 和 `ServiceTimeout` 定义自定义资源并启动堆栈操作。

1. CloudFormation 通过 SNS 或 Lambda 向自定义资源提供商发送 JSON 请求。

1. 该自定义资源提供商会处理请求，并在超时时间到期之前向预签名的 Amazon S3 存储桶 URL 返回一个 JSON 响应。

1. CloudFormation 会读取响应并继续堆栈操作。如果在超时期限结束之前没有收到任何响应，则该请求被视为不成功，并且堆栈操作将会失败。

有关更多信息，请参阅 [自定义资源的工作原理](template-custom-resources.md#how-custom-resources-work)。

本节介绍每种请求类型的结构、参数和预期响应。

**注意**  
响应正文的总大小不能超过 4096 字节。

## 模板设置
<a name="crpg-ref-template-setup"></a>

在模板中定义自定义资源时，模板开发者会使用具有以下属性的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-customresource.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-customresource.html)：

`ServiceToken`  
来自与堆栈相同区域的 Amazon SNS 主题 ARN 或 Lambda 函数 ARN。  
*是否必需*：是  
*类型*：字符串

`ServiceTimeout`  
自定义资源操作超时前的最长时间（以秒为单位）。此值必须介于 1 和 3600 之间。默认值：3600 秒（1 小时）。  
*必需*：否  
*类型*：字符串

支持其他资源属性。资源属性将以 `ResourceProperties` 形式包含在请求中。自定义资源提供商必须确定哪些属性有效以及它们的可接受值。

## 请求对象
<a name="crpg-ref-requesttypes"></a>

------
#### [ Create ]

当模板开发者创建包含自定义资源的堆栈时，CloudFormation 会发送一条将 `RequestType` 设置为 `Create` 的请求。

创建请求包含以下字段：

`RequestType`  
`Create`.  
*是否必需*：是  
*类型*：字符串

`RequestId`  
请求的唯一 ID。  
将 `StackId` 与 `RequestId` 组合形成一个值，您可以使用该值唯一标识对特定自定义资源的请求。  
*是否必需*：是  
*类型*：字符串

`StackId`  
标识包含自定义资源的堆栈的 Amazon 资源名称（ARN）。  
将 `StackId` 与 `RequestId` 组合形成一个值，您可以使用该值唯一标识对特定自定义资源的请求。  
*是否必需*：是  
*类型*：字符串

`ResponseURL`  
响应 URL 标识一个预签名 S3 存储桶，该存储桶接收从自定义资源提供商到 CloudFormation 的响应。  
*是否必需*：是  
*类型*：字符串

`ResourceType`  
CloudFormation 模板中模板开发人员选择的自定义资源的资源类型。自定义资源类型名称的长度最多为 60 个字符，并且可包含字母数字字符和以下字符：`_@-`。  
*是否必需*：是  
*类型*：字符串

`LogicalResourceId`  
CloudFormation 模板中模板开发人员选择的自定义资源的名称（逻辑 ID）。  
*是否必需*：是  
*类型*：字符串

`ResourceProperties`  
此字段包含模板开发人员发送的 `Properties` 对象的内容。其内容由自定义资源提供商定义。  
*必需*：否  
*类型*：JSON 对象

*示例*

```
{
   "RequestType" : "Create",
   "RequestId" : "unique-request-id",
   "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/id",
   "ResponseURL" : "pre-signed-url-for-create-response",
   "ResourceType" : "Custom::MyCustomResourceType",
   "LogicalResourceId" : "resource-logical-id",
   "ResourceProperties" : {
      "key1" : "string",
      "key2" : [ "list" ],
      "key3" : { "key4" : "map" }
   }
}
```

------
#### [ Update ]

当模板开发者更改模板中某个自定义资源的属性并更新堆栈时，CloudFormation 会向自定义资源提供者发送一条将 `RequestType` 设置为 `Update` 的请求。这意味着自定义资源代码无需检测资源中的更改，因为在请求类型为 `Update` 时，代码会知道其属性已经更改。

更新请求包含以下字段：

`RequestType`  
`Update`.  
*是否必需*：是  
*类型*：字符串

`RequestId`  
请求的唯一 ID。  
将 `StackId` 与 `RequestId` 组合形成一个值，您可以使用该值唯一标识对特定自定义资源的请求。  
*是否必需*：是  
*类型*：字符串

`StackId`  
标识包含自定义资源的堆栈的 Amazon 资源名称（ARN）。  
将 `StackId` 与 `RequestId` 组合形成一个值，您可以使用该值唯一标识对特定自定义资源的请求。  
*是否必需*：是  
*类型*：字符串

`ResponseURL`  
响应 URL 标识一个预签名 S3 存储桶，该存储桶接收从自定义资源提供商到 CloudFormation 的响应。  
*是否必需*：是  
*类型*：字符串

`ResourceType`  
CloudFormation 模板中模板开发人员选择的自定义资源的资源类型。自定义资源类型名称的长度最多为 60 个字符，并且可包含字母数字字符和以下字符：`_@-`。更新期间不能更改类型。  
*是否必需*：是  
*类型*：字符串

`LogicalResourceId`  
CloudFormation 模板中模板开发人员选择的自定义资源的名称（逻辑 ID）。  
*是否必需*：是  
*类型*：字符串

`PhysicalResourceId`  
自定义资源提供商定义的物理 ID，该 ID 对于该提供程序是唯一的。  
*是否必需*：是  
*类型*：字符串

`ResourceProperties`  
此字段包含模板开发人员发送的 `Properties` 对象的内容。其内容由自定义资源提供商定义。  
*必需*：否  
*类型*：JSON 对象

`OldResourceProperties`  
仅用于 `Update` 请求。模板开发人员之前在 CloudFormation 模板中声明的资源属性值。  
*是否必需*：是  
*类型*：JSON 对象

*示例*

```
{
   "RequestType" : "Update",
   "RequestId" : "unique-request-id",
   "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/id",
   "ResponseURL" : "pre-signed-url-for-update-response",
   "ResourceType" : "Custom::MyCustomResourceType",
   "LogicalResourceId" : "resource-logical-id",
   "PhysicalResourceId" : "provider-defined-physical-id",
   "ResourceProperties" : {
      "key1" : "new-string",
      "key2" : [ "new-list" ],
      "key3" : { "key4" : "new-map" }
   },
   "OldResourceProperties" : {
      "key1" : "string",
      "key2" : [ "list" ],
      "key3" : { "key4" : "map" }
   }
}
```

------
#### [ Delete ]

当模板开发者删除该堆栈或从模板中移除该自定义资源然后更新堆栈时，CloudFormation 会发送一条将 `RequestType` 设置为 `Delete` 的请求。

删除请求包含以下字段：

`RequestType`  
`Delete`.  
*是否必需*：是  
*类型*：字符串

`RequestId`  
请求的唯一 ID。  
*是否必需*：是  
*类型*：字符串

`StackId`  
标识包含自定义资源的堆栈的 Amazon 资源名称（ARN）。  
*是否必需*：是  
*类型*：字符串

`ResponseURL`  
响应 URL 标识一个预签名 S3 存储桶，该存储桶接收从自定义资源提供商到 CloudFormation 的响应。  
*是否必需*：是  
*类型*：字符串

`ResourceType`  
CloudFormation 模板中模板开发人员选择的自定义资源的资源类型。自定义资源类型名称的长度最多为 60 个字符，并且可包含字母数字字符和以下字符：`_@-`。  
*是否必需*：是  
*类型*：字符串

`LogicalResourceId`  
CloudFormation 模板中模板开发人员选择的自定义资源的名称（逻辑 ID）。  
*是否必需*：是  
*类型*：字符串

`PhysicalResourceId`  
自定义资源提供商定义的物理 ID，该 ID 对于该提供程序是唯一的。  
*是否必需*：是  
*类型*：字符串

`ResourceProperties`  
此字段包含模板开发人员发送的 `Properties` 对象的内容。其内容由自定义资源提供商定义。  
*必需*：否  
*类型*：JSON 对象

*示例*

```
{
   "RequestType" : "Delete",
   "RequestId" : "unique-request-id",
   "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/id",
   "ResponseURL" : "pre-signed-url-for-delete-response",
   "ResourceType" : "Custom::MyCustomResourceType",
   "LogicalResourceId" : "resource-logical-id",
   "PhysicalResourceId" : "provider-defined-physical-id",
   "ResourceProperties" : {
      "key1" : "string",
      "key2" : [ "list" ],
      "key3" : { "key4" : "map" }
   }
}
```

------

## 响应对象
<a name="crpg-ref-responses"></a>

对于所有的请求类型，自定义资源提供商会向预签名 URL 发送一条响应。如果自定义资源提供商没有发送响应，CloudFormation 会等待直到操作超时。

该响应必须为具有以下字段的 JSON 对象：

`Status`  
必须是 `SUCCESS` 或 `FAILED`。  
*是否必需*：是  
*类型*：字符串

`RequestId`  
请求的唯一 ID。完全按照请求中显示的值复制该值。  
*是否必需*：是  
*类型*：字符串

`StackId`  
标识包含自定义资源的堆栈的 Amazon 资源名称（ARN）。完全按照请求中显示的值复制该值。  
*是否必需*：是  
*类型*：字符串

`LogicalResourceId`  
CloudFormation 模板中模板开发人员选择的自定义资源的名称（逻辑 ID）。完全按照请求中显示的值复制该值。  
*是否必需*：是  
*类型*：字符串

`PhysicalResourceId`  
该值应该为自定义资源供应商的唯一标识符，并且最大为 1KB。该值必须为非空字符串，并且对于同一资源的所有响应都必须相同。  
更新自定义资源时，`PhysicalResourceId` 返回的值决定了更新行为。如果值保持相同，则 CloudFormation 将其视为正常更新。如果值发生更改，CloudFormation 会将该更新解读为替换，并向旧资源发送删除请求。有关更多信息，请参阅 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-customresource.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-customresource.html)。  
*是否必需*：是  
*类型*：字符串

`Reason`  
描述失败响应的原因。  
如果 `Status` 为 `FAILED`，则必需。否则，它是可选的。  
*必需*：条件  
*类型*：字符串

`NoEcho`  
指示在使用 `Fn::GetAtt` 函数检索时是否遮蔽自定义资源的输出。如果设置为 `true`，则*除模板 `Metadata` 区段中存储的值*外，所有返回值都将用星号 (\$1\$1\$1\$1\$1) 遮蔽。CloudFormation 不会转换、修改或编辑您在 `Metadata` 部分中包含的任何信息。默认值为 `false`。  
有关使用 `NoEcho` 遮蔽敏感信息的更多信息，请参阅 [请勿将凭证嵌入您的模板](security-best-practices.md#creds) 最佳实践。  
仅适用于 `Create` 和 `Update` 响应。不支持 `Delete` 响应。  
*必需*：否  
*类型*：布尔值

`Data`  
自定义资源提供商定义的名称值对，随响应一起发送。您可以使用 `Fn::GetAtt` 在模板中按名称访问此处提供的值。  
仅适用于 `Create` 和 `Update` 响应。不支持 `Delete` 响应。  
如果名称值对包含敏感信息，应使用 `NoEcho` 字段遮蔽自定义资源的输出。否则，这些值通过显示属性值的 API（例如 `DescribeStackEvents`）可见。
*必需*：否  
*类型*：JSON 对象

### 成功响应示例
<a name="crpg-ref-success-response-examples"></a>

#### `Create` 和 `Update` 响应
<a name="crpg-ref-success-response-example-1"></a>

```
{
   "Status": "SUCCESS",
   "RequestId": "unique-request-id",
   "StackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/name/id",
   "LogicalResourceId": "resource-logical-id", 
   "PhysicalResourceId": "provider-defined-physical-id",
   "NoEcho": true,
   "Data": {
      "key1": "value1",
      "key2": "value2"
   }
}
```

#### `Delete` 响应
<a name="crpg-ref-success-response-example-2"></a>

```
{
   "Status": "SUCCESS",
   "RequestId": "unique-request-id",
   "StackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/name/id",
   "LogicalResourceId": "resource-logical-id", 
   "PhysicalResourceId": "provider-defined-physical-id"
}
```

### 失败的响应示例
<a name="crpg-ref-failed-response-example"></a>

```
{
   "Status": "FAILED",
   "RequestId": "unique-request-id",
   "StackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/name/id",
   "LogicalResourceId": "resource-logical-id",
   "PhysicalResourceId": "provider-defined-physical-id",
   "Reason": "Required failure reason string"
}
```

# Amazon SNS 支持的自定义资源
<a name="template-custom-resources-sns"></a>

以下主题展示了如何使用服务令牌配置自定义资源，该令牌指定了 CloudFormation 向其发送请求的 Amazon SNS 主题。您还将了解自定义资源堆栈创建、更新和删除过程中发送和接收的事件和消息的顺序。

通过自定义资源和 Amazon SNS，您可以启用方案，例如向堆栈添加新资源和向堆栈注入动态数据。例如，创建堆栈时，CloudFormation 可以向被 Amazon EC2 实例上运行的应用程序监控的主题发送 `Create` 请求。Amazon SNS 通知触发应用程序以执行其他预置任务，如检索列在白名单中的弹性 IP 池。完成后，应用程序发送响应（和任何输出数据），通知 CloudFormation 继续执行堆栈操作。

将 Amazon SNS 主题指定为自定义资源的目标时，CloudFormation 会在涉及自定义资源的堆栈操作期间，向指定的 SNS 主题发送消息。要处理这些消息并执行必要的操作，必须有一个订阅 SNS 主题的受支持端点。

有关自定义资源及其工作原理的介绍，请参阅[自定义资源的工作原理](template-custom-resources.md#how-custom-resources-work)。有关 Amazon SNS 及其工作原理的信息，请参阅 [Amazon Simple Notification Service Developer Guide](https://docs.amazonaws.cn/sns/latest/dg/)。

## 使用 Amazon SNS 创建自定义资源
<a name="walkthrough-custom-resources-sns-adding-nonaws-resource"></a>

**Topics**
+ [

### 步骤 1：堆栈创建
](#crpg-walkthrough-stack-creation)
+ [

### 步骤 2：堆栈更新
](#crpg-walkthrough-stack-updates)
+ [

### 步骤 3：堆栈删除
](#crpg-walkthrough-stack-deletion)

### 步骤 1：堆栈创建
<a name="crpg-walkthrough-stack-creation"></a>

1. <a name="crpg-walkthrough-stack-creation-customer-template"></a>模板开发人员创建包含自定义资源的 CloudFormation 堆栈。

   在以下模板示例中，对具有逻辑 ID `Custom::SeleniumTester` 的自定义资源使用自定义资源类型名称 `MySeleniumTest`。自定义资源类型名称必须是字母数字字符，最大长度为 60 个字符。

   自定义资源类型是使用服务令牌、可选提供商特定属性以及由自定义资源提供商定义的可选 [Fn::GetAtt](resources-section-structure.md#resource-properties-getatt) 属性声明的。使用这些属性和特性可以将信息从template developer传递给custom resource provider，反之亦然。服务令牌指定资源提供商已配置的 Amazon SNS 主题。

   ```
   {
      "AWSTemplateFormatVersion" : "2010-09-09",
      "Resources" : {
         "MySeleniumTest" : {
            "Type": "Custom::SeleniumTester",
            "Version" : "1.0",
            "Properties" : {
               "ServiceToken": "arn:aws:sns:us-west-2:123456789012:CRTest",
               "seleniumTester" : "SeleniumTest()",
               "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com" ],
               "frequencyOfTestsPerHour" : [ "3", "2", "4" ]
            }
         }
      },
      "Outputs" : {
         "topItem" : {
            "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "resultsPage"] }
         },
         "numRespondents" : {
            "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "lastUpdate"] }
         }
      }
   }
   ```
**注意**  
在提供商响应 CloudFormation 期间，自定义资源提供商会返回使用 `Fn::GetAtt` 访问的数据的名称和值。如果custom resource provider是第三方，则template developer必须从custom resource provider获取这些返回值的名称。

1. <a name="crpg-walkthrough-stack-creation-provider-request"></a>CloudFormation 使用 `"RequestType" : "Create"` 向资源提供者发送一条 Amazon SNS 通知，其中包含有关堆栈的信息、堆栈模板中的自定义资源属性和用于响应的 S3 URL。

   用于发送通知的 SNS 主题嵌入在模板的 `ServiceToken` 属性中。要避免使用硬编码值，模板开发人员可以使用模板参数，以便在启动堆栈时输入值。

   以下示例显示一个自定义资源 `Create` 请求，其中包含一个用 `Custom::SeleniumTester` 的 `LogicalResourceId` 创建的自定义资源类型名称 `MySeleniumTester`：

   ```
   {
      "RequestType" : "Create",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "ResponseURL" : "http://pre-signed-S3-url-for-response",
      "ResourceType" : "Custom::SeleniumTester",
      "LogicalResourceId" : "MySeleniumTester",
      "ResourceProperties" : {
         "seleniumTester" : "SeleniumTest()",
         "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com" ],
         "frequencyOfTestsPerHour" : [ "3", "2", "4" ]
      }
   }
   ```

   有关 `Create` 请求的请求对象的详细信息，请参阅 [请求和响应参考](crpg-ref.md) 主题。

1. <a name="crpg-walkthrough-stack-creation-provider-response"></a>custom resource provider处理template developer发送的数据，并确定 `Create` 请求是否已成功。然后，资源提供者使用 CloudFormation 发送的 S3 URL 来发送 `SUCCESS` 或 `FAILED` 响应。

   根据响应类型，CloudFormation 将需要不同的响应字段。有关特定请求类型的响应字段的信息，请参阅 [请求和响应参考](crpg-ref.md) 部分中该请求类型的文档。

   在响应创建或更新请求时，custom resource provider 可以在响应的 `Data` 字段中返回数据元素。这些是名称/值对，*名称*对应于用于堆栈模板中的自定义资源的 `Fn::GetAtt` 属性。该*值*是模板开发人员对具有此属性名称的资源调用 `Fn::GetAtt` 时返回的数据。

   以下是自定义资源响应的示例：

   ```
   {
      "Status" : "SUCCESS",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester1",
      "Data" : {
         "resultsPage" : "http://www.myexampledomain/test-results/guid",
         "lastUpdate" : "2012-11-14T03:30Z"
      }
   }
   ```

   有关 `Create` 请求的响应对象的详细信息，请参阅 [请求和响应参考](crpg-ref.md) 主题。

   `StackId`、`RequestId` 和 `LogicalResourceId` 字段必须从请求中逐字复制。

1. <a name="crpg-walkthrough-stack-creation-stack-status"></a> CloudFormation 将堆栈状态声明为 `CREATE_COMPLETE` 或 `CREATE_FAILED`。如果堆栈已成功创建，模板开发人员通过 [Fn::GetAtt](resources-section-structure.md#resource-properties-getatt) 访问已创建的自定义资源的输出值，可以使用这些值。

   例如，用于举例说明的自定义资源模板使用 `Fn::GetAtt` 将资源输出复制到堆栈输出：

   ```
   "Outputs" : {
      "topItem" : {
         "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "resultsPage"] }
      },
      "numRespondents" : {
         "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "lastUpdate"] }
      }
   }
   ```

### 步骤 2：堆栈更新
<a name="crpg-walkthrough-stack-updates"></a>

要更新现有堆栈，您必须提交一个指定了堆栈资源属性更新的模板，如下面的示例所示。CloudFormation 只更新模板中指定了更改的资源。有关更多信息，请参阅 [理解堆栈资源的更新行为](using-cfn-updating-stacks-update-behaviors.md)。

您可以更新需要替换基础物理资源的自定义资源。在 CloudFormation 模板中更新某个自定义资源时，CloudFormation 会向该自定义资源发送更新请求。如果需要替换自定义资源，新的自定义资源必须使用新的物理 ID 发送响应。CloudFormation 收到响应时，会比较新旧自定义资源的 `PhysicalResourceId`。如果不同，CloudFormation 会将更新视为替换，并向旧资源发送删除请求，如 [步骤 3：堆栈删除](#crpg-walkthrough-stack-deletion) 中所示。

**注意**  
如果您没有对自定义资源进行更改，CloudFormation 在堆栈更新过程中不会向资源发送请求。

1. <a name="crpg-walkthrough-stack-updates-customer-template"></a>template developer启动对包含自定义资源的堆栈的更新。在更新期间，template developer可以在堆栈模板中指定新属性。

   下面是一个使用自定义资源类型的堆栈模板 `Update` 示例：

   ```
   {
      "AWSTemplateFormatVersion" : "2010-09-09",
      "Resources" : {
         "MySeleniumTest" : {
            "Type": "Custom::SeleniumTester",
            "Version" : "1.0",
            "Properties" : {
               "ServiceToken": "arn:aws:sns:us-west-2:123456789012:CRTest",
               "seleniumTester" : "SeleniumTest()",
               "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com",
                  "http://mynewsite.com" ],
               "frequencyOfTestsPerHour" : [ "3", "2", "4", "3" ]
            }
         }
      },
      "Outputs" : {
         "topItem" : {
            "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "resultsPage"] }
         },
         "numRespondents" : {
            "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "lastUpdate"] }
         }
      }
   }
   ```

1. <a name="crpg-walkthrough-stack-updates-provider-request"></a>CloudFormation 会使用 `"RequestType" : "Update"` 向资源提供者发送一条 Amazon SNS 通知，其中包含与 `Create` 调用类似的信息，不同的是，`OldResourceProperties` 字段包含旧的资源属性，而 ResourceProperties 包含已更新的（如果有）资源属性。

   以下是一个 `Update` 请求的示例：

   ```
   {
      "RequestType" : "Update",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "ResponseURL" : "http://pre-signed-S3-url-for-response",
      "ResourceType" : "Custom::SeleniumTester",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester1",
      "ResourceProperties" : {
         "seleniumTester" : "SeleniumTest()",
         "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com",
            "http://mynewsite.com" ],
         "frequencyOfTestsPerHour" : [ "3", "2", "4", "3" ]
      },
      "OldResourceProperties" : {
         "seleniumTester" : "SeleniumTest()",
         "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com" ],
         "frequencyOfTestsPerHour" : [ "3", "2", "4" ]
      }
   }
   ```

   有关 `Update` 请求的请求对象的详细信息，请参阅 [请求和响应参考](crpg-ref.md) 主题。

1. <a name="crpg-walkthrough-stack-updates-provider-response"></a>自定义资源提供商处理由 CloudFormation 发送的数据。自定义资源执行更新并向 S3 URL 发送 `SUCCESS` 或 `FAILED` 响应。然后，CloudFormation 比较新旧自定义资源的 `PhysicalResourceIDs`。如果不同，CloudFormation 将认为更新需要替换，并向旧资源发送删除请求。下面的示例说明custom resource provider对 `Update` 请求的响应。

   ```
   {
      "Status" : "SUCCESS",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester2"
   }
   ```

   有关 `Update` 请求的响应对象的详细信息，请参阅 [请求和响应参考](crpg-ref.md) 主题。

   `StackId`、`RequestId` 和 `LogicalResourceId` 字段必须从请求中逐字复制。

1. <a name="crpg-walkthrough-stack-updates-stack-status"></a>CloudFormation 将堆栈状态声明为 `UPDATE_COMPLETE` 或 `UPDATE_FAILED`。如果更新失败，堆栈将回滚。如果堆栈更新成功，template developer可以使用 `Fn::GetAtt` 访问已创建自定义资源的任何新输出值。

### 步骤 3：堆栈删除
<a name="crpg-walkthrough-stack-deletion"></a>

1. <a name="crpg-walkthrough-stack-deletion-customer-template"></a>模板开发人员删除包含自定义资源的堆栈。CloudFormation 将获取堆栈模板中指定的当前属性及 SNS 主题，并准备向自定义资源提供商发出请求。

1. <a name="crpg-walkthrough-stack-deletion-provider-request"></a>CloudFormation 使用 `"RequestType" : "Delete"` 向资源提供者发送一条 Amazon SNS 通知，其中包含有关堆栈的当前信息、堆栈模板中的自定义资源属性和用于响应的 S3 URL。

   只要您删除堆栈或进行自定义资源的删除或替换更新，CloudFormation 都会比较新旧自定义资源的 `PhysicalResourceId`。如果不同，CloudFormation 会将更新视为替换，并向旧资源 (`OldPhysicalResource`) 发送删除请求，如下面的 `Delete` 请求示例所示。

   ```
   {
      "RequestType" : "Delete",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "ResponseURL" : "http://pre-signed-S3-url-for-response",
      "ResourceType" : "Custom::SeleniumTester",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester1",
      "ResourceProperties" : {
         "seleniumTester" : "SeleniumTest()",
         "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com",
            "http://mynewsite.com" ],
         "frequencyOfTestsPerHour" : [ "3", "2", "4", "3" ]
      }
   }
   ```

   有关 `Delete` 请求的请求对象的详细信息，请参阅 [请求和响应参考](crpg-ref.md) 主题。

   `DescribeStackResource`、`DescribeStackResources` 和 `ListStackResources` 显示用户定义的名称 (如果已指定)。

1. <a name="crpg-walkthrough-stack-deletion-provider-response"></a>自定义资源提供商处理 CloudFormation 发送的数据，并确定 `Delete` 请求是否已成功。然后，资源提供者使用 CloudFormation 发送的 S3 URL 来发送 `SUCCESS` 或 `FAILED` 响应。要成功删除带自定义资源的堆栈，custom resource provider 必须成功响应删除请求。

   以下是custom resource provider响应 `Delete` 请求的示例：

   ```
   {
      "Status" : "SUCCESS",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester1"
   }
   ```

   有关 `Delete` 请求的响应对象的详细信息，请参阅 [请求和响应参考](crpg-ref.md) 主题。

   `StackId`、`RequestId` 和 `LogicalResourceId` 字段必须从请求中逐字复制。

1. <a name="crpg-walkthrough-stack-updates-stack-status-delete"></a>CloudFormation 将堆栈状态声明为 `DELETE_COMPLETE` 或 `DELETE_FAILED`。

# Lambda 支持的自定义资源
<a name="template-custom-resources-lambda"></a>

如果将 Lambda 函数与自定义资源关联，则在创建、更新或删除自定义资源时就会调用该函数。CloudFormation 将调用 Lambda API 来调用此函数，并将所有请求数据（如请求类型和资源属性）传递给此函数。通过将 Lambda 函数的强大功能和可自定义性与 CloudFormation 结合，您可以支持各种方案，例如在堆栈创建期间动态查找 AMI ID，或者实现和使用实用工具函数（例如，字符串反转函数）。

有关自定义资源及其工作原理的介绍，请参阅[自定义资源的工作原理](template-custom-resources.md#how-custom-resources-work)。

**Topics**
+ [

# 演练：使用 Lambda 支持的自定义资源创建延迟机制
](walkthrough-lambda-backed-custom-resources.md)
+ [

# `cfn-response` 模块
](cfn-lambda-function-code-cfnresponsemodule.md)

# 演练：使用 Lambda 支持的自定义资源创建延迟机制
<a name="walkthrough-lambda-backed-custom-resources"></a>

本演练向您展示如何使用示例 CloudFormation 模板配置和启动 Lambda 支持的自定义资源。此模板创建了一种延迟机制，可在指定时间暂停堆栈部署。当您需要在资源预置期间引入故意的延迟时（例如在创建依赖资源之前等待资源稳定时），这可能非常有用。

**注意**  
虽然之前建议使用 Lambda 支持的自定义资源来检索 AMI ID，但现在建议使用 Amazon Systems Manager 参数。此方法可以使您的模板提高可重用性和更易于维护。有关更多信息，请参阅 [获取 Systems Manager Parameter Store 中的纯文本值](dynamic-references-ssm.md)。

**Topics**
+ [

## 概述
](#walkthrough-lambda-backed-custom-resources-overview)
+ [

## 示例模板
](#walkthrough-lambda-backed-custom-resources-sample-template)
+ [

## 示例模板演练
](#walkthrough-lambda-backed-custom-resources-sample-template-walkthrough)
+ [

## 先决条件
](#walkthrough-lambda-backed-custom-resources-prerequisites)
+ [

## 启动堆栈
](#walkthrough-lambda-backed-custom-resources-createfunction-createstack)
+ [

## 清理资源
](#walkthrough-lambda-backed-custom-resources-createfunction-cleanup)
+ [

## 相关信息
](#w2aac11c45b9c24b9c23)

## 概述
<a name="walkthrough-lambda-backed-custom-resources-overview"></a>

此演练中使用的示例堆栈模板创建了 Lambda 支持的自定义资源。此自定义资源在堆栈创建过程中引入了可配置的延迟（默认为 60 秒）。只有在修改自定义资源的属性时，才会在堆栈更新期间出现延迟。

此模板预置以下资源：
+ 自定义资源，
+ Lambda 函数，和
+ 使 Lambda 能够将日志写入到 CloudWatch 的 IAM 角色。

它还定义了两个输出：
+ 函数等待的实际时间。
+ 每次执行 Lambda 函数期间生成的唯一标识符。



**注意**  
CloudFormation 是一项免费服务，但 Lambda 会根据您的函数请求数量和代码执行时间收费。有关 Lambda 定价的更多信息，请参阅 [Amazon Lambda 定价](https://www.amazonaws.cn/lambda/pricing/)。

## 示例模板
<a name="walkthrough-lambda-backed-custom-resources-sample-template"></a>

您可以查看具有以下延迟机制的 Lambda 支持的自定义资源示例模板：

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-json"></a>

```
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": {
    "LambdaExecutionRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [{
            "Effect": "Allow",
            "Principal": { "Service": ["lambda.amazonaws.com"] },
            "Action": ["sts:AssumeRole"]
          }]
        },
        "Path": "/",
        "Policies": [{
          "PolicyName": "AllowLogs",
          "PolicyDocument": {
            "Statement": [{
              "Effect": "Allow",
              "Action": ["logs:*"],
              "Resource": "*"
            }]
          }
        }]
      }
    },
    "CFNWaiter": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Handler": "index.handler",
        "Runtime": "python3.9",
        "Timeout": 900,
        "Role": { "Fn::GetAtt": ["LambdaExecutionRole", "Arn"] },
        "Code": {
          "ZipFile": { "Fn::Join": ["\n", [
            "from time import sleep",
            "import json",
            "import cfnresponse",
            "import uuid",
            "",
            "def handler(event, context):",
            "  wait_seconds = 0",
            "  id = str(uuid.uuid1())",
            "  if event[\"RequestType\"] in [\"Create\", \"Update\"]:",
            "    wait_seconds = int(event[\"ResourceProperties\"].get(\"ServiceTimeout\", 0))",
            "    sleep(wait_seconds)",
            "  response = {",
            "    \"TimeWaited\": wait_seconds,",
            "    \"Id\": id ",
            "  }",
            "  cfnresponse.send(event, context, cfnresponse.SUCCESS, response, \"Waiter-\"+id)"
          ]]}
        }
      }
    },
    "CFNWaiterCustomResource": {
      "Type": "AWS::CloudFormation::CustomResource",
      "Properties": {
        "ServiceToken": { "Fn::GetAtt": ["CFNWaiter", "Arn"] },
        "ServiceTimeout": 60
      }
    }
  },
  "Outputs": {
    "TimeWaited": {
      "Value": { "Fn::GetAtt": ["CFNWaiterCustomResource", "TimeWaited"] },
      "Export": { "Name": "TimeWaited" }
    },
    "WaiterId": {
      "Value": { "Fn::GetAtt": ["CFNWaiterCustomResource", "Id"] },
      "Export": { "Name": "WaiterId" }
    }
  }
}
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-yaml"></a>

```
AWSTemplateFormatVersion: "2010-09-09"
Resources:
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      Policies:
        - PolicyName: "AllowLogs"
          PolicyDocument:
            Statement:
              - Effect: "Allow"
                Action:
                  - "logs:*"
                Resource: "*"
  CFNWaiter:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Runtime: python3.9 
      Timeout: 900
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile:
          !Sub |
          from time import sleep
          import json
          import cfnresponse
          import uuid
​
          def handler(event, context):
            wait_seconds = 0
            id = str(uuid.uuid1())
            if event["RequestType"] in ["Create", "Update"]:
              wait_seconds = int(event["ResourceProperties"].get("ServiceTimeout", 0))
              sleep(wait_seconds)
            response = {
              "TimeWaited": wait_seconds,
              "Id": id 
            }
            cfnresponse.send(event, context, cfnresponse.SUCCESS, response, "Waiter-"+id)
  CFNWaiterCustomResource:
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt CFNWaiter.Arn
      ServiceTimeout: 60
Outputs:
  TimeWaited:
    Value: !GetAtt CFNWaiterCustomResource.TimeWaited
    Export:
      Name: TimeWaited
  WaiterId:
    Value: !GetAtt CFNWaiterCustomResource.Id
    Export:
      Name: WaiterId
```

## 示例模板演练
<a name="walkthrough-lambda-backed-custom-resources-sample-template-walkthrough"></a>

以下代码段解释了示例模板的相关部分，以帮助您了解 Lambda 函数如何与自定义资源关联并理解输出。

[AWS::Lambda::Function](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html) 资源 `CFNWaiter`  
`AWS::Lambda::Function` 资源指定了函数的源代码、处理程序名称、运行时环境和执行角色的 Amazon 资源名称（ARN）。  
由于 `Handler` 属性使用 Python 源代码，因此将其设置为 `index.handler`。有关使用内联函数源代码时可接受的处理程序标识符的更多信息，请参阅 [ AWS::Lambda::Function 代码](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-zipfile)。  
由于源文件是 Python 代码，因此 `Runtime` 指定为 `python3.9`。  
`Timeout` 设置为 900 秒。  
`Role` 属性使用 `Fn::GetAtt` 函数来获取在模板中的 `AWS::IAM::Role` 资源中声明的 `LambdaExecutionRole` 执行角色的 ARN。  
`Code` 属性使用 Python 函数以内联方式定义函数代码。示例模板中的 Python 函数执行下面的操作：  
+ 使用 UUID 创建唯一 ID
+ 检查请求是创建请求还是更新请求
+ 在 `Create` 或 `Update` 请求期间休眠 `ServiceTimeout` 指定的持续时间
+ 返回等待时间和唯一 ID

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-lambda-resource-json"></a>

```
...
    "CFNWaiter": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Handler": "index.handler",
        "Runtime": "python3.9",
        "Timeout": 900,
        "Role": { "Fn::GetAtt": ["LambdaExecutionRole", "Arn"] },
        "Code": {
          "ZipFile": { "Fn::Join": ["\n", [
            "from time import sleep",
            "import json",
            "import cfnresponse",
            "import uuid",
            "",
            "def handler(event, context):",
            "  wait_seconds = 0",
            "  id = str(uuid.uuid1())",
            "  if event[\"RequestType\"] in [\"Create\", \"Update\"]:",
            "    wait_seconds = int(event[\"ResourceProperties\"].get(\"ServiceTimeout\", 0))",
            "    sleep(wait_seconds)",
            "  response = {",
            "    \"TimeWaited\": wait_seconds,",
            "    \"Id\": id ",
            "  }",
            "  cfnresponse.send(event, context, cfnresponse.SUCCESS, response, \"Waiter-\"+id)"
          ]]}
        }
      }
    },
...
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-lambda-resource-yaml"></a>

```
...
  CFNWaiter:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Runtime: python3.9 
      Timeout: 900
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile:
          !Sub |
          from time import sleep
          import json
          import cfnresponse
          import uuid
​
          def handler(event, context):
            wait_seconds = 0
            id = str(uuid.uuid1())
            if event["RequestType"] in ["Create", "Update"]:
              wait_seconds = int(event["ResourceProperties"].get("ServiceTimeout", 0))
              sleep(wait_seconds)
            response = {
              "TimeWaited": wait_seconds,
              "Id": id 
            }
            cfnresponse.send(event, context, cfnresponse.SUCCESS, response, "Waiter-"+id)
...
```

[AWS::IAM::Role](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-role.html) 资源 `LambdaExecutionRole`  
`AWS::IAM:Role` 资源为 Lambda 函数创建一个执行角色，其中包括允许 Lambda 使用该角色的代入角色策略。它还包含允许 CloudWatch Logs 访问的策略。

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-iam-role-json"></a>

```
...
    "LambdaExecutionRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [{
            "Effect": "Allow",
            "Principal": { "Service": ["lambda.amazonaws.com"] },
            "Action": ["sts:AssumeRole"]
          }]
        },
        "Path": "/",
        "Policies": [{
          "PolicyName": "AllowLogs",
          "PolicyDocument": {
            "Statement": [{
              "Effect": "Allow",
              "Action": ["logs:*"],
              "Resource": "*"
            }]
          }
        }]
      }
    },
...
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-iam-role-yaml"></a>

```
...
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      Policies:
        - PolicyName: "AllowLogs"
          PolicyDocument:
            Statement:
              - Effect: "Allow"
                Action:
                  - "logs:*"
                Resource: "*"
...
```

[AWS::CloudFormation::CustomResource](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-customresource.html) 资源 `CFNWaiterCustomResource`  
自定义资源使用 `!GetAtt CFNWaiter.Arn` 将其 ARN 链接到 Lambda 函数。它将为创建和更新操作实现 60 秒的等待时间，如 `ServiceTimeout` 中设置的那样。只有当属性被修改时，才会调用资源进行更新操作。

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-custom-resource-json"></a>

```
...
    "CFNWaiterCustomResource": {
      "Type": "AWS::CloudFormation::CustomResource",
      "Properties": {
        "ServiceToken": { "Fn::GetAtt": ["CFNWaiter", "Arn"] },
        "ServiceTimeout": 60
      }
    }
  },
...
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-custom-resource-yaml"></a>

```
...
  CFNWaiterCustomResource:
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt CFNWaiter.Arn
      ServiceTimeout: 60
...
```

`Outputs`  
此模板的 `Outputs` 是 `TimeWaited` 和 `WaiterId`。`TimeWaited` 值使用 `Fn::GetAtt` 函数提供等待者资源实际等待的时间。`WaiterId` 使用 `Fn::GetAtt` 函数来提供生成并与执行关联的唯一 ID。

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-output-json"></a>

```
...
  "Outputs": {
    "TimeWaited": {
      "Value": { "Fn::GetAtt": ["CFNWaiterCustomResource", "TimeWaited"] },
      "Export": { "Name": "TimeWaited" }
    },
    "WaiterId": {
      "Value": { "Fn::GetAtt": ["CFNWaiterCustomResource", "Id"] },
      "Export": { "Name": "WaiterId" }
    }
  }
}
...
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-output-yaml"></a>

```
...
Outputs:
  TimeWaited:
    Value: !GetAtt CFNWaiterCustomResource.TimeWaited
    Export:
      Name: TimeWaited
  WaiterId:
    Value: !GetAtt CFNWaiterCustomResource.Id
    Export:
      Name: WaiterId
...
```

## 先决条件
<a name="walkthrough-lambda-backed-custom-resources-prerequisites"></a>

您必须拥有 IAM 权限才能使用所有相应的服务，例如 Lambda 和 CloudFormation。

## 启动堆栈
<a name="walkthrough-lambda-backed-custom-resources-createfunction-createstack"></a>

**要创建 堆栈，请执行以下操作：**

1. 从[示例模板](#walkthrough-lambda-backed-custom-resources-sample-template)部分找到您喜欢的模板（YAML 或 JSON），并将其保存到您的计算机，名称为 `samplelambdabackedcustomresource.template`。

1. 通过以下网址打开 CloudFormation 控制台：[https://console.aws.amazon.com/cloudformation/](https://console.amazonaws.cn/cloudformation/)。

1. 在**堆栈**页面，选择右上角的**创建堆栈**，然后选择**使用新资源（标准）**。

1. 在**先决条件 – 准备模板**中，选择**选择现有模板**。

1. 对于**指定模板**，选择**上传模板文件**，然后选择**选择文件**。

1. 选择您之前保存的 `samplelambdabackedcustomresource.template` 模板文件。

1. 选择**下一步**。

1. 对于**堆栈名称**，键入 **SampleCustomResourceStack**，然后选择**下一步**。

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

1. 确保堆栈名​​称看起来正确，然后选择**创建**。

CloudFormation 可能需要几分钟的时间创建堆栈。要监控进度，可查看堆栈事件。有关更多信息，请参阅 [从 CloudFormation 控制台查看堆栈信息](cfn-console-view-stack-data-resources.md)。

如果堆栈创建成功，则堆栈中的所有资源（例如 Lambda 函数和自定义资源）都已创建。您已成功使用 Lambda 函数和自定义资源。

如果 Lambda 函数返回错误，则在 CloudWatch Logs [控制台](https://console.amazonaws.cn/cloudwatch/home#logs:)中查看此函数的日志。日志流的名称与自定义资源的物理 ID 相同，您可通过查看堆栈的资源来查找该名称。有关更多信息，请参阅《Amazon CloudWatch 用户指南》中的[查看日志数据](https://docs.amazonaws.cn/AmazonCloudWatch/latest/logs/Working-with-log-groups-and-streams.html#ViewingLogData)**。

## 清理资源
<a name="walkthrough-lambda-backed-custom-resources-createfunction-cleanup"></a>

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

**删除堆栈**

1. 从 CloudFormation 控制台中，选择 **SampleCustomResourceStack** 堆栈。

1. 选择 **Actions**，然后选择 **Delete Stack**。

1. 在确认消息中，选择 **Yes, Delete**。

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

既然您已了解如何创建和使用 Lambda 支持的自定义资源，可以使用本演练中的示例模板和代码来生成和试验其他堆栈和函数。

## 相关信息
<a name="w2aac11c45b9c24b9c23"></a>
+ [CloudFormation 自定义资源参考](crpg-ref.md)
+ [AWS::CloudFormation::CustomResource](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-customresource.html)

# `cfn-response` 模块
<a name="cfn-lambda-function-code-cfnresponsemodule"></a>

在 CloudFormation 模板中，您可以指定 Lambda 函数作为自定义资源的对象。如果使用 `ZipFile` 属性指定[函数](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html)的源代码，可以加载 `cfn-response` 模块，以将 Lambda 函数的响应发送到自定义资源。`cfn-response` 模块是一个库，可简化向调用 Lambda 函数的自定义资源发送响应的过程。该模块包含一个 `send` 方法，可以通过 Amazon S3 预签名 URL (`ResponseURL`) 将[响应对象](crpg-ref.md#crpg-ref-responses)发送到自定义资源。

只有当您使用 `cfn-response` 属性编写您的源代码时，`ZipFile` 模块可用。它对于存储在 Amazon S3 存储桶中的源代码不可用。对于 存储桶中的代码，您必须编写自己的函数来发送响应。

**注意**  
在执行 `send` 方法后，Lambda 函数将终止，因此，将忽略在该方法之后写入的任何内容。

## 加载 `cfn-response` 模块
<a name="cfn-lambda-function-code-cfnresponsemodule-loading"></a>

对于 Node.js 函数，使用 `require()` 函数来加载 `cfn-response` 模块。例如，以下代码示例创建一个名为 `cfn-response` 的 `response` 对象：

```
var response = require('cfn-response');
```

对于 Python，使用 `import` 语句来加载 `cfnresponse` 模块，如下例所示：

**注意**  
使用这个确切的导入语句。如果使用导入语句的其他变体，CloudFormation 将不会包含响应模块。

```
import cfnresponse
```

## `send` 方法参数
<a name="cfn-lambda-function-code-cfnresponsemodule-send-parameters"></a>

您可以将以下参数用于 `send` 方法。

`event`  
[自定义资源请求](crpg-ref.md#crpg-ref-requesttypes)中的字段。

`context`  
Lambda 函数特定的对象，可用于指定何时函数和任何回调完成执行，或从 Lambda 执行环境中访问信息。有关更多信息，请参阅《Amazon Lambda 开发人员指南》**中的[使用 Node.js 构建 Lambda 函数](https://docs.amazonaws.cn/lambda/latest/dg/lambda-nodejs.html)。

`responseStatus`  
函数是否成功完成。使用 `cfnresponse` 模块常量指定状态：`SUCCESS` 表示执行成功；`FAILED` 表示执行失败。

`responseData`  
自定义资源[响应对象](crpg-ref.md#crpg-ref-responses)的 `Data` 字段。数据为名称-值对列表。

`physicalResourceId`  
可选。调用此函数的自定义资源的唯一标识符。默认情况下，该模块使用与 Lambda 函数关联的 Amazon CloudWatch Logs 日志流的名称。  
为 `PhysicalResourceId` 返回的值可以更改自定义资源更新操作。如果返回的值相同，则将其视为正常更新。如果返回的值不同，CloudFormation 会将该更新视为替换，并向旧资源发送删除请求。有关更多信息，请参阅 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-customresource.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-customresource.html)。

`noEcho`  
可选。指示在使用 `Fn::GetAtt` 函数检索自定义资源的输出时是否遮蔽它。如果设置为 `true`，则所有返回的值都将用星号 (\$1\$1\$1\$1\$1) 遮蔽，但存储在下面指定位置的信息除外。默认情况下，此值为 `false`。  
使用 `NoEcho` 属性不会遮蔽在以下各区段中存储的任何信息：  
+ `Metadata` 模板区段。CloudFormation 不会转换、修改或编辑您在 `Metadata` 部分中包含的任何信息。有关更多信息，请参阅 [Metadata](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html)。
+ `Outputs` 模板区段。有关更多信息，请参阅 [Outputs](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html)。
+ 资源定义的 `Metadata` 属性。有关更多信息，请参阅 [`Metadata` 属性](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-attribute-metadata.html)。
强烈建议您不要使用这些机制来包含敏感信息，例如密码。
有关使用 `NoEcho` 遮蔽敏感信息的更多信息，请参阅 [请勿将凭证嵌入您的模板](security-best-practices.md#creds) 最佳实践。

## 示例
<a name="cfn-lambda-function-code-cfnresponsemodule-examples"></a>

### Node.js
<a name="cfn-lambda-function-code-zipfile-examplenodejs"></a>

在下面的 Node.js 示例中，内联 Lambda 函数获取输入值并将其乘以 5。内联函数对于较小的函数尤为有用，因为它们让您能够在模板中直接指定源代码，而不必先创建包再将包上传到 Amazon S3 存储桶中。函数使用 `cfn-response` `send` 方法将结果发回给调用此函数的自定义资源。

#### JSON
<a name="cfn-lambda-function-code-zipfile-examplenodejs.json"></a>

```
"ZipFile": { "Fn::Join": ["", [
  "var response = require('cfn-response');",
  "exports.handler = function(event, context) {",
  "  var input = parseInt(event.ResourceProperties.Input);",
  "  var responseData = {Value: input * 5};",
  "  response.send(event, context, response.SUCCESS, responseData);",
  "};"
]]}
```

#### YAML
<a name="cfn-lambda-function-code-zipfile-examplenodejs-yaml"></a>

```
ZipFile: >
  var response = require('cfn-response');
  exports.handler = function(event, context) {
    var input = parseInt(event.ResourceProperties.Input);
    var responseData = {Value: input * 5};
    response.send(event, context, response.SUCCESS, responseData);
  };
```

### Python
<a name="cfn-lambda-function-code-zipfile-examplepython"></a>

在下面的 Python 示例中，内联 Lambda 函数采用一个整数值并将它乘以 5。

#### JSON
<a name="cfn-lambda-function-code-zipfile-examplepython.json"></a>

```
"ZipFile" : { "Fn::Join" : ["\n", [
  "import json",
  "import cfnresponse",
  "def handler(event, context):",
  "   responseValue = int(event['ResourceProperties']['Input']) * 5",
  "   responseData = {}",
  "   responseData['Data'] = responseValue",
  "   cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, \"CustomResourcePhysicalID\")"
]]}
```

#### YAML
<a name="cfn-lambda-function-code-zipfile-examplepython.yaml"></a>

```
ZipFile: |
  import json
  import cfnresponse
  def handler(event, context):
    responseValue = int(event['ResourceProperties']['Input']) * 5
    responseData = {}
    responseData['Data'] = responseValue
    cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")
```

## 模块源代码
<a name="cfn-lambda-function-code-cfnresponsemodule-source"></a>

**Topics**
+ [

### 异步 Node.js 源代码
](#cfn-lambda-function-code-cfnresponsemodule-source-nodejs-async)
+ [

### Node.js 源代码
](#cfn-lambda-function-code-cfnresponsemodule-source-nodejs)
+ [

### Python 源代码
](#cfn-lambda-function-code-cfnresponsemodule-source-python)

### 异步 Node.js 源代码
<a name="cfn-lambda-function-code-cfnresponsemodule-source-nodejs-async"></a>

以下是在处理程序异步进行处理时，Node.js 函数的响应模块源代码。请查看这些内容，以理解此模块的功能并帮助您实现自己的响应函数。

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0

exports.SUCCESS = "SUCCESS";
exports.FAILED = "FAILED";

exports.send = function(event, context, responseStatus, responseData, physicalResourceId, noEcho) {

    return new Promise((resolve, reject) => {
        var responseBody = JSON.stringify({
            Status: responseStatus,
            Reason: "See the details in CloudWatch Log Stream: " + context.logStreamName,
            PhysicalResourceId: physicalResourceId || context.logStreamName,
            StackId: event.StackId,
            RequestId: event.RequestId,
            LogicalResourceId: event.LogicalResourceId,
            NoEcho: noEcho || false,
            Data: responseData
        });

        console.log("Response body:\n", responseBody);

        var https = require("https");
        var url = require("url");

        var parsedUrl = url.parse(event.ResponseURL);
        var options = {
            hostname: parsedUrl.hostname,
            port: 443,
            path: parsedUrl.path,
            method: "PUT",
            headers: {
                "content-type": "",
                "content-length": responseBody.length
            }
        };

        var request = https.request(options, function(response) {
            console.log("Status code: " + parseInt(response.statusCode));
            resolve(context.done());
        });

        request.on("error", function(error) {
            console.log("send(..) failed executing https.request(..): " + maskCredentialsAndSignature(error));
            reject(context.done(error));
        });

        request.write(responseBody);
        request.end();
    })
}
 
function maskCredentialsAndSignature(message) {
    return message.replace(/X-Amz-Credential=[^&\s]+/i, 'X-Amz-Credential=*****')
        .replace(/X-Amz-Signature=[^&\s]+/i, 'X-Amz-Signature=*****');
}
```

### Node.js 源代码
<a name="cfn-lambda-function-code-cfnresponsemodule-source-nodejs"></a>

以下是在处理程序不是异步进行处理时，Node.js 函数的响应模块源代码。请查看这些内容，以理解此模块的功能并帮助您实现自己的响应函数。

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0
 
exports.SUCCESS = "SUCCESS";
exports.FAILED = "FAILED";

exports.send = function(event, context, responseStatus, responseData, physicalResourceId, noEcho) {

    var responseBody = JSON.stringify({
        Status: responseStatus,
        Reason: "See the details in CloudWatch Log Stream: " + context.logStreamName,
        PhysicalResourceId: physicalResourceId || context.logStreamName,
        StackId: event.StackId,
        RequestId: event.RequestId,
        LogicalResourceId: event.LogicalResourceId,
        NoEcho: noEcho || false,
        Data: responseData
    });

    console.log("Response body:\n", responseBody);

    var https = require("https");
    var url = require("url");

    var parsedUrl = url.parse(event.ResponseURL);
    var options = {
        hostname: parsedUrl.hostname,
        port: 443,
        path: parsedUrl.path,
        method: "PUT",
        headers: {
            "content-type": "",
            "content-length": responseBody.length
        }
    };

    var request = https.request(options, function(response) {
        console.log("Status code: " + parseInt(response.statusCode));
        context.done();
    });

    request.on("error", function(error) {
        console.log("send(..) failed executing https.request(..): " + maskCredentialsAndSignature(error));
        context.done();
    });

    request.write(responseBody);
    request.end();
}
```

### Python 源代码
<a name="cfn-lambda-function-code-cfnresponsemodule-source-python"></a>

以下是 Python 函数的响应模块源代码。

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
 
from __future__ import print_function
import urllib3
import json
import re

SUCCESS = "SUCCESS"
FAILED = "FAILED"

http = urllib3.PoolManager()


def send(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False, reason=None):
    responseUrl = event['ResponseURL']

    responseBody = {
        'Status' : responseStatus,
        'Reason' : reason or "See the details in CloudWatch Log Stream: {}".format(context.log_stream_name),
        'PhysicalResourceId' : physicalResourceId or context.log_stream_name,
        'StackId' : event['StackId'],
        'RequestId' : event['RequestId'],
        'LogicalResourceId' : event['LogicalResourceId'],
        'NoEcho' : noEcho,
        'Data' : responseData
    }

    json_responseBody = json.dumps(responseBody)

    print("Response body:")
    print(json_responseBody)

    headers = {
        'content-type' : '',
        'content-length' : str(len(json_responseBody))
    }

    try:
        response = http.request('PUT', responseUrl, headers=headers, body=json_responseBody)
        print("Status code:", response.status)


    except Exception as e:

        print("send(..) failed executing http.request(..):", mask_credentials_and_signature(e))
 
 
def mask_credentials_and_signature(message):
    message = re.sub(r'X-Amz-Credential=[^&\s]+', 'X-Amz-Credential=*****', message, flags=re.IGNORECASE)
    return re.sub(r'X-Amz-Signature=[^&\s]+', 'X-Amz-Signature=*****', message, flags=re.IGNORECASE)
```

# 使用模板宏对 CloudFormation 模板执行自定义处理
<a name="template-macros"></a>

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

要了解可能性的广度，请考虑 `AWS::Include` 和 `AWS::Serverless` 转换，这些转换是由 CloudFormation 托管的宏：
+ [AWS::Include 转换](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/transform-aws-include.html)可让您将样板文件模板代码段插入您的模板中。
+ [AWS::Serverless 转换](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/transform-aws-serverless.html)采用以 Amazon Serverless Application Model（Amazon SAM）语法编写的完整模板，将其转换并扩展为符合规范的 CloudFormation 模板。有关无服务器应用程序和 Amazon SAM 的更多信息，请参阅 [Amazon Serverless Application Model 开发人员指南](https://docs.amazonaws.cn/serverless-application-model/latest/developerguide/what-is-sam.html)。

**Topics**
+ [

## 计费
](#template-macros-billing)
+ [

## 宏示例
](#template-macros-examples-list)
+ [

## 相关资源
](#template-macros-related-resources)
+ [

# CloudFormation 宏概述
](template-macros-overview.md)
+ [

# 创建 CloudFormation 宏定义
](template-macros-author.md)
+ [

# 简单字符串替换宏的示例
](macros-example.md)
+ [

# 对所处理的模板进行故障排除
](template-macros-troubleshoot-processed-template.md)

## 计费
<a name="template-macros-billing"></a>

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

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

## 宏示例
<a name="template-macros-examples-list"></a>

除了本部分的示例之外，您还可以在 [GitHub 存储库](https://github.com/aws-cloudformation/aws-cloudformation-templates/tree/main/CloudFormation/MacrosExamples)中找到示例宏，包括源代码和模板。这些示例按“原样”提供，用于教学目的。

## 相关资源
<a name="template-macros-related-resources"></a>
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-macro.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-macro.html)
+ [CloudFormation 模板 Transform 部分](transform-section-structure.md)
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-transform.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-transform.html)
+ [AWS::Serverless 转换](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/transform-aws-serverless.html)
+ [AWS::Include 转换](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/transform-aws-include.html)

# CloudFormation 宏概述
<a name="template-macros-overview"></a>

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

要创建宏定义，您必须创建以下内容：
+ 一个执行模板处理的 Lambda 函数。此 Lambda 函数接受一个代码段或整个模板，以及您定义的任何其他参数。它返回已处理的模板代码段或整个模板作为响应。
+ [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-macro.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-macro.html) 类型的资源，使用户能够从 CloudFormation 模板内调用 Lambda 函数。此资源指定要为此宏调用的 Lambda函数的 ARN，以及辅助调试的其他可选属性。要在账户中创建此资源，请创建一个包含 `AWS::CloudFormation::Macro` 资源的模板，然后利用该模板创建具有自行管理权限的堆栈或堆栈集。Amazon CloudFormationStackSets 目前不支持通过引用 宏的模板创建或更新具有服务托管权限的堆栈集。

要使用宏，请在您的模板中引用宏：
+ 要处理模板的一段或部分，请在 `Fn::Transform` 函数中引用宏（位置是相对于要转换的模板内容而言的）。当使用 `Fn::Transform` 时，您还可以传递它需要的任何指定参数。
+ 要处理整个模板，请在模板的 [Transform](transform-section-structure.md) 部分中引用宏。

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

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

![\[使用 Fn::Transform 内置函数或模板的 Transform 部分，将模板内容和关联参数传递给宏的底层 Lambda 函数，该函数返回处理的模板内容。\]](http://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/images/template-macro-use.png)


## 如何直接创建堆栈
<a name="template-macros-change-sets"></a>

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

宏可以将 IAM 资源添加到您的模板中。对于这些资源，CloudFormation 要求您[确认其功能](control-access-with-iam.md#using-iam-capabilities)。由于 CloudFormation 无法在处理模板前了解所添加的资源，因此您可能需要在创建更改集时确认 IAM 功能，具体取决于引用的宏是否包含 IAM 资源。这样，当您运行该更改集时，CloudFormation 会具有创建 IAM 资源所需的功能。

要直接从处理的模板来创建或更新堆栈，而不事先查看更改集中提议的更改，可以在 `CreateStack` 或 `UpdateStack` 请求期间指定 `CAPABILITY_AUTO_EXPAND` 功能。仅当您知道宏在处理什么时，才应直接从包含宏的堆栈模板创建堆栈。您不能将更改集与堆栈集宏一起使用，必须直接更新堆栈集。

有关更多信息，请参阅《Amazon CloudFormation API 参考》** 中的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/APIReference/API_CreateStack.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/APIReference/API_CreateStack.html) 或 [https://docs.amazonaws.cn/AWSCloudFormation/latest/APIReference/API_UpdateStack.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/APIReference/API_UpdateStack.html)。

**重要**  
如果堆栈集模板引用了一个或多个宏，则必须直接从处理过的模板创建堆栈集，而无需先查看更改集中生成的更改。处理宏可添加您可能不知道的多个资源。在通过直接引用宏的模板创建或更新堆栈集之前，请确保您知道宏执行的处理操作。

为减少从引用宏的模板启动堆栈的步骤数，可使用 `package` 和 `deploy` Amazon CLI 命令。有关更多信息，请参阅[使用 Amazon CLI 将本地构件上传到 S3 存储桶](using-cfn-cli-package.md)和[创建包含转换的堆栈](service_code_examples.md#deploy-sdk)。

## 注意事项
<a name="template-macros-considerations"></a>

使用宏时，请记住以下注意事项和限制：
+ 只有在提供 Lambda 的 Amazon Web Services 区域才支持宏。有关提供 Lambda 的区域的列表，请参阅 [Amazon Lambda 端点和配额](https://docs.amazonaws.cn/general/latest/gr/lambda-service.html)。
+ 任何已处理模板代码段都必须是有效的 JSON。
+ 任何已处理的模板代码段都必须通过创建堆栈、更新堆栈、创建堆栈集或更新堆栈集等操作的验证检查。
+ CloudFormation 会先解析宏，然后再处理模板。生成的模板必须是有效的 JSON，并且不得超出模板大小限制。
+ 由于 CloudFormation 处理模板中元素的顺序，宏无法在其返回给 CloudFormation 的已处理模板内容中包含模块。有关更多信息，请参阅 [宏评估顺序](template-macros-author.md#template-macros-order)。
+ 使用更新回滚功能时，CloudFormation 会使用原始模板的副本。即使包含的代码段发生更改，它也会回滚到原始模板。
+ 宏中不能嵌套宏，因为我们不会迭代处理宏。
+ 目前在宏中不支持 `Fn::ImportValue` 内部函数。
+ 模板中包含的内部函数会在任何宏之后被评估。因此，宏返回的已处理模板内容可以包括对内部函数的调用，并且像往常一样对其进行评估。
+ StackSets 目前不支持通过引用 CloudFormation 宏的模板，使用服务托管权限创建或更新堆栈集。

## 宏账户范围和权限
<a name="template-macros-permissions"></a>

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

![\[通过允许对 Lambda 函数进行跨账户访问，Amazon 能让您在引用该函数的多个账户中创建宏。\]](http://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/images/template-macro-accounts.png)


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

要使 CloudFormation 成功运行模板中包含的宏，用户必须对底层 Lambda 函数具有 `Invoke` 权限。为防止可能的权限升级，CloudFormation 会在运行宏时模拟用户。

有关更多信息，请参阅*《Amazon Lambda 开发人员指南》*中的[在 Amazon Lambda 中管理权限](https://docs.amazonaws.cn/lambda/latest/dg/lambda-permissions.html)和*《服务授权参考》*中的 [Amazon Lambda 操作、资源和条件键](https://docs.amazonaws.cn/service-authorization/latest/reference/list_awslambda.html)。

# 创建 CloudFormation 宏定义
<a name="template-macros-author"></a>

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

## 事件映射
<a name="template-macros-event-mapping"></a>

当 CloudFormation 调用宏的 Lambda 函数时，它会以 JSON 格式发送请求，其结构如下所示：

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

  宏所在的区域。
+ `accountId`

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

  可用于自定义处理的模板内容，采用 JSON 格式。
  + 对于 `Transform` 模板部分中包含的宏，这是整个模板，除 `Transform` 部分外。
  + 对于在 `Fn::Transform` 内部函数调用中包含的宏，这包括基于内部函数在模板中的位置的所有同级节点（及其子节点），除 `Fn::Transform` 函数外。有关更多信息，请参阅 [宏模板范围](#template-macros-scope)。
+ `transformId`

  调用此函数的宏的名称。
+ `params`

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

  对于在 `Transform` 模板部分中包含的宏，此部分为空。
+ `requestId`

  调用此函数的请求的 ID。
+ `templateParameterValues`

  在模板的 [Parameters](parameters-section-structure.md) 部分中指定的任何参数。CloudFormation 在将这些参数传递给函数之前会进行评估。

## 响应格式
<a name="template-macros-response-format"></a>

CloudFormation 要求 Lambda 函数以如下 JSON 格式返回响应：

```
{
    "requestId" : "$REQUEST_ID",
    "status" : "$STATUS",
    "fragment" : { ... },
    "errorMessage": "optional error message for failures"
}
```
+ `requestId`

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

  请求的状态（不区分大小写）。应设置为 `success`。CloudFormation 会将任何其他响应都视为失败。
+ `fragment`

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

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

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

  解释转换失败原因的错误消息。CloudFormation 将在堆栈的 **Stack details**（堆栈详细信息）页面的 **Events**（事件）窗格中显示此错误消息。

  例如：

  ```
  Error creating change set: Transform
                              Amazon Web Services 账户 account
                              number::macro name failed with:
                              error message string.
  ```

## 创建宏定义
<a name="create-a-macro-definition"></a>

**创建 CloudFormation 宏定义**

1. [构建 Lambda 函数](https://docs.amazonaws.cn/lambda/latest/dg/getting-started.html)来处理模板内容。该函数可以处理模板的任何部分，甚至是整个模板。

1. 创建包含 `AWS::CloudFormation::Macro` 资源类型的 CloudFormation 模板，并指定 `Name` 和 `FunctionName` 属性。`FunctionName` 属性必须包含在 CloudFormation 运行宏时调用的 Lambda 函数的 ARN。

1. （可选）为了帮助调试，您还可以在为宏创建 `AWS::CloudFormation::Macro` 资源类型时指定 `LogGroupName` 和 `LogRoleArn` 属性。借助这些属性，您可以指定 CloudFormation 在调用宏的底层 Lambda 函数时向其发送错误日志信息的 CloudWatch Logs 日志组，以及 CloudFormation 在将日志条目发送到这些日志时应代入的角色。

1. 在要使用宏的账户中使用带宏的模板[创建堆栈](cfn-console-create-stack.md)。或在管理员账户中使用带宏的模板[创建具有自行管理权限的堆栈集](stacksets-getting-started-create-self-managed.md)，然后在目标账户中创建堆栈实例。

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

## 宏模板范围
<a name="template-macros-scope"></a>

在模板的 `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: amzn-s3-demo-bucket1
        Tags: [{"key":"value"}] 
        'Fn::Transform':
          - Name: 'AWS::Include'
              Parameters:
                Location: s3://amzn-s3-demo-bucket2/MyFileName.yaml
        CorsConfiguration: []
        # End of processable content for AWS::Include
    MyEc2Instance:
      Type: AWS::EC2::Instance
      Properties:
        ImageID: ami-1234567890abcdef0
# End of processable content for MyMacro
```

## 宏评估顺序
<a name="template-macros-order"></a>

您可以在给定模板中引用多个宏，包括由 CloudFormation 托管的转换，例如 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/transform-aws-include.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/transform-aws-include.html) 和 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/transform-aws-serverless.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/transform-aws-serverless.html)。

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

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

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

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

# 简单字符串替换宏的示例
<a name="macros-example"></a>

下面的示例演示了使用宏的过程：从在模板中定义宏，到为宏创建 Lambda 函数，再到在模板中使用宏。

在此示例中，我们创建一个简单的宏，它插入指定的字符串来替换已处理模板中的指定目标内容。然后我们将使用它在已处理模板的指定位置插入空白 `WaitHandleCondition`。

## 创建宏
<a name="macros-example-definiton"></a>

在使用宏之前，我们首先要完成两件事：创建执行所需模板处理的 Lambda 函数，然后通过创建宏定义使该 Lambda 函数可用于 CloudFormation。

以下示例模板包含示例宏的定义。为了使宏在特定 Amazon Web Services 账户中可用，应从模板创建一个堆栈。宏定义指定宏名称、简要描述，并引用在模板中使用此宏时 CloudFormation 调用的 Lambda 函数的 ARN。（我们没有包含 `LogGroupName` 或 `LogRoleARN` 属性来用于记录错误日志。） 

在本示例中，假定从此模板创建的堆栈名为 `JavaMacroFunc`。由于宏 `Name` 属性设置为堆栈名称，因此生成的宏也名为 `JavaMacroFunc`。

```
AWSTemplateFormatVersion: 2010-09-09
  Resources:
    Macro:
      Type: AWS::CloudFormation::Macro
      Properties:
        Name: !Sub '${AWS::StackName}'
        Description: Adds a blank WaitConditionHandle named WaitHandle
        FunctionName: 'arn:aws:lambda:us-east-1:012345678910:function:JavaMacroFunc'
```

## 使用宏
<a name="macros-example-usage"></a>

为了使用宏，我们将使用 `Fn::Transform` 内置函数将其包含在模板中。

当我们使用下面的模板创建堆栈时，CloudFormation 会调用我们的示例宏。底层 Lambda 函数将一个指定的字符串替换为另一个指定的字符串。在这种情况下，结果是空的 `AWS::CloudFormation::WaitConditionHandle` 插入到已处理模板中。

```
Parameters:
  ExampleParameter:
    Type: String
    Default: 'SampleMacro'

Resources:
  2a:
    Fn::Transform:
      Name: "JavaMacroFunc"
      Parameters:
        replacement: 'AWS::CloudFormation::WaitConditionHandle'
        target: '$$REPLACEMENT$$'
    Type: '$$REPLACEMENT$$'
```
+ 要调用的宏被指定为 `JavaMacroFunc`，它来自上一个宏定义示例。
+ 将会向该宏传递两个参数，`target` 和 `replacement`，它们代表目标字符串及其所需的替换值。
+ 该宏可以对 `Type` 节点的内容进行操作，因为 `Type` 是引用该宏的 `Fn::Transform` 函数的同级节点。
+ 生成的 `AWS::CloudFormation::WaitConditionHandle` 名为 `2a`。
+ 该模板还包含一个该宏也可以访问的模板参数 `ExampleParameter`（但在这种情况下不使用）。

## Lambda 输入数据
<a name="macros-example-request"></a>

当 CloudFormation 在堆栈创建期间处理我们的示例模板时，它将以下事件映射传递给在 `JavaMacroFunc` 宏定义中引用的 Lambda 函数。
+ `region` : `us-east-1`
+ `accountId` : `012345678910`
+ `fragment` :

  ```
  {
    "Type": "$$REPLACEMENT$$"
  }
  ```
+ `transformId` : `012345678910::JavaMacroFunc`
+ `params` : 

  ```
  {
      "replacement": "AWS::CloudFormation::WaitConditionHandle",
      "target": "$$REPLACEMENT$$"
  }
  ```
+ `requestId` : `5dba79b5-f117-4de0-9ce4-d40363bfb6ab`
+ `templateParameterValues` :

  ```
  {
      "ExampleParameter": "SampleMacro"
  }
  ```

`fragment` 包含 JSON，表示该宏可以处理的模板片段。此片段由 `Fn::Transform` 函数调用的同级函数调用组成，但不包括函数调用本身。此外，`params` 包含 JSON，表示宏参数。在这种情况下，是替换和目标。同样，`templateParameterValues` 包含 JSON，表示为整个模板指定的参数。

## Lambda 函数代码
<a name="macros-example-function"></a>

以下是 Lambda 函数的实际代码，它是 `JavaMacroFunc` 示例宏的底层。它迭代响应中包含的模板片段（无论是字符串、列表还是映射格式），从而查找指定的目标字符串。如果它找到指定的目标字符串，则 Lambda 函数会使用指定的替换字符串替换目标字符串。否则，该函数会保持模板片段不变。然后，该函数将下面详细讨论的预期属性的映射返回到 CloudFormation。

```
package com.macroexample.lambda.demo;

import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

public class LambdaFunctionHandler implements RequestHandler<Map<String, Object>, Map<String, Object>> {

	private static final String REPLACEMENT = "replacement";
	private static final String TARGET = "target";
	private static final String PARAMS = "params";
	private static final String FRAGMENT = "fragment";
	private static final String REQUESTID = "requestId";
	private static final String STATUS = "status";
	private static final String SUCCESS = "SUCCESS";
	private static final String FAILURE = "FAILURE";
    @Override
    public Map<String, Object> handleRequest(Map<String, Object> event, Context context) {
        // TODO: implement your handler
    	final Map<String, Object> responseMap = new HashMap<String, Object>();
        responseMap.put(REQUESTID, event.get(REQUESTID));
        responseMap.put(STATUS, FAILURE);
    	try {
	        if (!event.containsKey(PARAMS)) {
	        	throw new RuntimeException("Params are required");
	        }
	    	
	        final Map<String, Object> params = (Map<String, Object>) event.get(PARAMS);
	        if (!params.containsKey(REPLACEMENT) || !params.containsKey(TARGET)) {
	        	throw new RuntimeException("replacement or target under Params are required");
	        }
	    	
	    	final String replacement = (String) params.get(REPLACEMENT);
	    	final String target = (String) params.get(TARGET);
	    	final Object fragment = event.getOrDefault(FRAGMENT, new HashMap<String, Object>());
	    	final Object retFragment;
	    	if (fragment instanceof String) {
	    		retFragment = iterateAndReplace(replacement, target, (String) fragment);
	    	} else if (fragment instanceof List) {
	    		retFragment = iterateAndReplace(replacement, target, (List<Object>) fragment);
	    	} else if (fragment instanceof Map) {
	    		retFragment = iterateAndReplace(replacement, target, (Map<String, Object>) fragment);
	    	} else {
	    		retFragment = fragment;
	    	}
	        responseMap.put(STATUS, SUCCESS);
	        responseMap.put(FRAGMENT, retFragment);
	        return responseMap;
    	} catch (Exception e) {
    		e.printStackTrace();
    		context.getLogger().log(e.getMessage());
    		return responseMap;
    	}
    }
    
    private Map<String, Object> iterateAndReplace(final String replacement, final String target, final Map<String, Object> fragment) {
    	final Map<String, Object> retFragment = new HashMap<String, Object>();
    	final List<String> replacementKeys = new ArrayList<>();
    	fragment.forEach((k, v) -> {
    		if (v instanceof String) {
    			retFragment.put(k, iterateAndReplace(replacement, target, (String)v));
    		} else if (v instanceof List) {
    			retFragment.put(k, iterateAndReplace(replacement, target, (List<Object>)v));
    		} else if (v instanceof Map ) {
    			retFragment.put(k, iterateAndReplace(replacement, target, (Map<String, Object>) v));
    		} else {
    			retFragment.put(k, v);
    		}
    	});
    	return retFragment;
    }

    private List<Object> iterateAndReplace(final String replacement, final String target, final List<Object> fragment) {
    	final List<Object> retFragment = new ArrayList<>();
    	fragment.forEach(o -> {
    		if (o instanceof String) {
    			retFragment.add(iterateAndReplace(replacement, target, (String) o));
    		} else if (o instanceof List) {
    			retFragment.add(iterateAndReplace(replacement, target, (List<Object>) o));
    		} else if (o instanceof Map) {
    			retFragment.add(iterateAndReplace(replacement, target, (Map<String, Object>) o));
    		} else {
    			retFragment.add(o);
    		}
    	});
    	return retFragment;
    }
    
    private String iterateAndReplace(final String replacement, final String target, final String fragment) {
    	System.out.println(replacement + " == " + target + " == " + fragment );
    	if (fragment != null AND_AND fragment.equals(target))
    		return replacement;
    	return fragment;
    }
}
```

## Lambda 函数响应
<a name="macros-example-response"></a>

以下是 Lambda 函数返回到 CloudFormation 进行处理的映射。
+ `requestId` : `5dba79b5-f117-4de0-9ce4-d40363bfb6ab`
+ `status` : `SUCCESS`
+ `fragment` :

  ```
  {
    "Type": "AWS::CloudFormation::WaitConditionHandle"
  }
  ```

从 CloudFormation 发送的 `requestId` 匹配项，以及 `SUCCESS` 的 `status` 值表示 Lambda 函数成功处理了请求中包含的模板片段。在此响应中，`fragment` 包含 JSON，表示要插入到已处理模板中的内容，而不是原始模板代码段。

## 生成的已处理模板
<a name="macros-example-processed"></a>

在 CloudFormation 从 Lambda 函数收到成功响应后，它将返回的模板片段插入到已处理模板中。

下面是我们示例的生成的已处理模板。不再包括引用 `JavaMacroFunc` 宏的 `Fn::Transform` 内置函数调用。Lambda 函数返回的模板片段包含在适当的位置，结果是内容 `"Type": "$$REPLACEMENT$$"` 已替换为 `"Type": "AWS::CloudFormation::WaitConditionHandle"`。

```
{
    "Parameters": {
        "ExampleParameter": {
            "Default": "SampleMacro",
            "Type": "String"
        }
    },
    "Resources": {
        "2a": {
            "Type": "AWS::CloudFormation::WaitConditionHandle"
        }
    }
}
```

# 对所处理的模板进行故障排除
<a name="template-macros-troubleshoot-processed-template"></a>

使用宏时，可以在 CloudFormation 控制台中找到所处理的模板。

模板的阶段指示其处理状态：
+ `Original`：用户最初提交的用于创建或更新堆栈或堆栈集的模板。
+ `Processed`：CloudFormation 在处理任何引用的宏之后，用于创建或更新堆栈或堆栈集的模板。即使原始模板格式化为 YAML，已处理模板也会格式化为 JSON。

要排除故障，可使用所处理的模板。如果模板不引用宏，则原始模板和已处理模板是相同的。

有关更多信息，请参阅 [从 CloudFormation 控制台查看堆栈信息](cfn-console-view-stack-data-resources.md)。

要使用 Amazon CLI 获取所处理的模板，应使用 [get-template](service_code_examples.md#get-template-sdk) 命令。

## 大小限制
<a name="template-macros-size-limitation"></a>

当处理的堆栈模板直接传递到 `CreateStack`、`UpdateStack` 或 `ValidateTemplate` 请求时，其最大大小为 51200 字节；或者当使用 Amazon S3 模板 URL 作为 S3 对象传递时，为 1MB。但是，在处理期间，CloudFormation 会更新模板的临时状态，因为它连续处理模板中包含的宏。因此，在处理期间，模板的大小可能会临时超出完全处理的模板所允许的大小。CloudFormation 允许为这些处理中的模板留出一些缓冲。但是，在设计模板和宏时，要始终考虑处理的堆栈模板所允许的最大大小。

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

要解决这一问题，可执行下列操作：
+ 将您的模板分成多个模板，以避免超出为处理中的模板规定的最大大小。例如：
  + 使用嵌套堆栈模板来封装模板的不同部分。有关更多信息，请参阅 [使用嵌套堆栈将模板拆分为可重复使用的部分](using-cfn-nested-stacks.md)。
  + 创建多个堆栈，并使用跨堆栈引用来相互交换信息。有关更多信息，请参阅 [引用其他 CloudFormation 堆栈中的资源输出](walkthrough-crossstackref.md)。
+ 减小给定宏返回的模板片段大小。CloudFormation 不会篡改宏返回的片段内容。

# 使用嵌套堆栈将模板拆分为可重复使用的部分
<a name="using-cfn-nested-stacks"></a>

随着基础设施的发展，您可能会发现自己在多个模板中反复创建相同的资源配置。为避免这种冗余，您可以将这些常用配置分成专用模板。然后，您可以使用其他模板中的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-stack.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-stack.html) 资源来引用这些专用模板，创建嵌套堆栈。

例如，假如您拥有用于大多数堆栈的负载均衡器配置。您可以为负载均衡器创建专用模板，而不是将相同的配置复制并粘贴到您的模板中。然后，您可以从需要相同负载均衡器配置的其他模板中引用此模板。

嵌套堆栈本身可以包含其他嵌套堆栈，构成一个堆栈层次结构，如下图所示。*根堆栈*是所有嵌套堆栈最终归属的顶级堆栈。每个嵌套堆栈都有一个直属父堆栈。对于第一级的嵌套堆栈而言，根堆栈也是父堆栈。
+ 堆栈 A 是该层次结构中所有其他嵌套堆栈的根堆栈。
+ 对于堆栈 B 来说，堆栈 A 既是父堆栈，也是根堆栈。
+ 对于堆栈 D，堆栈 C 是父堆栈；而对于堆栈 C 来说，堆栈 B 是父堆栈。

![\[作为另一个堆栈的一部分而创建的嵌套堆栈具有一个直属父堆栈，同时也具有顶级根堆栈。\]](http://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/images/cfn-console-nested-stacks.png)


**Topics**
+ [

## 拆分模板之前和之后的示例
](#create-nested-stack-template)
+ [

## 嵌套堆栈架构的示例
](#nested-stack-examples)
+ [

## 在嵌套堆栈上执行堆栈操作
](#perform-stack-operations-on-nested-stacks)
+ [

## 相关信息
](#nested-stacks-related-information)

## 拆分模板之前和之后的示例
<a name="create-nested-stack-template"></a>

此示例演示如何提取单个大型 CloudFormation 模板，然后使用嵌套模板将其重组为结构化程度更高、可重复使用的设计。最初，“嵌套堆栈前”模板显示在一个文件中定义了所有资源。随着资源数量不断增长，该文件可能会变得混乱且难以管理。“嵌套堆栈后”模板将资源拆分为若干较小的独立模板。每个嵌套堆栈都处理一组特定的相关资源，从而使整体结构更有条理，更易于维护。


| 嵌套堆栈前 | 嵌套堆栈后 | 
| --- | --- | 
| <pre>AWSTemplateFormatVersion: 2010-09-09<br />Parameters:<br />  InstanceType:<br />    Type: String<br />    Default: t2.micro<br />    Description: The EC2 instance type<br />  <br />  Environment:<br />    Type: String<br />    Default: Production<br />    Description: The deployment environment<br /><br />Resources:<br />  MyEC2Instance:<br />    Type: AWS::EC2::Instance<br />    Properties:<br />      ImageId: ami-1234567890abcdef0<br />      InstanceType: !Ref InstanceType<br /><br />  MyS3Bucket:<br />    Type: AWS::S3::Bucket</pre> | <pre>AWSTemplateFormatVersion: 2010-09-09<br />Resources:<br />  MyFirstNestedStack:<br />    Type: AWS::CloudFormation::Stack<br />    Properties:<br />      TemplateURL: https://s3.amazonaws.com/amzn-s3-demo-bucket/first-nested-stack.yaml<br />      Parameters:<br />        # Pass parameters to the nested stack if needed<br />        InstanceType: t3.micro<br /><br />  MySecondNestedStack:<br />    Type: AWS::CloudFormation::Stack<br />    Properties:<br />      TemplateURL: https://s3.amazonaws.com/amzn-s3-demo-bucket/second-nested-stack.yaml<br />      Parameters:<br />        # Pass parameters to the nested stack if needed<br />        Environment: Testing<br />    DependsOn: MyFirstNestedStack</pre> | 

## 嵌套堆栈架构的示例
<a name="nested-stack-examples"></a>

本部分演示了一种嵌套堆栈架构，该架构由引用嵌套堆栈的顶级堆栈组成。嵌套堆栈部署 Node.js Lambda 函数，从顶级堆栈接收参数值，并返回通过顶级堆栈公开的输出。

**Topics**
+ [

### 步骤 1：在本地系统上为嵌套堆栈创建模板
](#create-a-nested-stack-template)
+ [

### 步骤 2：在本地系统上为顶级堆栈创建模板
](#create-a-nested-stack-parent-template)
+ [

### 步骤 3：打包并部署模板
](#create-a-nested-stack-parent-template)

### 步骤 1：在本地系统上为嵌套堆栈创建模板
<a name="create-a-nested-stack-template"></a>

以下示例显示嵌套堆栈模板的格式。

#### YAML
<a name="nested-stack-child-example.yaml"></a>

```
 1. AWSTemplateFormatVersion: 2010-09-09
 2. Description: Nested stack template for Lambda function deployment
 3. Parameters:
 4.   MemorySize:
 5.     Type: Number
 6.     Default: 128
 7.     MinValue: 128
 8.     MaxValue: 10240
 9.     Description: Lambda function memory allocation (128-10240 MB)
10. Resources:
11.   LambdaFunction:
12.     Type: AWS::Lambda::Function
13.     Properties:
14.       FunctionName: !Sub "${AWS::StackName}-Function"
15.       Runtime: nodejs18.x
16.       Handler: index.handler
17.       Role: !GetAtt LambdaExecutionRole.Arn
18.       Code:
19.         ZipFile: |
20.           exports.handler = async (event) => {
21.             return {
22.               statusCode: 200,
23.               body: JSON.stringify('Hello from Lambda!')
24.             };
25.           };
26.       MemorySize: !Ref MemorySize
27.   LambdaExecutionRole:
28.     Type: AWS::IAM::Role
29.     Properties:
30.       AssumeRolePolicyDocument:
31.         Version: '2012-10-17'
32.         Statement:
33.           - Effect: Allow
34.             Principal:
35.               Service: lambda.amazonaws.com
36.             Action: sts:AssumeRole
37.       ManagedPolicyArns:
38.         - 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
39. Outputs:
40.   LambdaArn:
41.     Description: ARN of the created Lambda function
42.     Value: !GetAtt LambdaFunction.Arn
```

### 步骤 2：在本地系统上为顶级堆栈创建模板
<a name="create-a-nested-stack-parent-template"></a>

以下示例显示了顶层堆栈模板的格式以及引用您在上一步中所创建堆栈的 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-stack.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-stack.html) 资源。

#### YAML
<a name="nested-stack-parent-example.yaml"></a>

```
 1. AWSTemplateFormatVersion: 2010-09-09
 2. Description: Top-level stack template that deploys a nested stack
 3. Resources:
 4.   NestedStack:
 5.     Type: AWS::CloudFormation::Stack
 6.     Properties:
 7.       TemplateURL: /path_to_template/nested-template.yaml
 8.       Parameters:
 9.         MemorySize: 256
10. Outputs:
11.   NestedStackLambdaArn:
12.     Description: ARN of the Lambda function from nested stack
13.     Value: !GetAtt NestedStack.Outputs.LambdaArn
```

### 步骤 3：打包并部署模板
<a name="create-a-nested-stack-parent-template"></a>

**注意**  
在本地使用模板时，Amazon CLI **package** 命令可以帮助您准备部署模板。它会自动处理将本地构件上传到 Amazon S3（包括 `TemplateURL`），并生成一个新的模板文件，其中包含对这些 S3 位置的更新引用。有关更多信息，请参阅 [使用 Amazon CLI 将本地构件上传到 S3 存储桶](using-cfn-cli-package.md)。

接下来，您可以使用 [https://docs.amazonaws.cn/cli/latest/reference/cloudformation/package.html](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/package.html) 命令将嵌套模板上传到 Amazon S3 存储桶。

```
aws cloudformation package \
  --s3-bucket amzn-s3-demo-bucket \
  --template /path_to_template/top-level-template.yaml \
  --output-template-file packaged-template.yaml \
  --output json
```

该命令在 `--output-template-file` 指定的路径上生成一个新模板。它将 `TemplateURL` 引用替换为 Amazon S3 位置，如下图所示。

**结果模板**

```
AWSTemplateFormatVersion: 2010-09-09
Description: Top-level stack template that deploys a nested stack
Resources:
  NestedStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://s3.us-west-2.amazonaws.com/amzn-s3-demo-bucket/8b3bb7aa7abfc6e37e2d06b869484bed.template
      Parameters:
        MemorySize: 256
Outputs:
  NestedStackLambdaArn:
    Description: ARN of the Lambda function from nested stack
    Value:
      Fn::GetAtt:
      - NestedStack
      - Outputs.LambdaArn
```

运行 **package** 命令后，您可以使用 [https://docs.amazonaws.cn/cli/latest/reference/cloudformation/deploy/](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/deploy/) 命令部署已处理的模板。对于包含 IAM 资源的嵌套堆栈，您必须通过包含 `--capabilities` 选项来确认 IAM 功能。

```
aws cloudformation deploy \
  --template-file packaged-template.yaml \
  --stack-name stack-name \
  --capabilities CAPABILITY_NAMED_IAM
```

## 在嵌套堆栈上执行堆栈操作
<a name="perform-stack-operations-on-nested-stacks"></a>

使用嵌套堆栈时，在操作过程中必须谨慎处理。某些堆栈操作（如堆栈更新等）应从根堆栈启动，而不是直接在嵌套堆栈上执行。更新根堆栈时，只有包含模板更改的嵌套堆栈才会更新。

此外，嵌套堆栈的存在可能会影响根堆栈上的操作。例如，如果一个嵌套堆栈卡在 `UPDATE_ROLLBACK_IN_PROGRESS` 状态，则根堆栈将等待该嵌套堆栈完成其回滚后再继续。在继续更新操作之前，请确保您拥有 IAM 权限，以在其回滚时取消堆栈更新。有关更多信息，请参阅 [使用 Amazon Identity and Access Management 控制 CloudFormation 访问权限](control-access-with-iam.md)。

按照以下过程查找根堆栈和嵌套堆栈。

**查看嵌套堆栈的根堆栈**

1. 登录到 Amazon Web Services 管理控制台 并打开 Amazon CloudFormation 控制台 [https://console.aws.amazon.com/cloudformation](https://console.amazonaws.cn/cloudformation/)。

1. 在**堆栈**页面上，选择您要查看其根堆栈的嵌套堆栈的名称。

   嵌套堆栈的堆栈名称上方会显示 **NESTED**。

1. 在**堆栈信息**选项卡的**概述**部分中，选择列为**根堆栈**的堆栈名称。

**查看属于根堆栈的嵌套堆栈**

1. 从要查看其嵌套堆栈的根堆栈中，选择**资源**选项卡。

1. 在**类型**列中，查找类型为 **AWS::CloudFormation::Stack** 的资源。

## 相关信息
<a name="nested-stacks-related-information"></a>
+ [嵌套现有的堆栈](resource-import-nested-stacks.md)
+ [理解堆栈资源的更新行为](using-cfn-updating-stacks-update-behaviors.md)
+ [继续回滚失败的嵌套堆栈更新](using-cfn-updating-stacks-continueupdaterollback.md#nested-stacks)
+ [嵌套堆栈回滚失败](troubleshooting.md#troubleshooting-errors-nested-stacks-are-stuck)

# 在 CloudFormation 模板中创建等待条件
<a name="using-cfn-waitcondition"></a>

本主题介绍了如何在模板中创建等待条件以协调堆栈资源的创建或跟踪配置过程的进度。例如，您可以在应用程序配置部分完成后开始另一个资源的创建，或者也可以在安装和配置过程中发送信号以跟踪其进度。

当 CloudFormation 创建含有等待条件的堆栈时：
+ 它会跟其他任何资源一样创建等待条件，并将等待条件的状态设置为 `CREATE_IN_PROGRESS`。
+ CloudFormation 等待至收到必要数量的成功信号或等待条件的超时时段到期。
+ 如果在超时时段到期之前收到了必要数量的成功信号：
  + 等待条件的状态更改为 `CREATE_COMPLETE`
  + 堆栈创建继续
+ 如果超时到期或收到了故障信号：
  + 等待条件的状态更改为 `CREATE_FAILED`
  + 堆栈回滚

**重要**  
对于 Amazon EC2 和 Auto Scaling 资源，我们建议您使用 CreationPolicy 属性而非等待条件。当实例创建过程成功完成后，将“CreationPolicy”属性添加到这些资源，并使用 cfn-signal 帮助程序脚本发送信号。  
有关更多信息，请参阅 [CreationPolicy 属性](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-attribute-creationpolicy.html)。

**注意**  
如果使用 Amazon PrivateLink，则响应等待条件的 VPC 中的资源必须能够访问 CloudFormation 特定的 Amazon Simple Storage Service (Amazon S3) 存储桶。资源必须将等待条件响应发送到预签名 Amazon S3 URL。如果这些资源不能向 Amazon S3 发送响应，则 CloudFormation 将不会收到响应，并且堆栈操作会失败。有关更多信息，请参阅[使用接口端点 (Amazon PrivateLink) 访问 Amazon CloudFormation](vpc-interface-endpoints.md)以及[使用存储桶策略控制从 VPC 端点的访问](https://docs.amazonaws.cn/AmazonS3/latest/userguide/example-bucket-policies-vpc-endpoint.html)。

**Topics**
+ [

## 在模板中创建等待条件
](#creating-wait-condition)
+ [

## 等待条件信号语法
](#wait-condition-signal-syntax)
+ [

## 访问信号数据
](#wait-condition-access-signal-data)

## 在模板中创建等待条件
<a name="creating-wait-condition"></a>

**1. 等待条件句柄**  
首先在堆栈模板中定义 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-waitconditionhandle.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-waitconditionhandle.html) 资源。该资源会生成发送信号所需的预签名 URL。这样您就可以发送信号，而无需提供 Amazon 凭证。例如：

```
Resources:
  MyWaitHandle:
    Type: AWS::CloudFormation::WaitConditionHandle
```

**2. 等待条件**  
接下来，在堆栈模板中定义 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-waitcondition.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-waitcondition.html) 资源。`AWS::CloudFormation::WaitCondition` 的基本结构如下所示：

```
  MyWaitCondition:
    Type: AWS::CloudFormation::WaitCondition
    Properties:
      Handle: String
      Timeout: String
      Count: Integer
```

`AWS::CloudFormation::WaitCondition` 资源有两个必要属性和一个可选属性。
+ `Handle`（必要）：对模板中声明的 `WaitConditionHandle` 的引用。
+ `Timeout`（必要）：CloudFormation 在收到必要数量的信号之前等待的秒数。`Timeout` 是一种最低时限属性，表示超时不会早于您指定的时间发生，但可能在指定时间后不久发生。您可指定的最长时间为 43200 秒 (12 小时)。
+ `Count`（可选）：CloudFormation 在将等待条件状态设置为 `CREATE_COMPLETE` 并继续创建堆栈前之前必须收到的成功信号数量。如果未指定，则默认值为 1。

通常，您想要等待条件在特定资源创建后立即开始。可以通过为等待条件添加 `DependsOn` 属性来完成此操作。向等待条件添加 `DependsOn` 属性时，CloudFormation 先在 `DependsOn` 属性中创建资源，然后创建等待条件。有关更多信息，请参阅 [DependsOn 属性](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-attribute-dependson.html)。

以下示例展示等待条件：
+ 在成功创建 `MyEC2Instance` 资源后开始
+ 将 `MyWaitHandle` 资源用作 `WaitConditionHandle`
+ 超时为 4500 秒
+ 默认 `Count` 为 1（因为未指定任何 `Count` 属性）

```
  MyWaitCondition:
    Type: AWS::CloudFormation::WaitCondition
    DependsOn: MyEC2Instance
    Properties:
      Handle: !Ref MyWaitHandle
      Timeout: '4500'
```

**3. 发送信号**  
为向 CloudFormation 发出成功或失败的信号，通常需要运行一些代码或脚本。例如，在 EC2 实例上运行的应用程序可能会执行一些额外的配置工作，然后向 CloudFormation 发出信号指示已完成。

信号必须发送至由等待条件句柄生成的预签名 URL。使用预签名 URL 发送成功或失败信号。

**发送信号**

1. 要检索模板中的预签名 URL，需使用带有等待条件句柄逻辑名称的 `Ref` 内置函数。

   如下例所示，您的模板可声明一个 Amazon EC2 实例，并使用 Amazon EC2 `UserData` 属性将预签名 URL 传递到该 EC2 实例。这样在这些实例上运行的脚本或应用程序就可以向 CloudFormation 发出成功或失败的信号。

   ```
     MyEC2Instance:
       Type: AWS::EC2::Instance
       Properties:
       InstanceType: t2.micro  # Example instance type
       ImageId: ami-055e3d4f0bbeb5878  # Change this as needed (Amazon Linux 2023 in us-west-2)
       UserData:
         Fn::Base64: 
           Fn::Join: 
             - ""
             - - "SignalURL="
               - { "Ref": "MyWaitHandle" }
   ```

   这会产生类似于下述信息的 `UserData` 输出：

   ```
   SignalURL=https://amzn-s3-demo-bucket.s3.amazonaws.com/....
   ```

   注意：在 Amazon Web Services 管理控制台和命令行工具中，预签名 URL 显示为等待条件句柄资源的物理 ID。

1. （可选）要检测堆栈进入等待条件的时间，可以使用以下方法之一：
   + 如果您通过启用的通知创建堆栈，那么 CloudFormation 将向指定主题发布针对每项堆栈事件的通知。如果您或您的应用程序订阅了该主题，您可以监测针对等待条件句柄创建事件的通知，并通过通知消息来检索预签名 URL。
   + 您还可以使用 Amazon Web Services 管理控制台、Amazon CLI 或 SDK 来监控堆栈事件。

1. 您需要通过预签名 URL 发送 HTTP 请求消息之后，才能发送信号。请求方法必须为 `PUT`，并且 `Content-Type` 标题必须为空字符串或省略。请求消息必须为 [等待条件信号语法](#wait-condition-signal-syntax) 指定表单的 JSON 结构。

   您必须发送由 `Count` 属性指定的成功信号数，以便 CloudFormation 继续创建堆栈。如果您的 `Count` 超过 1，则在发送到特定等待条件的所有信号中，每个信号的 `UniqueId` 值必须是唯一的。`UniqueId` 是随机的字母数字字符串。

   `curl` 命令是发送信号的一种方式。以下示例显示了向等待条件发送成功信号的 `curl` 命令行。

   ```
   $ curl -T /tmp/a \
     "https://amzn-s3-demo-bucket.s3.amazonaws.com/arn%3Aaws%3Acloudformation%3Aus-west-2%3A034017226601%3Astack%2Fstack-gosar-20110427004224-test-stack-with-WaitCondition--VEYW%2Fe498ce60-70a1-11e0-81a7-5081d0136786%2FmyWaitConditionHandle?Expires=1303976584&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Signature=ik1twT6hpS4cgNAw7wyOoRejVoo%3D"
   ```

   其中文件 *`/tmp/a`* 包含以下 JSON 结构：

   ```
   {
      "Status" : "SUCCESS",
      "Reason" : "Configuration Complete",
      "UniqueId" : "ID1234",
      "Data" : "Application has completed configuration."
   }
   ```

   此示例显示发送同一成功信号的 `curl` 命令行，不同的是，它将 JSON 结构作为命令行参数发送。

   ```
   $ curl -X PUT \
     -H 'Content-Type:' --data-binary '{"Status" : "SUCCESS","Reason" : "Configuration Complete","UniqueId" : "ID1234","Data" : "Application has completed configuration."}' \
     "https://amzn-s3-demo-bucket.s3.amazonaws.com/arn%3Aaws%3Acloudformation%3Aus-west-2%3A034017226601%3Astack%2Fstack-gosar-20110427004224-test-stack-with-WaitCondition--VEYW%2Fe498ce60-70a1-11e0-81a7-5081d0136786%2FmyWaitConditionHandle?Expires=1303976584&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Signature=ik1twT6hpS4cgNAw7wyOoRejVoo%3D"
   ```

## 等待条件信号语法
<a name="wait-condition-signal-syntax"></a>

在向等待条件句柄生成的 URL 发送信号时，您必须使用以下 JSON 格式：

```
{
  "Status" : "StatusValue",
  "UniqueId" : "Some UniqueId",
  "Data" : "Some Data",
  "Reason" : "Some Reason"
}
```

### 属性
<a name="wait-condition-signal-properties"></a>

`Status` 字段必须是以下任一值：
+ `SUCCESS`
+ `FAILURE`

`UniqueId` 字段标识发送至 CloudFormation 的信号。如果等待条件的 `Count` 属性大于 1，那么在针对特定等待条件发送的所有信号中，`UniqueId` 值必须唯一；否则，CloudFormation 会将该信号视为对先前已发送的具有相同 `UniqueId` 的信号的重传，并将其忽略。

`Data` 字段可包含要通过信号发回的任何信息。可以通过使用模板中的 [Fn::GetAtt ](resources-section-structure.md#resource-properties-getatt)函数来访问 `Data` 值。

`Reason` 字段为字符串，除与 JSON 格式相一致外，其内容中无任何其他限制。

## 访问信号数据
<a name="wait-condition-access-signal-data"></a>

要访问由有效信号发送的数据，可以在 CloudFormation 模板中为等待条件创建输出值。例如：

```
Outputs:
  WaitConditionData:
    Description: The data passed back as part of signalling the WaitCondition
    Value: !GetAtt MyWaitCondition.Data
```

然后可以使用 [https://docs.amazonaws.cn/cli/latest/reference/cloudformation/describe-stacks.html](https://docs.amazonaws.cn/cli/latest/reference/cloudformation/describe-stacks.html) 命令或 CloudFormation 控制台的**输出**选项卡来查看该数据。

`Fn::GetAtt` 函数将返回 `UniqueId` 和 `Data` 作为 JSON 结构中的名称/值对。例如：

```
{"Signal1":"Application has completed configuration."}
```

# 使用 CloudFormation 模块创建可跨模板包含的可重复使用的资源配置
<a name="modules"></a>

*模块*是一种供您以透明、易管理和可重复的方式打包资源配置以便跨堆栈模板实现包含的方法。模块可以将常见服务配置和最佳实践封装为模块化、可自定义的构建基块，供您包含在堆栈模板中。模块使您能够将包含最佳实践、专家领域知识和可接受的指南（例如安全性、合规性、治理和行业法规）在内的资源配置纳入模板中，而无需深入了解资源实施的复杂性。

例如，网络领域专家可以创建一个包含遵守安全准则的内置安全组和入口/出口规则的模块。然后，您可以将该模块纳入到模板中，以便在堆栈中预置安全的网络基础架构，而无需花费时间弄清楚 VPC、子网、安全组和网关的工作方式。此外，由于模块具有版本控制，因此如果安全指南随时间而发生变化，模块作者可以创建包含这些更改的新版本模块。

在模板中使用模块的特点包括：
+ **可预测性** – 模块必须遵守其在 CloudFormation 注册表中注册的架构，这样在您将模块纳入到模板中后，您就知道该模块可以解析到哪些资源。
+ **可重用性** – 您可以在多个模板和账户中使用同一模块。
+ **可追溯性** – CloudFormation 可以保留堆栈中的哪些资源是从模块预配置的知识，使您能够轻松了解资源变化的来源。
+ **可管理性**：注册模块后，您可以通过 CloudFormation 注册表对其进行管理，包括版本控制以及账户和区域可用性。

模块可以包含：
+ 要从模块配置的一个或多个资源以及任何关联的数据，例如输出数据或条件。
+ 使您能够在使用模块时指定自定义值的任何模块参数。

有关开发模块的信息，请参阅《CloudFormation CLI User Guide》**中的 [Developing modules](https://docs.amazonaws.cn/cloudformation-cli/latest/userguide/modules.html)。

**Topics**
+ [

## 使用模块时的注意事项
](#module-considerations)
+ [

# 了解模块版本控制
](module-versioning.md)
+ [

# 使用 CloudFormation 私有注册表中的模块
](modules-using.md)
+ [

# 使用参数指定模块值
](module-using-params.md)
+ [

# CloudFormation 模板中的引用模块资源
](module-ref-resources.md)

## 使用模块时的注意事项
<a name="module-considerations"></a>
+ 使用模块不收取任何额外费用。您只需为模块解析到堆栈中的资源付费。
+ CloudFormation 配额（例如堆栈中允许的最大资源数或模板正文的最大大小）适用于处理过的模板，无论该模板中包含的资源是否来自模块。有关更多信息，请参阅 [了解 CloudFormation 配额](cloudformation-limits.md)。
+ 您在堆栈级别指定的标签将分配给派生自模块的各个资源。
+ CloudFormation 处理模板时，在模块级别指定的帮助程序脚本不会传播到模块中包含的各个资源。
+ 模块中指定的输出将在模板级别传播到输出。

  将为每个输出分配一个逻辑 ID，该 ID 是模块逻辑名称和模块中定义的输出名称的拼接。有关更多信息，请参阅 [获取从已部署的 CloudFormation 堆栈导出的输出](using-cfn-stack-exports.md)。
+ 模块中指定的参数不会传播到模板级别的参数。

  但是，您可以创建引用模块级参数的模板级参数。有关更多信息，请参阅 [使用参数指定模块值](module-using-params.md)。

# 了解模块版本控制
<a name="module-versioning"></a>

CloudFormation 注册表充当存储库，您可以在其中注册和管理模块，以供在您的 Amazon Web Services 账户和区域内使用。您可以在您的账户和区域内注册来自各种来源的模块，包括 Amazon、第三方发布者和您自己的自定义扩展。有关更多信息，请参阅 [通过 CloudFormation 注册表管理扩展](registry.md)。

模块可以有不同的版本，因此您可以指定要使用的模块版本。当您需要更新或修改模块而不破坏依赖该模块的现有堆栈时，此版本控制功能特别有用。

使用模块的多个版本时，请注意以下事项：
+ 在堆栈操作期间，CloudFormation 会使用当前在执行堆栈操作的 Amazon Web Services 账户和区域中注册为默认版本的模块版本。包括嵌套在其他模块中的模块。

  因此，请注意，如果您在不同账户或区域中将同一模块的不同版本注册为默认版本，则使用同一个模板可能会导致不同的结果。
+ 在堆栈操作期间，CloudFormation 会使用当前在执行堆栈操作的 Amazon Web Services 账户和区域中注册为默认版本的资源版本。这包括通过纳入模块生成的资源。
+ 更改模块的默认版本不会启动任何堆栈更新操作。但是，在您下次使用包含该模块的任何模板执行堆栈操作（例如堆栈更新）时，CloudFormation 将在操作中使用新的默认版本。

  但在指定了**使用以前的模板**选项的情况下执行堆栈更新时例外，如下所述。
+ 对于堆栈更新操作，如果您指定**使用以前的模板**选项，则 CloudFormation 会使用先前处理过的模板进行堆栈更新，不会针对您可能对模块作出的任何更改重新处理模块。
+ 为了保证结果统一，如果要在堆栈模板中纳入模块以用于堆栈集，则应确保在计划部署堆栈实例的所有账户和区域中将模块的同一版本设置为默认版本。这包括嵌套在其他模块中的模块。有关更多信息，请参阅 [使用 StackSets 跨账户和区域管理堆栈](what-is-cfnstacksets.md)。

## 激活第三方公共模块的要求
<a name="requirements-for-modules"></a>

要在您的账户和区域中成功激活第三方公有模块，模块中包含的每个第三方公有扩展（资源或模块）必须满足以下条件：
+ **扩展激活**：必须在您要使用扩展的账户和区域中激活该扩展。有关更多信息，请参阅 [使用 CloudFormation 注册表中的第三方公有扩展](registry-public.md)。
+ **别名注册**：如果模块中的扩展使用类型名称别名，则该扩展必须使用相同的类型名称别名在您的账户和区域中注册。有关更多信息，请参阅 [使用别名以引用扩展](registry-public.md#registry-public-enable-alias)。
+ **版本兼容性**：当前激活的扩展版本必须是模块中指定的该扩展支持的主要版本之一。

如果您没有激活正确的第三方公有扩展和扩展版本，CloudFormation 将使操作失败，并显示一条错误消息，其中列出在成功激活该模块之前需要激活的扩展和版本。

# 使用 CloudFormation 私有注册表中的模块
<a name="modules-using"></a>

本主题介绍如何在 CloudFormation 模板中使用模块。将模块视为可以添加到模板中的预制资源包。

要使用模块，步骤如下：
+ **注册模块**：您在 CloudFormation 注册表中将模块注册为私有扩展。请确保模块已在您工作的 Amazon Web Services 账户和区域注册。有关更多信息，请参阅 [CoudFormation 注册表概念](registry-concepts.md)。
+ **将其包含在模板中**：将模块添加到 CloudFormation 模板的 [Resources](resources-section-structure.md) 部分，就像处理其他资源一样。您还需要提供模块所需的所有属性。
+ **创建或更新堆栈**：当您启动堆栈操作时，CloudFormation 会生成一个已处理的模板，该模板将所有包含的模块解析为适当的资源。
+ **预览更改**：在进行更改之前，您可以使用更改集来查看将添加或更改哪些资源。有关更多信息，请参阅 [使用更改集更新 CloudFormation 堆栈](using-cfn-updating-stacks-changesets.md)。

参阅以下示例：您有一个包含资源和模块的模板。模板包含一个单独的资源 `ResourceA` 和一个模块 `ModuleParent`。该模块包含两个资源（`ResourceB` 和 `ResourceC`）以及一个嵌套模块 `ModuleChild`。`ModuleChild` 包含单个资源 `ResourceD`。如果您使用此模板创建堆栈，CloudFormation 会处理模板并将模块解析为适当的资源。生成的堆栈有四个资源：`ResourceA`、`ResourceB`、`ResourceC` 和 `ResourceD`。

![\[在堆栈操作期间，CloudFormation 会将堆栈模板中包含的两个模块解析为适当的四个资源。\]](http://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/images/modules-resource-inclusion.png)


CloudFormation 会跟踪堆栈中的哪些资源是从模块创建而成的。您可以在给定堆栈的 **Events**（事件）、**Resources**（资源）和 **Drifts**（偏差）选项卡上查看此信息，更改集预览中也包含此信息。

模块与模板中的资源可以区别开来，因为它们遵循以下四部分命名约定，而不是资源所用的典型的三部分命名约定：

```
organization::service::use-case::MODULE
```

# 使用参数指定模块值
<a name="module-using-params"></a>

在 CloudFormation 中，您可以通过在堆栈创建或更新期间提供输入值，从而使用模板参数来自定义堆栈。这些参数允许您根据需要更改堆栈的某些方面。有关定义模板参数的更多信息，请参阅 [CloudFormation 模板 Parameters 语法](parameters-section-structure.md)。

同样，模块也可以有参数。这些模块参数使您能够从使用自定义值的模板（或其他模块）向模块输入自定义值。然后，模块可以使用这些自定义值来设置其所包含资源的属性值。

您还可以定义设置模块属性的模板参数，以便您可以输入在堆栈操作时传递给模块的值。

如果模块包含具有自己的模块参数的嵌套模块，则您可以：
+ 直接在父模块中为嵌套模块的参数指定值。
+ 在父模块中定义相应的模块参数，使嵌套模块的参数能够由包含父模块的模板（或模块）来设置。

## 使用模板参数指定模块参数值
<a name="module-using-params-example-1"></a>

以下示例展示了如何定义将值传递给模块的模板参数。

包含 `My::S3::SampleBucket::MODULE` 的此模板定义了模板参数 `BucketName`，该参数使用户能够在堆栈操作期间指定 S3 存储桶名称。

```
# Template containing My::S3::SampleBucket::MODULE
Parameters:
  BucketName:
    Description: Name for your sample bucket
    Type: String
Resources:
  MyBucket:
    Type: 'My::S3::SampleBucket::MODULE'
    Properties:
      BucketName: !Ref BucketName
```

## 在父模块中指定子模块中资源的属性
<a name="module-using-params-example-2"></a>

以下示例展示了如何在嵌套在另一个模块中的模块中指定参数值。

第一个模块 `My::S3::SampleBucketPrivate::MODULE` 将是子模块。该模块定义了两个参数：`BucketName` 和 `AccessControl`。为这些参数指定的值用于指定模块所包含的 `AWS::S3::Bucket` 资源的 `BucketName` 和 `AccessControl` 属性。以下为 `My::S3::SampleBucketPrivate::MODULE` 的模板片段。

```
# My::S3::SampleBucketPrivate::MODULE
AWSTemplateFormatVersion: 2010-09-09
Description: A sample S3 Bucket with Versioning and DeletionPolicy.
Parameters:
  BucketName:
    Description: Name for the bucket
    Type: String
  AccessControl:
    Description: AccessControl for the bucket
    Type: String
Resources:
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref BucketName
      AccessControl: !Ref AccessControl
      DeletionPolicy: Retain
      VersioningConfiguration:
        Status: Enabled
```

接下来，上一个模块嵌套在父模块 `My::S3::SampleBucket::MODULE` 中。父模块 `My::S3::SampleBucket::MODULE` 通过以下方式设置子模块参数：
+ 其将 `My::S3::SampleBucketPrivate::MODULE` 的 `AccessControl` 参数设置为 `Private`。
+ 对于 `BucketName`，其定义了一个模块参数，该参数将允许存储桶名称在包含 `My::S3::SampleBucket::MODULE` 的模板（或模块）中进行指定。

```
# My::S3::SampleBucket::MODULE
AWSTemplateFormatVersion: 2010-09-09
Description: A sample S3 Bucket. With Private AccessControl.
Parameters:
  BucketName:
    Description: Name for your sample bucket
    Type: String
Resources:
  MyBucket:
    Type: 'My::S3::SampleBucketPrivate::MODULE'
    Properties:
      BucketName: !Ref BucketName
      AccessControl: Private
```

## 为模块参数指定约束
<a name="modules-using-parameters-constraints"></a>

模块参数不支持约束强制执行。要对模块参数执行约束检查，请创建具有所需约束的模板参数，然后在模块参数中引用该模板参数。有关定义模板参数的更多信息，请参阅 [CloudFormation 模板 Parameters 语法](parameters-section-structure.md)。

# CloudFormation 模板中的引用模块资源
<a name="module-ref-resources"></a>

在 CloudFormation 模板中，您经常需要根据一个资源的名称或属性来设置另一个资源的属性。有关更多信息，请参阅 [引用资源](resources-section-structure.md#using-cross-resource-references)。

要引用 CloudFormation 模板中某个模块内包含的资源，必须将以下两个逻辑名称组合在一起：
+ 您在模板中包含模块时为模块本身指定的逻辑名称。
+ 该模块内特定资源的逻辑名称。

您可以将这两个逻辑名称组合在一起，两者之间可以使用也可以不使用句点 (.)。例如，如果模块的逻辑名称为 `MyModule`，而资源的逻辑名称为 `MyBucket`，则可以将该资源称为 `MyModule.MyBucket` 或 `MyModuleMyBucket`。

要查找模块内资源的逻辑名称，您可以查阅该模块的架构（该架构可在 CloudFormation 注册表中找到），也可以使用 [https://docs.amazonaws.cn/AWSCloudFormation/latest/APIReference/API_DescribeType.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/APIReference/API_DescribeType.html) 操作。架构列出了属于该模块的所有资源及其逻辑名称。

获得完整的逻辑名称后，您可以使用 `GetAtt` 和 `Ref` 之类的 CloudFormation 函数来访问模块资源上的属性值。

例如，您有一个 `My::S3::SampleBucket::MODULE` 模块，其中包含逻辑名称为 `S3Bucket` 的 `AWS::S3::Bucket` 资源。要使用 `Ref` 函数引用此存储桶的名称，请将模板中模块的名称（`MyBucket`）与模块中资源的逻辑名称（`S3Bucket`）组合使用。完整的逻辑名称为 `MyBucket.S3Bucket` 或 `MyBucketS3Bucket`。

**示例 模板**  
以下示例模板使用 `My::S3::SampleBucket::MODULE` 模块创建 S3 存储桶。它还会创建一个 Amazon SQS 队列，并将其名称设置为与模块中的存储桶名称相同。此外，该模板还输出所创建的 S3 存储桶的 Amazon 资源名称（ARN）。

```
# Template that uses My::S3::SampleBucket::MODULE
Parameters:
  BucketName:
    Description: Name for your sample bucket
    Type: String
Resources:
  MyBucket:
    Type: My::S3::SampleBucket::MODULE
    Properties:
      BucketName: !Ref BucketName
  exampleQueue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: !Ref MyBucket.S3Bucket
Outputs:
  BucketArn:
    Value: !GetAtt MyBucket.S3Bucket.Arn
```