参考资料
- https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-waitcondition.html
- https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-waitcondition.html
本文介绍cloudformation的waitcondition条件,waitcondition会使cdn堆栈停止并等待信号,从而协调堆栈相关资源创建和其他操作。
理解 waitcondition
注意:对于asg和ec2来说,创建createpolicy显然更好,只需要在资源配置完成后使用cfn-signal发送信号即可
amazon_linux.template
waitcondition
涉及到的cfn资源有
-
AWS::CloudFormation::WaitCondition
Fn::GetAtt Data,包含来自指定等待条件的等待条件信号的 UniqueId 和 Data 值
!GetAtt mywaitcondition.Data
-
AWS::CloudFormation::WaitConditionHandle
WaitConditionHandle 类型没有属性。当使用 Ref 函数引用 WaitConditionHandle 资源时,cfn返回一个指定的 URL。可以将此 URL 传递给在 AmazonEC2实例上运行的应用程序或脚本,以向该 URL 发送信号
!Ref mywaitconditionhandle
waitcondition
的使用场景如下
- 在应用程序配置过程中,埋点发送信号到cfn跟踪资源的创建进度
- 在资源的创建过程中触发其他资源部署,不需要等待创建完毕
- 等待资源内部创建逻辑完整运行后,才进行cfn的下一阶段部署
注意: cfn等待条件资源需要使用s3服务,向特定的presign url发送响应。否则cfn不会收到相关信息导致堆栈失败。因此如果无法访问公网,需要注意终端节点的配置是否正确
waitcondition
的工作流程
-
waitcondition
本身也是个资源,堆栈创建后处于CREATE_IN_PROGRESS
状态,直到收到指定数量信号,或超时和接受失败信号 -
如果超时则进入
CREATE_FAILED
状态,最大超时时间为43200秒 (12 hours ) -
将
DependsOn
属性添加到waitcondition
,则资源创建后堆栈立即停止 -
waitcondition
的Count
属性指定需要接受信号的数量,满足条件后进入CREATE_COMPLETE
状态,如果没有设置count则默认为1 -
waitcondition
需要相应的WaitConditionHandle
创建的presign url完成信号发送(json字符),避免了认证{ "Status" : "SUCCESS", "Reason" : "Configuration Complete", "UniqueId" : "ID1234", "Data" : "Application has completed configuration." }
-
发送信号的方式是HTTP请求,请求方法为
PUT
,Content-Type
标头为空$ cat > /tmp/a << EOF { "Status" : "SUCCESS", "Reason" : "Configuration Complete", "UniqueId" : "ID1234", "Data" : "Application has completed configuration." } EOF $ curl -T /tmp/a "https://cloudformation-waitcondition-cn-north-1.s3.cn-north-1.amazonaws.com.cn/arn%3Aaws-cn%3Acloudformation%3Acn-north-1%3A037047667284%3Astack/awstemp/52d456e0-9649-11ed-983f-025e4a0fdde2/mywaitconditionhandle?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230117T092841Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86399&X-Amz-Credential=AKIAOMTUJJXMXKXJZEPQ%2F20230117%2Fcn-north-1%2Fs3%2Faws4_request&X-Amz-Signature=0cb81d51fe65253e3dc7378b865b0dcae1370f512f275b4bf3f648f6cd05d298" $ curl -X PUT -H 'Content-Type:' --data-binary '{"Status" : "SUCCESS","Reason" : "Configuration Complete","UniqueId" : "ID1234","Data" : "Application has completed configuration."}' "https://cloudformation-waitcondition-test.s3.amazonaws.com/arn%3Aaws%3Acloudformation%3Aus-east-2%3A034017226601%3Astack%2Fstack-gosar-20110427004224-test-stack-with-WaitCondition--VEYW%2Fe498ce60-70a1-11e0-81a7-5081d0136786%2FmyWaitConditionHandle?Expires=1303976584&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Signature=ik1twT6hpS4cgNAw7wyOoRejVoo%3D"
-
waitcondition
的Handle
和TimeOut
属性是必须的
配置工具和测试堆栈
安装cfn帮助脚本
yum install -y aws-cfn-bootstrap
查看cfn-signal命令说明,常用的几个参数如下
$ /opt/aws/bin/cfn-signal
Usage: cfn-signal [options] [WaitConditionHandle URL]
Options:
-h, --help show this help message and exit
-s SUCCESS, --success=SUCCESS If true, signal success to CloudFormation; if false, signal failure. Default: true
-i ID, --id=ID A unique ID to send with the signal
-e EXIT_CODE, --exit-code=EXIT_CODE Derive success or failure from specified exit code
AWS Credentials:
Options for specifying AWS Account Credentials.
-f CREDENTIAL_FILE, --credential-file=CREDENTIAL_FILE A credential file, with keys 'AWSAccessKeyId' and 'AWSSecretKey'
--role=IAM_ROLE An IAM Role
--access-key=ACCESS_KEY An AWS Access Key
--secret-key=SECRET_KEY An AWS Secret Key
WaitConditionHandle Signal Options:
-r REASON, --reason=REASON The reason for success/failure
-d DATA, --data=DATA Data to include with the WaitCondition signal
Resource Signal Options:
--stack=STACK_NAME A CloudFormation stack
--resource=LOGICAL_RESOURCE_ID A CloudFormation logical resource ID
--url=ENDPOINT The CloudFormation service URL.
--region=REGION The CloudFormation region. Default: us-east-1.
在ec2的userdata中常见的用法,WebServerInstance
是ec2的资源逻辑id
yum install -y aws-cfn-bootstrap
/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region}
/opt/aws/bin/cfn-signal --exit-code $? --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region}
创建简单的堆栈
AWSTemplateFormatVersion: "2010-09-09"
Description: AWS CloudFormation test waitcondition.
Resources:
S3Bucket:
Type: AWS::S3::Bucket
Properties:
VersioningConfiguration:
Status: Suspended
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
mywaitconditionhandle:
Type: AWS::CloudFormation::WaitConditionHandle
mywaitcondition:
Type: AWS::CloudFormation::WaitCondition
DependsOn: S3Bucket
Properties:
Handle: !Ref "mywaitconditionhandle"
Timeout: "60"
Count: 1
Outputs:
WaitConditionUrl:
Description: WaitConditionUrl
Value: !Ref mywaitconditionhandle
WaitConditionData:
Description: WaitConditionData
Value: !GetAtt mywaitcondition.Data
查看控制台的cfn事件如下
创建了特定的资源,handle的逻辑id很有趣,是一个s3预签名url
事件卡在了创建等待条件上,这里设定60秒超时查看超时状态的结果
手动发送信号
将超时时间修改为1800秒,尝试手动发送失败信号
通过cfn-signal
发送
可见如果通过cfn-signal
发送信号,那么实例id会自动作为UID,需要权限才能向cfn发送信号,这里直接指定aksk。
但是发了很多次,无论是success还是failure还是堆栈都没反应
$ /opt/aws/bin/cfn-signal --exit-code 1 --stack awstemp --resource mywaitcondition --region cn-north-1
Could not open /var/log/cfn-init.log for logging. Using stderr instead.
2023-01-17 09:30:59,853 [DEBUG] CloudFormation client initialized with endpoint https://cloudformation.cn-north-1.amazonaws.com.cn
2023-01-17 09:30:59,854 [DEBUG] Signaling resource mywaitcondition in stack awstemp with unique ID i-017ff62b060a71f0a and status FAILURE
AccessDenied: Instance i-01xxxxxxxx0a is not allowed to call SignalResource for awstemp
$ /opt/aws/bin/cfn-signal --exit-code 1 --stack awstemp --resource mywaitcondition --region cn-north-1 --access-key=AKxxxxxxxxxxxxT4 --secret-key=lVw4xxxxxxxxxxxxxxxizLW
Could not open /var/log/cfn-init.log for logging. Using stderr instead.
2023-01-17 09:35:30,693 [DEBUG] CloudFormation client initialized with endpoint https://cloudformation.cn-north-1.amazonaws.com.cn
2023-01-17 09:35:30,694 [DEBUG] Signaling resource mywaitcondition in stack awstemp with unique ID i-017ff62b060a71f0a and status FAILURE
$ /opt/aws/bin/cfn-signal -i uid1234567 --exit-code 0 --stack awstemp1 --resource mywaitcondition --region cn-north-1 --access-key=AKxxxxxxxxxxxxT4 --secret-key=lVw4xxxxxxxxxxxxxxxizLW
Could not open /var/log/cfn-init.log for logging. Using stderr instead.
2023-01-17 10:12:06,024 [DEBUG] CloudFormation client initialized with endpoint https://cloudformation.cn-north-1.amazonaws.com.cn
2023-01-17 10:12:06,025 [DEBUG] Signaling resource mywaitcondition in stack awstemp1 with unique ID uid1234567 and status SUCCESS
测试后以下方式可以发送
$ /opt/aws/bin/cfn-signal --exit-code 0 --reason="test cfn-signal" "https://cloudformation-waitcondition-cn-north-1.s3.cn-north-1.amazonaws.com.cn/arn%3Aaws-cn%3Acloudformation%3Acn-north-1%3A037047667284%3Astack/awstemp/e84fa070-9686-11ed-8472-0e622fd9393a/mywaitconditionhandle?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230117T164931Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86399&X-Amz-Credential=AKIAOMTUJJXMXKXJZEPQ%2F20230117%2Fcn-north-1%2Fs3%2Faws4_request&X-Amz-Signature=d63b30eadb3238ab762bc1d6fb9e84df83bf3bc30d789729a8f80fcfc0d5de5d"
Could not open /var/log/cfn-init.log for logging. Using stderr instead.
CloudFormation signaled successfully with %s.
使用aws cli发送信号
https://docs.aws.amazon.com/cli/latest/reference/cloudformation/signal-resource.html#examples
如果资源不存在则报错
$ aws cloudformation signal-resource --stack-name awstemp --logical-resource-id mywaitconditio --unique-id uuid123456 --status SUCCESS
An error occurred (ValidationError) when calling the SignalResource operation: Resource mywaitconditio does not exist for stack awstemp1
发送成功信号,发了很多次,无论是success还是failure还是堆栈也都没反应
$ aws cloudformation signal-resource \
--stack-name awstemp \
--logical-resource-id mywaitcondition \
--unique-id uuid123456 \
--status SUCCESS
使用http请求发送信号
这种方式更够触发堆栈信号
$ curl -T /tmp/a "https://cloudformation-waitcondition-cn-north-1.s3.cn-north-1.amazonaws.com.cn/arn%3Aaws-cn%3Acloudformation%3Acn-north-1%3A037047667284%3Astack/awstemp/6b872d70-964e-11ed-a57a-0e1ccbbaa2e8/mywaitconditionhandle?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230117T100510Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86399&X-Amz-Credential=AKIAOMTUJJXMXKXJZEPQ%2F20230117%2Fcn-north-1%2Fs3%2Faws4_request&X-Amz-Signature=31ec53a42ed56e3481fbdbd9eef3a7867c34c62d9a8e74c7bbfbeb63b6d9d861"
继续通过http请求发信号测试
如果发送失败信号,则堆栈失败
如果发送success和failure之外的状态信号,则报错
而且发信号之后到接收信号开始处理有一定的延迟,并非是立即执行的
此外,对于在cdk中使用waitcondition,找到一篇文章可以参考
https://9incloud.com/aws/cdk-aws-codedeploy-autoscaling-waitcondition-creationpolicy