AWS CDK部署Linux EC2实例:重启后cfn-signal执行异常
问题根源
你遇到的问题核心在于Linux和Windows上的CloudFormation Init执行机制差异:Windows的cfn-init在实例重启后会自动恢复执行未完成的Config Set步骤,但Linux的cfn-init是一次性执行的——重启会直接终止当前的cfn-init进程,且重启后不会自动续上之前的流程。
从你的cfn-init.log就能看出来:日志里显示的Running config cfn-signal是重启前执行的,但reboot命令会立即终止所有进程,导致cfn-signal根本没来得及完成发送信号的操作,而重启后没有机制触发它再次执行,最终CloudFormation栈因为收不到信号超时失败。
解决方案
要让Linux实例重启后自动发送cfn-signal,你需要把信号发送逻辑设置为开机自启动任务,而不是依赖Config Set的后续步骤。下面是具体的CDK代码修改方案:
修改后的CDK代码
testInit = ec2.CloudFormationInit.from_config_sets( config_sets={ "test_configsets" : ["change_hostname", "reboot"] }, configs={ "change_hostname" : ec2.InitConfig([ # 修改主机名 ec2.InitCommand.shell_command("> /etc/hostname ; echo testInstance > /etc/hostname", key = "change_hostname"), # 创建systemd服务文件,用于开机时发送CFN信号 ec2.InitFile.from_string( file_name="/etc/systemd/system/cfn-signal-on-boot.service", content=core.Fn.sub(""" [Unit] Description=Send CloudFormation success signal after system boot After=network.target [Service] Type=oneshot ExecStart=/opt/aws/bin/cfn-signal -e 0 --stack ${AWS::StackId} --resource TestInstance --region ${AWS::Region} RemainAfterExit=true [Install] WantedBy=multi-user.target """), key="cfn-signal-service-file" ), # 启用该systemd服务,确保开机自动执行 ec2.InitCommand.shell_command("systemctl enable cfn-signal-on-boot.service", key="enable-signal-service") ]), "reboot" : ec2.InitConfig([ ec2.InitCommand.shell_command("reboot", key = "reboot") ]) } )
方案说明
- 移除原有的
cfn-signalConfig Set:不再依赖Config Set的后续步骤,避免重启前执行信号发送被中断。 - 添加systemd自启动服务:
- 创建一个systemd服务文件,指定在网络就绪后执行
cfn-signal命令,确保网络可用后再发送信号 - 通过
systemctl enable设置服务开机自启,保证实例重启后自动触发
- 创建一个systemd服务文件,指定在网络就绪后执行
- 重启实例:修改主机名并配置好自启动任务后,执行重启操作。实例重启后,systemd会自动触发信号发送,CloudFormation就能收到完成信号,栈创建成功。
额外优化建议
- 如果你觉得systemd配置太繁琐,也可以用
crontab的@reboot任务替代:
不过systemd是Linux系统的标准服务管理工具,可靠性更高。ec2.InitCommand.shell_command(core.Fn.sub("echo '@reboot /opt/aws/bin/cfn-signal -e 0 --stack ${AWS::StackId} --resource TestInstance --region ${AWS::Region}' >> /var/spool/cron/root"), key="add-cron-signal") - 修改主机名时,建议同时执行
hostnamectl set-hostname testInstance让主机名即时生效(虽然重启后也会生效,但即时生效能避免一些中间状态问题)。
内容的提问来源于stack exchange,提问作者Sheldon Carter
相关产品推荐
相关产品推荐

