You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Boto3创建EC2实例时检测UserData脚本执行完成以拉取日志销毁实例

判断EC2实例启动完成且UserData脚本执行完毕的实现方案

1. 先改造UserData执行脚本(推荐)

在你现有的UserData脚本末尾添加执行状态标记,方便外部检测结果,不需要改现有逻辑,只需要追加以下代码:

# 原有脚本逻辑保持不变,仅在末尾追加
# 写入执行状态标记文件
if [ $? -eq 0 ]; then
    echo "success" > /var/log/user_data_exec_done
else
    echo "fail:$?" > /var/log/user_data_exec_done
fi

如果不想改脚本,也可以直接用cloud-init自带的状态检测能力,不需要加任何标记,后面检测的时候直接调用cloud-init命令即可。

2. 本地控制脚本检测逻辑

分两步完成检测:先确认实例本身正常启动,再确认UserData脚本执行完成。

2.1 检测实例正常启动

用Boto3自带的等待器,等实例进入running状态且系统、实例两级健康检查都通过,确保实例可正常连接:

import time
import paramiko

# 你的createInstances逻辑执行完拿到instances对象后,逐个处理
for instance in instances:
    # 等待实例进入运行状态
    instance.wait_until_running()
    # 刷新实例属性,获取公网IP等最新信息
    instance.reload()
    # 等待实例健康检查通过
    status_waiter = self.ec2_client.get_waiter('instance_status_ok')
    status_waiter.wait(InstanceIds=[instance.id])

2.2 检测UserData脚本执行完成

通过SSH连接实例,轮询状态标记或者cloud-init执行状态:

# 初始化SSH客户端
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 最长等待时间,根据你的脚本实际执行时长调整,这里设为30分钟
max_wait_seconds = 1800
start_time = time.time()
exec_result = False

while time.time() - start_time < max_wait_seconds:
    try:
        # 连接实例,注意替换为你的AMI对应默认用户名、私钥路径
        ssh.connect(
            hostname=instance.public_ip_address,
            username="ec2-user",
            key_filename="/path/to/your/aws_key_pair.pem"
        )
        # 方式1:如果前面加了自定义状态标记,用这个命令
        stdin, stdout, stderr = ssh.exec_command("cat /var/log/user_data_exec_done 2>/dev/null")
        exec_status = stdout.read().decode().strip()
        
        # 方式2:如果没改UserData脚本,用cloud-init自带命令检测,替换上面的exec_command即可
        # stdin, stdout, stderr = ssh.exec_command("cloud-init status --wait >/dev/null 2>&1 && echo success")
        # exec_status = stdout.read().decode().strip()

        if exec_status == "success":
            print(f"实例{instance.id}的UserData脚本执行成功")
            exec_result = True
            break
        elif exec_status.startswith("fail"):
            print(f"实例{instance.id}的UserData脚本执行失败,错误码:{exec_status.split(':')[-1]}")
            break
    except Exception:
        # 连接失败就等待10秒重试
        time.sleep(10)
        continue

# 检测完成后执行SCP拉取日志
if exec_result:
    # 用paramiko SFTPClient拉日志,或者调用系统scp命令
    sftp = ssh.open_sftp()
    sftp.get("/path/to/your/logfile.log", "./local_logfile.log")
    sftp.close()

# 最后销毁实例
instance.terminate()
ssh.close()

注意事项

  • 实例绑定的安全组入方向需要开放22端口,允许你运行控制脚本的机器IP访问,否则无法建立SSH连接
  • 不同AMI的默认用户名不同:Amazon Linux默认是ec2-user,Ubuntu默认是ubuntu,CentOS默认是centos,需要根据你用的镜像调整连接参数
  • 如果UserData脚本执行时长超过30分钟,需要对应调大max_wait_seconds的取值,避免超时误判

内容的提问来源于stack exchange,提问作者Arun Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 21:06:03