

# 使用嵌套堆栈将模板拆分为可重复使用的部分
<a name="using-cfn-nested-stacks"></a>

随着基础设施的发展，您可能会发现自己在多个模板中反复创建相同的资源配置。为避免这种冗余，您可以将这些常用配置分成专用模板。然后，您可以使用其他模板中的 [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-stack.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-stack.html) 资源来引用这些专用模板，创建嵌套堆栈。

例如，假如您拥有用于大多数堆栈的负载均衡器配置。您可以为负载均衡器创建专用模板，而不是将相同的配置复制并粘贴到您的模板中。然后，您可以从需要相同负载均衡器配置的其他模板中引用此模板。

嵌套堆栈本身可以包含其他嵌套堆栈，构成一个堆栈层次结构，如下图所示。*根堆栈*是所有嵌套堆栈最终归属的顶级堆栈。每个嵌套堆栈都有一个直属父堆栈。对于第一级的嵌套堆栈而言，根堆栈也是父堆栈。
+ 堆栈 A 是该层次结构中所有其他嵌套堆栈的根堆栈。
+ 对于堆栈 B 来说，堆栈 A 既是父堆栈，也是根堆栈。
+ 对于堆栈 D，堆栈 C 是父堆栈；而对于堆栈 C 来说，堆栈 B 是父堆栈。

![\[作为另一个堆栈的一部分而创建的嵌套堆栈具有一个直属父堆栈，同时也具有顶级根堆栈。\]](http://docs.aws.amazon.com/zh_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.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-stack.html](https://docs.aws.amazon.com/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>

**注意**  
在本地使用模板时，AWS CLI **package** 命令可以帮助您准备部署模板。它会自动处理将本地构件上传到 Amazon S3（包括 `TemplateURL`），并生成一个新的模板文件，其中包含对这些 S3 位置的更新引用。有关更多信息，请参阅 [使用 AWS CLI 将本地构件上传到 S3 存储桶](using-cfn-cli-package.md)。

接下来，您可以使用 [https://docs.aws.amazon.com/cli/latest/reference/cloudformation/package.html](https://docs.aws.amazon.com/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.aws.amazon.com/cli/latest/reference/cloudformation/deploy/](https://docs.aws.amazon.com/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 权限，以在其回滚时取消堆栈更新。有关更多信息，请参阅 [使用 AWS Identity and Access Management 控制 CloudFormation 访问权限](control-access-with-iam.md)。

按照以下过程查找根堆栈和嵌套堆栈。

**查看嵌套堆栈的根堆栈**

1. 登录到 AWS 管理控制台 并打开 CloudFormation 控制台 [https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/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)