

# 引导基于 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.aws.amazon.com/AWSEC2/latest/UserGuide/ec2launch-v2.html)。  
有关 AWS Windows AMI 的信息，请参阅《[AWS Windows AMI Reference](https://docs.aws.amazon.com/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 实例上运行。

有关更多信息，请参阅《CloudFormation 模板参考指南**》中的 [CloudFormation 帮助程序脚本参考](https://docs.aws.amazon.com/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.aws.amazon.com/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.aws.amazon.com/AWSEC2/latest/UserGuide/ec2config-service.html#UsingConfigXML_WinAMI)
+ [EC2Launch v2 目录结构](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2launch-v2.html#ec2launch-v2-directory)

有关排查引导问题的更多信息，请参阅[如何排查无法在具有 Windows 实例的 CloudFormation 堆栈中引导的帮助程序脚本的问题？](https://repost.aws/knowledge-center/cloudformation-helper-scripts-windows)。