【问题标题】:Accessing MySQL database using Python over SSH Tunnel port forwarding通过 SSH 隧道端口转发使用 Python 访问 MySQL 数据库
【发布时间】:2016-03-18 16:40:42
【问题描述】:

我在远程服务器上有 MySQL 数据库,在访问它之前,我需要使用 ssh 隧道进行端口转发。如果没有 python,我通常会执行以下命令并在 shell 中输入我的密码。一旦通过身份验证,我通过连接到 localhost:3306 访问 mysql 工作台中的数据库。我用我的 Mac OS X El Capitan 做所有事情

ssh -L 3306:remote.database.host:3306 xxxx@xxxx.com

我现在想从 Python 访问数据库,这是我使用的脚本:

import pexpect
import time
import sqlalchemy as sql
from sqlalchemy.engine.url import URL

myDB = URL(drivername='mysql+pymysql', host='localhost',
database='test_db',
username='roott',
password='xxxxxx',
port=3306)

child = pexpect.spawnu('ssh -L 3306:remote.database.host:3306 xxxx@xxxx.com')
child.expect (u'password:')
child.sendline ('xxxxx')

while child.isalive():
    try:
    engine = sql.create_engine(name_or_url=myDB)
    connection = engine.connect()
    connection.close()
    break
finally:
    child.close()

上面的脚本给了我以下错误:

sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2003, "Can't connect to MySQL server on 'localhost' ([Errno 61] Connection refused)")

我也尝试使用 sshtunnelforwarder,参考 jsjc 在 Python - SSH Tunnel Setup and MySQL DB Access 的解决方案,它也不起作用。

from sshtunnel import SSHTunnelForwarder
from sqlalchemy import create_engine
from sqlalchemy.engine.url import URL

with SSHTunnelForwarder(('ssh_host', 22),
                    ssh_username='xxxxx',
                    ssh_pkey='/path/to/key/file',
                    local_bind_address=('127.0.0.1', 3306),
                    remote_bind_address=('127.0.0.1', 3306)) as server:


myDB = URL(drivername='mysql+pymysql', host='127.0.0.1',
           database='test_db',
           username='roott',
           password='xxxxx',
           port=3306
           )

engine = create_engine(name_or_url=myDB)
connection = engine.connect()    
connection.close()

我将以下信息登录到控制台,但没有任何反应,它只是挂在那里,我必须手动终止程序。

DEBUG:paramiko.transport:starting thread (client mode): 0xbe25940
DEBUG:paramiko.transport:Local version/idstring: SSH-2.0-paramiko_1.16.0
DEBUG:paramiko.transport:Remote version/idstring: SSH-2.0-OpenSSH_6.2
INFO:paramiko.transport:Connected (version 2.0, client OpenSSH_6.2)
DEBUG:paramiko.transport:........
DEBUG:paramiko.transport:Kex agreed: diffie-hellman-group1-sha1
DEBUG:paramiko.transport:Cipher agreed: aes128-ctr
DEBUG:paramiko.transport:MAC agreed: hmac-sha2-256
DEBUG:paramiko.transport:Compression agreed: none
DEBUG:paramiko.transport:kex engine KexGroup1 specified hash_algo <built-in function openssl_sha1>
DEBUG:paramiko.transport:Switch to new keys ...
DEBUG:paramiko.transport:Attempting public-key auth...
DEBUG:paramiko.transport:userauth is OK
INFO:paramiko.transport:Auth banner: b'Amazon Linux AMI release 2014.09\nKernel \\r on an \\m\n'
INFO:paramiko.transport:Authentication continues...
DEBUG:paramiko.transport:Methods: ['password']
DEBUG:paramiko.transport:[chan 0] Max packet in: 32768 bytes
WARNING:paramiko.transport:Oops, unhandled type 3

【问题讨论】:

    标签: python mysql sqlalchemy paramiko pexpect


    【解决方案1】:

    这是我之前遇到的一个问题。问题是当使用localhost作为数据库服务器时,驱动坚持连接到本地unix套接字,而不是使用指定端口通过环回接口连接。

    解决方法是将数据库服务器更改为 除了 localhost。这将导致驱动程序使用您指定的服务器/端口,而不是尝试连接到本地套接字。

    myDB = URL(drivername='mysql+pymysql', host='127.0.0.1', ...)
    myDB = URL(drivername='mysql+pymysql', host='your.ip.add.ress', ...)
    myDB = URL(drivername='mysql+pymysql', host='your.hostname', ...)
    

    【讨论】:

    • 我只有对数据库服务器的读取权限,并且无法将其更改为 localhost 以外的其他内容。还有其他选择吗?
    • @user2714753 我不是在谈论更改数据库服务器。我说的是在 python 脚本中将您的输入参数更改为您的驱动程序,以便它实际使用您要求的端口。
    • 抱歉给您带来了困惑。我厌倦了我的 ipaddress 和主机名,终端只是挂了一会儿然后抛出这个错误。 sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2013, 'Lost connection to MySQL server during query')
    【解决方案2】:

    如果 OP 已经解决了问题(已经 3 年了,所以我希望如此),但我的解决方案非常简单。我只需要在“with”子句中缩进 myDB、引擎和连接定义。否则,ssh 隧道将在您有机会连接到数据库之前关闭:

    with SSHTunnelForwarder(('ipforsshing', sshport), ssh_username='sshuser', ssh_pkey='privatekeypath', local_bind_address=('127.0.0.1', 3305), remote_bind_address=('127.0.0.1', 3306)) as server:
        adcrawl_db = URL(drivername='mysql+pymysql', host='127.0.0.1', database='dbname', username='dbusername',password='dbpassword', port=3305)
    
        engine = create_engine(name_or_url=adcrawl_db)
        connection = engine.connect()
        print("CONNECTED!")
        connection.close()
    

    希望这对将来的任何人都有帮助。

    【讨论】:

      猜你喜欢
      • 2016-09-08
      • 2017-12-26
      • 2020-01-28
      • 2019-07-15
      • 2012-10-10
      • 2013-02-05
      • 2015-04-02
      • 2016-02-07
      • 2013-08-21
      相关资源
      最近更新 更多