簡體   English   中英

通過 SSH 隧道端口轉發使用 Python 訪問 MySQL 數據庫

[英]Accessing MySQL database using Python over SSH Tunnel port forwarding

我在遠程服務器上有 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)")

我還通過參考Python 中的jsjc 解決方案- SSH Tunnel Setup and MySQL DB Access嘗試使用 sshtunnelforwarder,但它也不起作用。

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

這是我以前遇到的一個問題。 問題是當使用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', ...)

我不知道 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()

希望這對未來的任何人都有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM