CloudFormation创建EC2后,如何获取UserData执行完成的回调通知?
更好的方式跟踪EC2 UserData执行完成状态
这确实是个挺闹心的痛点——EC2实例显示“就绪”后UserData才开始跑,而且日志还要等执行完才全量出来,循环轮询实在太折腾人了。这里有几个更优雅的方案,能让你及时收到完成通知,不用再盯着日志刷新:
1. 用CloudWatch EventBridge发送自定义事件
在你的UserData脚本最后,加一段调用AWS CLI发送自定义事件的代码,一旦脚本执行完,就会触发这个事件:
# 获取当前实例ID INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) # 发送自定义事件到EventBridge aws events put-events --entries '[ { "Source": "ec2.userdata", "DetailType": "UserDataExecutionCompleted", "Detail": "{\"InstanceId\": \"'"$INSTANCE_ID"'\", \"Status\": \"Success\"}", "EventBusName": "default" } ]'
然后你可以在AWS控制台或者CloudFormation里创建一个EventBridge规则,把这个事件路由到SNS(发邮件/短信)、Lambda(执行后续操作)或者其他服务,一旦事件触发,立刻就能收到通知。
注意:要给EC2实例绑定的IAM角色加上events:PutEvents的权限,不然脚本没法发送事件。
2. 写入SSM参数作为状态标记
在UserData结尾写入一个SSM参数,用它来标记执行完成:
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) aws ssm put-parameter \ --name "/ec2/userdata/status/$INSTANCE_ID" \ --type "String" \ --value "COMPLETED" \ --overwrite
之后你可以用aws ssm get-parameter --name "/ec2/userdata/status/$INSTANCE_ID"快速查询状态,或者在CloudFormation里配置一个触发器,当这个参数存在时触发后续操作。同样要给EC2角色加ssm:PutParameter的权限。
3. 直接用SNS发送通知(最简单粗暴)
如果不需要复杂的流程,直接在脚本末尾调用SNS发送消息到你的邮箱或者手机:
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) aws sns publish \ --topic-arn "arn:aws:sns:你的区域:你的账号ID:UserDataCompletionTopic" \ --message "EC2实例 $INSTANCE_ID 的UserData执行完成啦!"
提前创建好SNS主题并订阅你的联系方式,再给EC2角色加sns:Publish权限,就能直接收到通知,连轮询都省了。
4. 让CloudFormation栈等待UserData完成(进阶)
如果希望整个CloudFormation栈只有在UserData执行完后才标记为CREATE_COMPLETE,可以用自定义资源:
- 在UserData脚本最后,调用一个部署好的Lambda函数(通过API Gateway暴露的端点),把实例ID和执行状态传过去。
- 自定义资源会等待Lambda的回调信号,只有收到成功回调后,CloudFormation才会认为栈创建完成。
这个方法适合需要严格保证UserData完成后再进行后续部署的场景,不过配置会稍微复杂一点。
额外小贴士
- 别忘了在脚本里加错误处理:比如如果安装CloudWatch/CodeDeploy代理失败,也要发送一个失败状态的通知,这样你能及时排查问题。
- 所有调用AWS服务的命令,都要确保EC2实例的IAM角色有对应的权限,不然会执行失败。
内容的提问来源于stack exchange,提问作者Justin
相关产品推荐
相关产品推荐

