ブートストラップを完了する前の Amazon EC2 Windows インスタンスが、 CREATE_COMPLETE シグナルを返さないようにするにはどうしたらよいですか?
最終更新日: 2020 年 2 月 11 日
AWS CloudFormation のヘルパースクリプトである cfn-init (cfn-init.exe) と cfn-signal (cfn-signal.exe) を使用して、Amazon Elastic Compute Cloud (Amazon EC2) Windows インスタンスをブートストラップしています。cfn-init スクリプトのシグナルが早く返されすぎます。さらに、この Windows インスタンスがブートストラップを完了する前に、AWS CloudFormation において CREATE_COMPLETE としてマークされてしまいます。
簡単な説明
Windows インスタンスでは、UserData スクリプトを Ec2ConfigService プロセスが実行します。UserData が cfn-init.exe を呼び出します。これは Ec2ConfigService の子プロセスとして実行されます。
次の理由により、Windows インスタンスが CREATE_COMPLETE としてシグナルを返している可能性があります。
- cfn-init.exe で実行される 1 段階処理でシステムの再起動を必要とする場合、システムはシャットダウンしてから、実行を Ec2ConfigService プロセスに返すことができます。システムは UserData スクリプトの処理を続行してから cfn-signal.exe を実行し、AWS CloudFormation にシグナルを返します。
- UserData は 1 度しか実行されないため、再起動後に cfn-signal がシグナルを送り返しません。
以下のコード例では、cfn-signal.exe は UserData から直接呼び出されます。cfn-init.exe プロセスが再起動した場合、UserData は 1 度しか実行されないため、cfn-signal.exe コマンドを呼び出すことはできません。
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. AWS::EC2::Instance または AWS::AutoScaling::LaunchConfiguration のリソースにある UserData セクションから、テンプレートの AWS::CloudFormation::Init Metadata セクションに cfn-signal.exe を移動します。
3. 最後の configset が実行した最後のコマンドとして cfn-signal.exe を実行します。
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 パラメータを 永続的に設定します。
注: waitAfterCompletion のデフォルト値は 60 秒です。値を永久に変更すると、cfn-init は終了し、再起動の完了後に再び開始します。