如何阻止我的 Amazon EC2 Windows 实例在完成引导之前发回 CREATE_COMPLETE 信号?
我正在使用 AWS CloudFormation 中的 cfn-init (cfn-init.exe) 和 cfn-signal (cfn-signal.exe) 帮助程序脚本引导 Amazon Elastic Compute Cloud (Amazon EC2) Windows 实例。我的 cfn-init 脚本会过早返回信号。然后,AWS CloudFormation 在我的 Windows 实例完成引导之前便将其标记为 CREATE_COMPLETE。
简短描述
在 Windows 实例中,UserData 脚本由 Ec2ConfigService 进程执行。UserData 会调用 cfn-init.exe,它作为 Ec2ConfigService 的子进程运行。
您的 Windows 实例发回 CREATE_COMPLETE 信号可能是出于以下原因:
- 如果 cfn-init.exe 执行的步骤之一需要系统重启,则系统会关闭,然后将执行权交还给 Ec2ConfigService 进程。系统会继续处理 UserData 脚本,然后执行 cfn-signal.exe 来向 AWS CloudFormation 发回信号。
- cfn-signal 在重启后未发回信号,因为 UserData 仅运行一次。
在以下代码示例中,cfn-signal.exe 直接从 UserData 调用。如果 cfn-init.exe 进程执行重启,则无法调用 cfn-signal.exe 命令,因为 UserData 仅运行一次。
JSON 示例:
"UserData": { "Fn::Base64": { "Fn::Join": [ "", [ "<script>\n", "cfn-init.exe -v -s ", { "Ref": "AWS::StackId" }, " -r WindowsInstance", " --configsets ascending", " --region ", { "Ref": "AWS::Region" }, "\n", "cfn-signal.exe -e %ERRORLEVEL% --stack ", { "Ref": "AWS::StackId" }, " --resource WindowsInstance --region ", { "Ref": "AWS::Region" }, "\n", "</script>" ] ] } }
YAML 示例:
UserData: Fn::Base64: !Sub | <script> cfn-init.exe -v -s ${AWS::StackId} -r WindowsInstance --configsets ascending --region ${AWS::Region} cfn-signal.exe -e %ERRORLEVEL% --stack ${AWS::StackId} --resource WindowsInstance --region ${AWS::Region} </script>
解决方法
1. 使用模板中 cfn-init Metadata 部分的 configsets 将需要重启的配置和不需要重启的配置分开。
2. 将 cfn-signal.exe 从 AWS::EC2::Instance 或 AWS::AutoScaling::LaunchConfiguration 资源的 UserData 部分移至模板的 AWS::CloudFormation::Init Metadata 部分。
3. 执行 cfn-signal.exe 作为最后一个 configset 运行的最后一个命令。
4. 在 JSON 或 YAML 模板中将 UserData 更改为 cfn-init 并制定升序 configset。
JSON 示例:
{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "cfn-init example using configsets", "Parameters": { "AMI": { "Type": "AWS::EC2::Image::Id" } }, "Resources": { "WindowsInstance": { "Type": "AWS::EC2::Instance", "Metadata": { "AWS::CloudFormation::Init": { "configSets": { "ascending": [ "config1", "config2", "config3" ] }, "config1": { "files": { "C:\\setup\\setenvironment.ps1": { "content": { "Fn::Join": [ "", [ "$Folder = 'C:\\Program Files\\Server\\packages\\bin.20182.18.0826.0815\\'\n", "$OldPath = [System.Environment]::GetEnvironmentVariable('path')\n", "$NewPath = $OldPath + ';' + $Folder\n", "[System.Environment]::SetEnvironmentVariable('path',$NewPath,'Machine')" ] ] } } } }, "config2": { "commands": { "0-restart": { "command": "powershell.exe -Command Restart-Computer", "waitAfterCompletion": "forever" } } }, "config3": { "commands": { "01-setenvironment": { "command": "powershell.exe -ExecutionPolicy Unrestricted C:\\setup\\setenvironment.ps1", "waitAfterCompletion": "0" }, "02-signal-resource": { "command": { "Fn::Join": [ "", [ "cfn-signal.exe -e %ERRORLEVEL% --resource WindowsInstance --stack ", { "Ref": "AWS::StackName" }, " --region ", { "Ref": "AWS::Region" } ] ] } } } } } }, "Properties": { "ImageId": { "Ref": "AMI" }, "InstanceType": "t2.medium", "UserData": { "Fn::Base64": { "Fn::Join": [ "", [ "<script>\n", "cfn-init.exe -v -s ", { "Ref": "AWS::StackId" }, " -r WindowsInstance", " --configsets ascending", " --region ", { "Ref": "AWS::Region" }, "</script>" ] ] } } }, "CreationPolicy": { "ResourceSignal": { "Count": "1", "Timeout": "PT30M" } } } } }
YAML 示例:
AWSTemplateFormatVersion: '2010-09-09' Description: cfn-init example using configsets Parameters: AMI: Type: 'AWS::EC2::Image::Id' Resources: WindowsInstance: Type: 'AWS::EC2::Instance' Metadata: AWS::CloudFormation::Init: configSets: ascending: - config1 - config2 - config3 config1: files: C:\setup\setenvironment.ps1: content: !Sub | $Folder = 'C:\Program Files\Server\packages\bin.20182.18.0826.0815\' $OldPath = [System.Environment]::GetEnvironmentVariable('path') $NewPath = $OldPath + ';' + $Folder [System.Environment]::SetEnvironmentVariable('path',$NewPath,'Machine') config2: commands: 0-restart: command: powershell.exe -Command Restart-Computer waitAfterCompletion: forever config3: commands: 01-setenvironment: command: powershell.exe -ExecutionPolicy Unrestricted C:\setup\setenvironment.ps1 waitAfterCompletion: '0' 02-signal-resource: command: !Sub > cfn-signal.exe -e %ERRORLEVEL% --resource WindowsInstance --stack ${AWS::StackName} --region ${AWS::Region} Properties: ImageId: !Ref AMI InstanceType: t2.medium UserData: Fn::Base64: !Sub | <script> cfn-init.exe -v -s ${AWS::StackId} -r WindowsInstance --configsets ascending --region ${AWS::Region} </script> CreationPolicy: ResourceSignal: Count: 1 Timeout: PT30M
在前面的模板中,信号不再在 UserData 中运行,这意味着您无法检索 cfn-init 进程提供的退出代码。默认情况下,如果未从 UserData 或 Metadata 部分收到信号,AWS CloudFormation 无法创建或更新堆栈。然后堆栈会返回一个“timeout exceeded”错误。
**提示:**要进行问题排查,请使用 Windows 实例中位于 c:\cfn\log 位置的日志。
5. 将 waitAfterCompletion 参数设置为 forever。
**注意:**waitAfterCompletion 的默认值为 60 秒。如果您将该值更改为 forever,cfn-init 将退出,然后仅在重启完成后才恢复。
相关信息
相关内容
- AWS 官方已更新 2 年前
- AWS 官方已更新 10 个月前
- AWS 官方已更新 7 个月前
- AWS 官方已更新 2 年前