Python通過跳板機(jī)訪問數(shù)據(jù)庫的方法
什么是跳板機(jī)?
跳板機(jī)(Jump Server):也稱堡壘機(jī),是一類可作為跳板批量操作的遠(yuǎn)程設(shè)備的網(wǎng)絡(luò)設(shè)備,是系統(tǒng)管理員和運(yùn)維人員常用的操作平臺(tái)之一。
那么具體是做什么的呢?
現(xiàn)在一些比較大的互聯(lián)網(wǎng)企業(yè),往往擁有大量的服務(wù)器,為了能夠統(tǒng)一方便管理,運(yùn)維人員通過跳板機(jī)去管理對(duì)應(yīng)的服務(wù)器。我們在訪問服務(wù)器的時(shí)候,先通過登陸跳板機(jī),然后再進(jìn)入相應(yīng)服務(wù)器。從一定程度上提升了服務(wù)器的數(shù)據(jù)安全性,也提升了服務(wù)器的可維護(hù)性。
sshtunnel 連接堡壘機(jī)
跳板機(jī)的本質(zhì)還是ssh連接,通過paramiko 自己造輪子的話理論也是可以實(shí)現(xiàn)的,這邊推薦 sshtunnel 這個(gè)包,省的自己寫了。
理解了跳板機(jī)的原理,這邊的配置就比較好理解了。拿這張圖舉例,首先需要先訪問跳板機(jī),其實(shí)就是最常見的ssh連接,可以是賬戶密碼,也可以是密鑰登錄的,如果是密鑰的話需要在 跳板機(jī)的.ssh 目錄下的某個(gè)許可文件中添加上自己的公鑰

最后還需要補(bǔ)充一下 目標(biāo)主機(jī)的ip 和端口。理解了這些,以下的這些參數(shù)就知道怎么配置了,
local_bind_address 可以不配置,不配置會(huì)隨機(jī)獲取本地的端口號(hào),如果指定的話就會(huì)占用本地固定的端口號(hào),推薦配置這一參數(shù)。
填寫本地的端口是因?yàn)檫@邊會(huì)將目標(biāo)服務(wù)器ip的端口映射為本地端口,然后訪問本地端口就能實(shí)現(xiàn)目標(biāo)端口的訪問了。
from sshtunnel import SSHTunnelForwarder
server = SSHTunnelForwarder(
(host_jump, int(port_jump)), # 跳板機(jī)的配置
ssh_pkey=ssh_pk_jump,
#密鑰的訪問方式,如果是密碼 ssh_password=???
ssh_username=user_name_jump,
remote_bind_address=(host_mysql, int(port_mysql))) # 數(shù)據(jù)庫服務(wù)器的配置
local_bind_address=(local_ip, local_port) # 開啟本地轉(zhuǎn)發(fā)端口
)
server.start()
server.close()
有些人習(xí)慣用 上下文管理器,看起來更舒服些
from sshtunnel import SSHTunnelForwarder
with SSHTunnelForwarder(
(host_jump, int(port_jump)), # 跳板機(jī)的配置
ssh_pkey=ssh_pk_jump,
#密鑰的訪問方式,如果是密碼 ssh_password=???
ssh_username=user_name_jump,
remote_bind_address=(host_mysql, int(port_mysql))) # 數(shù)據(jù)庫服務(wù)器的配置
local_bind_address=(local_ip, local_port) # 開啟本地轉(zhuǎn)發(fā)端口
)as server
server.start()
連接數(shù)據(jù)庫
建立好通道后就能通過本地映射的端口訪問目標(biāo)的數(shù)據(jù)庫端口了。
常見的mysql 數(shù)據(jù)庫訪問 比如 mysqldb,pymysql,mysql.connector,
mysqldb跟 pymysql 差不多,只不過前者適用python2的版本,后者適用python3的版本,mysql.connector是官方推薦的。
pymysql 跟 mysql.connector 還是有一些區(qū)別的
我這邊使用的是 mysql.connector ,在實(shí)踐中老是無法連接上,而pymysql卻是可以的。
最終終于找到了解決辦法。。。

以下是我的mysql.connector 連接數(shù)據(jù)庫的樣例。
with SSHTunnelForwarder(
(host_jump, int(port_jump)), # 跳板機(jī)的配置
ssh_pkey=ssh_pk_jump,
#密鑰的訪問方式,如果是密碼 ssh_password=???
ssh_username=user_name_jump,
remote_bind_address=(host_mysql, int(port_mysql))) # 數(shù)據(jù)庫服務(wù)器的配置
local_bind_address=(local_ip, local_port) # 開啟本地轉(zhuǎn)發(fā)端口
)as server
server.start()
conn = mysql.connector.connect(**{'host': '127.0.0.1',
'port': server.local_bind_port,
'user': dbcfg["user"],
'password': dbcfg["password"],
'db': dbcfg["db"],
'charset': dbcfg["charset"],
'collation': dbcfg["collation"],
'use_unicode': dbcfg["use_unicode"],
'use_pure': True})
cursor = conn.cursor(dictionary=True)
cursor.execute(sql, params)
rows = cursor.fetchall()
# conn.commit()
cursor.close()
conn.close()
這樣,數(shù)據(jù)庫就能正常訪問啦
代碼重構(gòu)和優(yōu)化
首先,就上面這樣的代碼而言,在每次查詢都需要進(jìn)行跳板機(jī)的連接,對(duì)于短時(shí)間突然大量請(qǐng)求的情況,這種是效率極低的。所以最好是能夠?qū)⒔⒐艿辣4嫦聛怼?br /> 其次,如果同時(shí)訪問多種數(shù)據(jù)庫的情況,存在有無跳板機(jī)的場景,所以最好能夠先將所有的數(shù)據(jù)庫都進(jìn)行連接,將conn保存在字典中,根據(jù)要訪問的機(jī)器調(diào)用對(duì)應(yīng)的conn,最后再統(tǒng)一釋放。
def get_slave_conn_byProxy(dbcfg):
server = SSHTunnelForwarder(
eval(dbcfg["addr"]),
ssh_username=dbcfg["ssh_username"],
ssh_pkey=os.getenv("HOME") + "/.ssh/id_rsa",
remote_bind_address=eval(dbcfg["remote_bind_address"]),
local_bind_address=eval(dbcfg["local_bind_address"]) # 開啟本地轉(zhuǎn)發(fā)端口
)
server.start()
conn = get_db_connection({'host': '127.0.0.1',
'port': server.local_bind_port,
'user': dbcfg["user"],
'password': dbcfg["password"],
'db': dbcfg["db"],
'charset': dbcfg["charset"],
'collation': dbcfg["collation"],
'use_unicode': dbcfg["use_unicode"],
'use_pure': True})
return server, conn
def get_db_connection(dbcfg):
# logger.info(f"============ debug db config: {dbcfg}")
conn = mysql.connector.connect(**dbcfg)
return conn
# 通過輸入的連接參數(shù)判斷是否需要通過跳板機(jī)的方式
def get_slave_conn(dbcfg):
if "addr" in dbcfg:
return get_slave_conn_byProxy(dbcfg)
else:
conn = get_db_connection(dbcfg)
return None, conn
def read_slave_db_data(sql, conn, params=None, use_pdf=True):
cursor = conn.cursor(dictionary=True)
cursor.execute(sql, params)
rows = cursor.fetchall()
# conn.commit()
cursor.close()
if use_pdf:
return pd.DataFrame(rows)
else:
return rows
到此這篇關(guān)于Python通過跳板機(jī)訪問數(shù)據(jù)庫的文章就介紹到這了,更多相關(guān)Python跳板機(jī)訪問數(shù)據(jù)庫內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python入門基礎(chǔ)之?dāng)?shù)字字符串與列表
這篇文章主要給大家介紹了關(guān)于Python入門基礎(chǔ)之?dāng)?shù)字字符串與列表的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
python爬蟲開發(fā)之urllib模塊詳細(xì)使用方法與實(shí)例全解
這篇文章主要介紹了python爬蟲開發(fā)之urllib模塊詳細(xì)使用方法與實(shí)例全解,需要的朋友可以參考下2020-03-03
一文帶你深入理解python中pytest-repeat插件的工作原理
這篇文章主要和大家一起深入探討到底pytest_repeat插件的具體功能是如何實(shí)現(xiàn)的呢,相信具體了解了該插件,其他三方插件也可以很快了解它內(nèi)部運(yùn)行機(jī)制,所以本文詳細(xì)講解了python pytest-repeat插件的工作原理,需要的朋友可以參考下2023-09-09
Python3數(shù)據(jù)庫操作包pymysql的操作方法
這篇文章主要介紹了Python3數(shù)據(jù)庫操作包pymysql的操作方法,文章通過實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下2018-07-07
Python3實(shí)現(xiàn)統(tǒng)計(jì)單詞表中每個(gè)字母出現(xiàn)頻率的方法示例
這篇文章主要介紹了Python3實(shí)現(xiàn)統(tǒng)計(jì)單詞表中每個(gè)字母出現(xiàn)頻率的方法,涉及Python針對(duì)文件的讀取、遍歷、統(tǒng)計(jì)等相關(guān)操作技巧,需要的朋友可以參考下2019-01-01
python函數(shù)缺省值與引用學(xué)習(xí)筆記分享
有關(guān)一個(gè)在函數(shù)參數(shù)設(shè)置缺省值與引用的問題,這個(gè)問題是大多數(shù)Pythoner可能會(huì)忽視的問題,作個(gè)筆記,以備后閱,同時(shí)供需要的朋友參考2013-02-02

