

# CloudFormation 堆栈的更改集示例
<a name="using-cfn-updating-stacks-changesets-samples"></a>

此部分提供 CloudFormation 将为通用堆栈更改创建的更改集示例。它们显示如何直接编辑模板；修改单个输入参数；计划资源重新创建 (替换)，这可防止您丢失未备份的数据或者中断正在堆栈中运行的应用程序；以及添加和删除资源。为了说明更改集的工作原理，我们将演练提交的更改，并说明生成的更改集。由于每个示例在之前的示例基础上构建并且假定您已了解之前的示例，我们建议您按顺序阅读。有关更改集中各个字段的说明，请参阅《Amazon CloudFormation API 参考》中的[更改](https://docs.amazonaws.cn/AWSCloudFormation/latest/APIReference/API_Change.html)数据类型。

您可以使用[控制台](using-cfn-updating-stacks-changesets-view.md)、Amazon CLI 或 CloudFormation [https://docs.amazonaws.cn/AWSCloudFormation/latest/APIReference/API_DescribeChangeSet.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/APIReference/API_DescribeChangeSet.html) API 操作来查看更改集详细信息。

我们使用以下[示例模板](https://s3.amazonaws.com/cloudformation-examples/user-guide/changesets/ec2-instance.txt)从堆栈生成以下各个更改集：

```
{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Description" : "A sample EC2 instance template for testing change sets.",
  "Parameters" : {
    "Purpose" : {
      "Type" : "String",
      "Default" : "testing",
      "AllowedValues" : ["testing", "production"],
      "Description" : "The purpose of this instance."
    },
    "KeyPairName" : {
      "Type": "AWS::EC2::KeyPair::KeyName",
      "Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instance"
    },
    "InstanceType" : {
      "Type" : "String",
      "Default" : "t2.micro",
      "AllowedValues" : ["t2.micro", "t2.small", "t2.medium"],
      "Description" : "The EC2 instance type."
    }
  },
  "Resources" : {
    "MyEC2Instance" : {
      "Type" : "AWS::EC2::Instance",
      "Properties" : {
        "KeyName" : { "Ref" : "KeyPairName" },
        "InstanceType" : { "Ref" : "InstanceType" },
        "ImageId" : "ami-8fcee4e5",
        "Tags" : [
          {
            "Key" : "Purpose",
            "Value" : { "Ref" : "Purpose" }
          }
        ]
      }
    }
  }
}
```

## 直接编辑模板
<a name="using-cfn-updating-stacks-changesets-samples-directly-editing-a-template"></a>

当您在堆栈模板中直接修改资源以生成更改集时，CloudFormation 将更改分为直接修改类，这与由更新后的参数值启动的更改相对。以下更改集添加新标签到 `i-1abc23d4` 实例，是直接修改的示例。所有其他输入值，例如参数值和功能均不变，因此我们将侧重于 `Changes` 结构。

```
{
    "StackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/MyStack/1a2345b6-0000-00a0-a123-00abc0abc000",
    "Status": "CREATE_COMPLETE",
    "ChangeSetName": "SampleChangeSet-direct",
    "Parameters": [
        {
            "ParameterValue": "testing",
            "ParameterKey": "Purpose"
        },
        {
            "ParameterValue": "MyKeyName",
            "ParameterKey": "KeyPairName"
        },
        {
            "ParameterValue": "t2.micro",
            "ParameterKey": "InstanceType"
        }
    ],
    "Changes": [
        {
            "ResourceChange": {
                "ResourceType": "AWS::EC2::Instance",
                "PhysicalResourceId": "i-1abc23d4",
                "Details": [
                    {
                        "ChangeSource": "DirectModification",
                        "Evaluation": "Static",
                        "Target": {
                            "Attribute": "Tags",
                            "RequiresRecreation": "Never"
                        }
                    }
                ],
                "Action": "Modify",
                "Scope": [
                    "Tags"
                ],
                "LogicalResourceId": "MyEC2Instance",
                "Replacement": "False"
            },
            "Type": "Resource"
        }
    ],
    "CreationTime": "2020-11-18T23:35:25.813Z",
    "Capabilities": [],
    "StackName": "MyStack",
    "NotificationARNs": [],
    "ChangeSetId": "arn:aws:cloudformation:us-east-1:123456789012:changeSet/SampleChangeSet-direct/1a2345b6-0000-00a0-a123-00abc0abc000"
}
```

在 `Changes` 结构中，只有一个 `ResourceChange` 结构。此结构描述一些信息，诸如 CloudFormation 将更改的资源类型、CloudFormation 将采取的操作、资源的 ID、更改的范围，以及更改是否需要替换（此时 CloudFormation 将创建新资源，然后删除旧资源）。在示例中，更改集指示 CloudFormation 将修改 `i-1abc23d4` EC2 实例的 `Tags` 属性，无需替换实例。

在 `Details` 结构中，CloudFormation 将此更改标记为直接修改，永远无需重新创建实例（替换）。您可以充满信心地执行此更改，知道 CloudFormation 不会替换实例。

CloudFormation 将此更改显示为 `Static` 评估。静态评估意味着 CloudFormation 可以在执行更改集之前确定标签的值。在一些情况下，CloudFormation 只有在执行更改集之后才可以确定值。CloudFormation 将这些更改标记为 `Dynamic` 评估。例如，如果您引用有条件替换的更新后资源，CloudFormation 无法确定是否会更改对更新后资源的引用。

## 修改输入参数值
<a name="using-cfn-updating-stacks-changesets-samples-modifying-a-single-input-parameter-value"></a>

在您修改输入参数值时，CloudFormation 为使用更新后参数值的每个资源生成两个更改。在本示例中，我们希望突出显示这些更改的样子以及您应该关注哪些信息。以下示例通过仅更改 `Purpose` 输入参数的值生成。

`Purpose` 参数指定 EC2 实例的标签键值。在示例中，参数值从 `testing` 更改为 `production`。新值显示在 `Parameters` 结构中。

```
{
    "StackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/MyStack/1a2345b6-0000-00a0-a123-00abc0abc000",
    "Status": "CREATE_COMPLETE",
    "ChangeSetName": "SampleChangeSet",
    "Parameters": [
        {
            "ParameterValue": "production",
            "ParameterKey": "Purpose"
        },
        {
            "ParameterValue": "MyKeyName",
            "ParameterKey": "KeyPairName"
        },
        {
            "ParameterValue": "t2.micro",
            "ParameterKey": "InstanceType"
        }
    ],
    "Changes": [
        {
            "ResourceChange": {
                "ResourceType": "AWS::EC2::Instance",
                "PhysicalResourceId": "i-1abc23d4",
                "Details": [
                    {
                        "ChangeSource": "DirectModification",
                        "Evaluation": "Dynamic",
                        "Target": {
                            "Attribute": "Tags",
                            "RequiresRecreation": "Never"
                        }
                    },
                    {
                        "CausingEntity": "Purpose",
                        "ChangeSource": "ParameterReference",
                        "Evaluation": "Static",
                        "Target": {
                            "Attribute": "Tags",
                            "RequiresRecreation": "Never"
                        }
                    }
                ],
                "Action": "Modify",
                "Scope": [
                    "Tags"
                ],
                "LogicalResourceId": "MyEC2Instance",
                "Replacement": "False"
            },
            "Type": "Resource"
        }
    ],
    "CreationTime": "2020-11-18T23:59:18.447Z",
    "Capabilities": [],
    "StackName": "MyStack",
    "NotificationARNs": [],
    "ChangeSetId": "arn:aws:cloudformation:us-east-1:123456789012:changeSet/SampleChangeSet/1a2345b6-0000-00a0-a123-00abc0abc000"
}
```

`Changes` 结构的工作原理与 [直接编辑模板](#using-cfn-updating-stacks-changesets-samples-directly-editing-a-template) 示例中类似。只有一个 `ResourceChange` 结构；它描述了对 `Tags` EC2 实例的 `i-1abc23d4` 属性的更改。

但是，在 `Details` 结构中，更改集显示了 `Tags` 属性的两个更改，即使只更改了一个参数值。引用更改后参数值的资源 (使用 `Ref` 内部函数) 始终会导致两个更改：一个为 `Dynamic` 评估，另一个为 `Static` 评估。您可以通过查看以下字段查看这些更改类型：
+ 对于 `Static` 评估更改，请查看 `ChangeSource` 字段。在此示例中，`ChangeSource` 字段等于 `ParameterReference`，意味着此更改是更新参数引用值的结果。更改集必须包含类似的 `Dynamic` 评估更改。
+ 您可以通过比较所有更改的 `Dynamic` 结构来查找匹配的 `Target` 评估更改，这会包含同样的信息。在此示例中，所有更改的 `Target` 结构包含 `Attribute` 和 `RequireRecreation` 字段的相同值。

对于这些类型的更改，重点在于静态评估，这向您提供了有关更改最详细的信息。在此示例中，静态评估显示更改是对参数引用值 (`ParameterReference`) 进行更改的结果。进行更改的确切参数由 `CauseEntity` 字段 (`Purpose` 参数) 指定。

## 确定“Replacement”字段中的值
<a name="using-cfn-updating-stacks-changesets-samples-determining-the-value-of-the-replacement-field"></a>

`ResourceChange` 结构中的 `Replacement` 字段指示 CloudFormation 是否重新创建资源。计划重新创建资源 (替换) 可防止您丢失未备份的数据或者中断正在堆栈中运行的应用程序。

`Replacement` 字段中的值取决于更改是否需要替换，这由更改的 `RequiresRecreation` 结构中的 `Target` 字段指示。例如，如果 `RequiresRecreation` 字段为 `Never`，则 `Replacement` 字段为 `False`。但是，如果单个资源上有多个更改，并且每个更改有不同的 `RequiresRecreation` 字段值，CloudFormation 将使用最具侵入性的行为更新资源。换而言之，即使多个更改中只有一个需要替换，CloudFormation 必须替换资源，因此，将 `Replacement` 字段设置为 `True`。

以下更改集通过更改每个参数 (`Purpose`、`InstanceType` 和 `KeyPairName`) 的值生成，这些参数均由 EC2 实例使用。通过这些更改，CloudFormation 需要替换实例，因为 `Replacement` 字段等于 `True`。

```
{
    "StackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/MyStack/1a2345b6-0000-00a0-a123-00abc0abc000",
    "Status": "CREATE_COMPLETE",
    "ChangeSetName": "SampleChangeSet-multiple",
    "Parameters": [
        {
            "ParameterValue": "production",
            "ParameterKey": "Purpose"
        },
        {
            "ParameterValue": "MyNewKeyName",
            "ParameterKey": "KeyPairName"
        },
        {
            "ParameterValue": "t2.small",
            "ParameterKey": "InstanceType"
        }
    ],
    "Changes": [
        {
            "ResourceChange": {
                "ResourceType": "AWS::EC2::Instance",
                "PhysicalResourceId": "i-7bef86f8",
                "Details": [
                    {
                        "ChangeSource": "DirectModification",
                        "Evaluation": "Dynamic",
                        "Target": {
                            "Attribute": "Properties",
                            "Name": "KeyName",
                            "RequiresRecreation": "Always"
                        }
                    },
                    {
                        "ChangeSource": "DirectModification",
                        "Evaluation": "Dynamic",
                        "Target": {
                            "Attribute": "Properties",
                            "Name": "InstanceType",
                            "RequiresRecreation": "Conditionally"
                        }
                    },
                    {
                        "ChangeSource": "DirectModification",
                        "Evaluation": "Dynamic",
                        "Target": {
                            "Attribute": "Tags",
                            "RequiresRecreation": "Never"
                        }
                    },
                    {
                        "CausingEntity": "KeyPairName",
                        "ChangeSource": "ParameterReference",
                        "Evaluation": "Static",
                        "Target": {
                            "Attribute": "Properties",
                            "Name": "KeyName",
                            "RequiresRecreation": "Always"
                        }
                    },
                    {
                        "CausingEntity": "InstanceType",
                        "ChangeSource": "ParameterReference",
                        "Evaluation": "Static",
                        "Target": {
                            "Attribute": "Properties",
                            "Name": "InstanceType",
                            "RequiresRecreation": "Conditionally"
                        }
                    },
                    {
                        "CausingEntity": "Purpose",
                        "ChangeSource": "ParameterReference",
                        "Evaluation": "Static",
                        "Target": {
                            "Attribute": "Tags",
                            "RequiresRecreation": "Never"
                        }
                    }
                ],
                "Action": "Modify",
                "Scope": [
                    "Tags",
                    "Properties"
                ],
                "LogicalResourceId": "MyEC2Instance",
                "Replacement": "True"
            },
            "Type": "Resource"
        }
    ],
    "CreationTime": "2020-11-18T00:39:35.974Z",
    "Capabilities": [],
    "StackName": "MyStack",
    "NotificationARNs": [],
    "ChangeSetId": "arn:aws:cloudformation:us-east-1:123456789012:changeSet/SampleChangeSet-multiple/1a2345b6-0000-00a0-a123-00abc0abc000"
}
```

通过查看各个更改 (`Details` 结构中的静态评估) 确定需要替换资源的更改。在此示例中，各个更改具有不同的 `RequireRecreation` 字段值，但对 `KeyName` 属性的更改是最具侵入性的更新行为，始终需要重新创建。CloudFormation 将替换实例，因为其键名称已更改。

如果键名称未更改，则对 `InstanceType` 属性的更改将为最具侵入性的更新行为 (`Conditionally`)，因此 `Replacement` 字段将为 `Conditionally`。要查找 CloudFormation 替换实例的条件，请查看 [https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-instance.html](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-instance.html) 资源类型的 `InstanceType` 属性的更新行为。

## 添加和删除资源
<a name="using-cfn-updating-stacks-changesets-samples-adding-and-removing-resources"></a>

以下示例通过提交修改后的模板生成，此修改删除了 EC2 实例，并添加了自动扩缩组和启动配置。

```
{
    "StackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/MyStack/1a2345b6-0000-00a0-a123-00abc0abc000",
    "Status": "CREATE_COMPLETE",
    "ChangeSetName": "SampleChangeSet-addremove",
    "Parameters": [
        {
            "ParameterValue": "testing",
            "ParameterKey": "Purpose"
        },
        {
            "ParameterValue": "MyKeyName",
            "ParameterKey": "KeyPairName"
        },
        {
            "ParameterValue": "t2.micro",
            "ParameterKey": "InstanceType"
        }
    ],
    "Changes": [
        {
            "ResourceChange": {
                "Action": "Add",
                "ResourceType": "AWS::AutoScaling::AutoScalingGroup",
                "Scope": [],
                "Details": [],
                "LogicalResourceId": "AutoScalingGroup"
            },
            "Type": "Resource"
        },
        {
            "ResourceChange": {
                "Action": "Add",
                "ResourceType": "AWS::AutoScaling::LaunchConfiguration",
                "Scope": [],
                "Details": [],
                "LogicalResourceId": "LaunchConfig"
            },
            "Type": "Resource"
        },
        {
            "ResourceChange": {
                "ResourceType": "AWS::EC2::Instance",
                "PhysicalResourceId": "i-1abc23d4",
                "Details": [],
                "Action": "Remove",
                "Scope": [],
                "LogicalResourceId": "MyEC2Instance"
            },
            "Type": "Resource"
        }
    ],
    "CreationTime": "2020-11-18T01:44:08.444Z",
    "Capabilities": [],
    "StackName": "MyStack",
    "NotificationARNs": [],
    "ChangeSetId": "arn:aws:cloudformation:us-east-1:123456789012:changeSet/SampleChangeSet-addremove/1a2345b6-0000-00a0-a123-00abc0abc000"
}
```

在 `Changes` 结构中，有三个 `ResourceChange` 结构，每个资源一个。对于每个资源，`Action` 字段指示 CloudFormation 添加还是删除资源。`Scope` 和 `Details` 字段为空，因为它们仅适用于修改后的资源。

对于新资源，CloudFormation 无法确定一些字段的值，直至您执行更改集。例如，CloudFormation 不提供自动扩缩组的物理 ID 和启动配置，因为它们尚不存在。在您执行更改集时，CloudFormation 创建新资源。

## 查看属性级别更改
<a name="using-cfn-updating-stacks-changesets-samples-property-level-change-set"></a>

以下示例说明了对 Amazon EC2 实例的 `Tag` 属性的属性级别更改。标签 `Value` 和 `Key` 将变为 `Test`。

```
"ChangeSetName": "SampleChangeSet",
    "ChangeSetId": "arn:aws:cloudformation:us-east-1:123456789012:changeSet/SampleChangeSet/38d91d27-798d-4736-9bf1-fb7c46207807",
    "StackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/SampleEc2Template/68edcdc0-f6b6-11ee-966c-126d572cdd11",
    "StackName": "SampleEc2Template",
    "Description": "A sample EC2 instance template for testing change sets.",
    "Parameters": [
        {
            "ParameterKey": "KeyPairName",
            "ParameterValue": "BatchTest"
        },
        {
            "ParameterKey": "Purpose",
            "ParameterValue": "testing"
        },
        {
            "ParameterKey": "InstanceType",
            "ParameterValue": "t2.micro"
        }
    ],
    "CreationTime": "2024-04-09T21:29:10.759000+00:00",
    "ExecutionStatus": "AVAILABLE",
    "Status": "CREATE_COMPLETE",
    "StatusReason": null,
    "NotificationARNs": [],
    "RollbackConfiguration": {
:...skipping...
{
    "Changes": [
        {
            "Type": "Resource",
            "ResourceChange": {
                "Action": "Modify",
                "LogicalResourceId": "MyEC2Instance",
                "PhysicalResourceId": "i-0cc7856a36315e62b",
                "ResourceType": "AWS::EC2::Instance",
                "Replacement": "False",
                "Scope": [
                    "Tags"
                ],
                "Details": [
                    {
                        "Target": {
                            "Attribute": "Tags",
                            "RequiresRecreation": "Never",
                            "Path": "/Properties/Tags/0/Value",
                            "BeforeValue": "testing",
                            "AfterValue": "Test",
                            "AttributeChangeType": "Modify"
                        },
                        "Evaluation": "Static",
                        "ChangeSource": "DirectModification"
                    },
                    {
                        "Target": {
                            "Attribute": "Tags",
                            "RequiresRecreation": "Never",
                            "Path": "/Properties/Tags/0/Key",
                            "BeforeValue": "Purpose",
                            "AfterValue": "Test",
                            "AttributeChangeType": "Modify"
                        },
                        "Evaluation": "Static",
                        "ChangeSource": "DirectModification"
                    }
                ],
                "BeforeContext": "{\"Properties\":{\"KeyName\":\"BatchTest\",\"ImageId\":\"ami-8fcee4e5\",\"InstanceType\":\"t2.micro\",\"Tags\":[{\"Value\":\"testing\",\"Key\":\"Purpose\"}]}}",
                "AfterContext": "{\"Properties\":{\"KeyName\":\"BatchTest\",\"ImageId\":\"ami-8fcee4e5\",\"InstanceType\":\"t2.micro\",\"Tags\":[{\"Value\":\"Test\",\"Key\":\"Test\"}]}}"
            }
        }
    ]
```

`Details` 结构说明了 `Key` 和 `Value` 在更改集执行之前的值，以及更改集执行之后将会具有的值。