Python 使用Paramiko尝试SSH到新的EC2实例时出现问题

Python 使用Paramiko尝试SSH到新的EC2实例时出现问题,python,amazon-ec2,paramiko,boto,Python,Amazon Ec2,Paramiko,Boto,我正在编写一个脚本,该脚本使用boto启动一个新的EC2实例,并使用Paramiko SSH客户端在该实例上执行远程命令。无论出于何种原因,Paramiko客户端无法连接,我得到错误: Traceback (most recent call last): File "scripts/sconfigure.py", line 29, in <module> ssh.connect(instance.ip_address, username='ubuntu', key_fil

我正在编写一个脚本,该脚本使用boto启动一个新的EC2实例,并使用Paramiko SSH客户端在该实例上执行远程命令。无论出于何种原因,Paramiko客户端无法连接,我得到错误:

Traceback (most recent call last):
  File "scripts/sconfigure.py", line 29, in <module>
    ssh.connect(instance.ip_address, username='ubuntu', key_filename=os.path.expanduser('~/.ssh/test'))
  File "build/bdist.macosx-10.3-fat/egg/paramiko/client.py", line 291, in connect
  File "<string>", line 1, in connect
socket.error: [Errno 61] Connection refused

我似乎已经通过反复试验弄明白了这一点。根据boto,即使实例状态为“正在运行”,但它实际允许SSH连接的时间也会有延迟。在“ssh.connect(…)”之前添加一个“time.sleep(30)”,似乎对我来说很管用,尽管这可能有所不同。

我最近遇到了这个问题。“正确”的方法是首先启动close(),然后重新打开连接。但是,在旧版本中,close()被破坏

对于此版本或更高版本,应将其修复:

“适当”方法:

newinstance=image.run(最小计数=instancenum,最大计数=instancenum,密钥名=keypair,安全组=security组,用户数据=instancename,实例类型=instancetype,位置=zone)
时间。睡眠(2)
newinstance.instances[0]。添加_标记('Name',instancename)
打印“等待公共\u dns\u名称…”
计数器=0
当计数器<70时:
时间。睡眠(1)
康涅狄格州关闭
conn=boto.ec2.connection.ec2连接(ec2auth.access\u密钥,ec2auth.private\u密钥)
startedinstance=conn.get_所有_实例(实例_id=str(newinstance.instances[0].id))[0]
计数器=计数器+1
如果str(startedinstance.instances[0].state)=“正在运行”:
打破
如果计数器==69:
打印“等待实例启动时超时”
打印“已添加:”+startedinstance.instances[0]。标记['Name']+”“+startedinstance.instances[0]。公共\u dns\u名称

为什么不改用
boto.manage.cmdshell

cmd = boto.manage.cmdshell.sshclient_from_instance(instance,
                                                   key_path,
                                                   user_name='ec2_user')
(代码取自中的第152行)


对于可用的
cmdshell
命令,请查看来自的
SSHClient
类。

检查其ssh可用性的方法是确保其两个状态检查两个过程。在web UI上,它如下所示:

使用boto3(最初的问题使用boto,但那是5年前),我们可以做到:

session = boto3.Session(...)
client = session.client('ec2')
res = client.run_instances(...) # launch instance
instance_id = res['Instances'][0]['InstanceId']

while True:
    statuses = client.describe_instance_status(InstanceIds=[instance_id])
    status = statuses['InstanceStatuses'][0]
    if status['InstanceStatus']['Status'] == 'ok' \
            and status['SystemStatus']['Status'] == 'ok':
        break
    print '.'
    time.sleep(5)
print "Instance is running, you are ready to ssh to it"

我最近查看了此代码,并对代码提出了建议, 您可以尝试“wait_until_running()”,而不是运行while循环来检查实例是否正在运行

下面是示例代码

client = boto3.resource(
    'ec2',
    region_name="us-east-1"
)

Instance_ID = "<your Instance_ID>"
instance = client.Instance(Instance_ID)
instance.start()
instance.wait_until_running()
client=boto3.resource(
“ec2”,
地区名称=“us-east-1”
)
实例_ID=“”
instance=client.instance(实例ID)
instance.start()
实例。请等待,直到\u正在运行()

然后尝试编写ssh连接代码。

+1问得好!我从来没有对我的EC2帐户做过任何事情,这会给我一些动力。您是否尝试过将端口指定为ssh.connect()中的第二个参数?谢谢您的建议,但我做过。不过我相信我已经弄明白了。根据boto,即使实例状态为“正在运行”,但它实际接受任何SSH连接的时间似乎也有延迟。在尝试建立连接之前添加一个time.slep(25)似乎已经足够了,但我要做更多的测试。太好了!一旦你让它工作,也许你可以回答你自己的问题,所以它在那里为下一个家伙谁碰到这个!确切地睡眠(60)可以解决问题。但是你的密码启发了我关于帕拉米科的部分。谢谢,伙计。“运行”可能意味着图像本身正在启动?所以你必须等待操作系统启动,sshd启动。是的,这是最有意义的。我和你一样做(45秒:p),这是我发现的唯一方法,即使我不喜欢睡觉(x),你也不需要这样做。您可以尝试多次连接并捕获异常。我成功地实现了与帕拉米科的合作。天哪,这太令人沮丧了!谢谢@rr!!我使用的是boto的
sshclient\u from\u instance
,显然它依赖于paramiko。我只是觉得这不是一个好的错误消息和API设计。它不应该那么神秘-除非这个用例很少见,也许吧?我不明白为什么每次通过循环都要创建一个新的连接。这段代码()每次都使用相同的连接执行类似的循环。我从来没有遇到过这种模式的问题。问题是,初始连接是缓存的。因此,除非您关闭并重新打开连接,否则它不会重新检查更新。这就是我在测试中发现的。我还没和boto的人谈过这件事我试过了。注意:在这两种状态从“初始化”切换到“确定”之前,可以通过ssh连接到节点。因此,如果您的代码不耐烦,希望尽快使用ssh,那么使用不同的技术可能会更好。
session = boto3.Session(...)
client = session.client('ec2')
res = client.run_instances(...) # launch instance
instance_id = res['Instances'][0]['InstanceId']

while True:
    statuses = client.describe_instance_status(InstanceIds=[instance_id])
    status = statuses['InstanceStatuses'][0]
    if status['InstanceStatus']['Status'] == 'ok' \
            and status['SystemStatus']['Status'] == 'ok':
        break
    print '.'
    time.sleep(5)
print "Instance is running, you are ready to ssh to it"
client = boto3.resource(
    'ec2',
    region_name="us-east-1"
)

Instance_ID = "<your Instance_ID>"
instance = client.Instance(Instance_ID)
instance.start()
instance.wait_until_running()