見出し画像

sshtunnel+mysql.connect

自分のPCからデータをawsのrdsにアップロードしたい

前提条件としてrdsは会社のPCからは直接見られないという制限が自社にあったとした場合、sshトンネル経由で接続する必要があります。というかその制限してない会社はないと思いたい。
a5mk2とかだと、ssh2トンネルとか利用して画面上は見られますし、そこからデータも入れられるので、データが少ない時はいいのですが、excelのデータを加工しながらロードしたいとかそういうニーズは中小企業はまだまだあって、その場合に半日も時間をつぶしてしまったので、自分用のメモです。

コード

import time
import mysql.connector # pip install mysql-connector-pythonなので注意
from sshtunnel import SSHTunnelForwarder

ssh_server = 'SSHサーバーのアドレス'
ssh_port = 22
ssh_username = 'sshのユーザー名'
ssh_pkey = '秘密鍵のパス'
ssh_pkeypassword = '秘密鍵のパスワード'
remote_rds_endpoint = 'RDSのエンドポイント'
remote_rds_port = 3306
local_bind_address = '127.0.0.1'
db_user = 'DBのユーザー名'
db_password = 'DBのパスワード'
db_name = 'DB名'

try:
    # SSHトンネルを作成
    tunnel = SSHTunnelForwarder(
        # ssh_serverのアドレスとポートを指定する
        (ssh_server, ssh_port),
        # sshでログインするユーザー名を指定する
        ssh_username=ssh_username,
        # 秘密鍵のパスを指定する
        ssh_pkey=ssh_pkey,
        # 秘密鍵のパスワードを指定する
        ssh_password=ssh_pkeypassword,
        # remote_bind_addressにRDSのエンドポイントとポートを指定する
        remote_bind_address=(remote_rds_endpoint, remote_rds_port),
        # local_bind_addressにローカルのバインドアドレスとポートを指定する
        local_bind_address=(local_bind_address, ),
    )

    tunnel.start()
    time.sleep(1)
 
    conn =  mysql.connector.connect(
        host=tunnel.local_bind_host,
        user=db_user,
        password=db_password,
        database=db_name,
        port=tunnel.local_bind_port,
        connection_timeout=10,
        charset='utf8mb4',
        use_pure=True
    )
    with conn.cursor() as cur:
        cur.execute('SHOW TABLES')
        for row in cur:
            print(row)

except Exception as e:
    print(str(e))
    exit(1)

コメントに解説も併せて書いたので、解説はとくには必要ないと思いますが、mysql.connectot.connectではtunnel.local_bind_hostと書いていますが、実際はlocalhostと同義の127.0.0.1につないでいます。つまり、mysqlのhostにはrdsのエンドポイントは書いてはいけません。
あと、mysql.connectのoptionでuse_pure=Trueを入れないと動きません。参照元です。一部の情報ではpymysqlにすれば動くなんていうのもあったのですが、自分の環境では動きませんでした。

大はまりした点

sshtunnelは作成できたんですが、そのトンネルを使ってmysqlにログインできない状態が続きました。で、その時に、sshトンネルを別途張ると、うまくmysqlにつなぐことができたので、tunnelのほうをずっと疑ってしまいました。そこで、仕方がないので、sourceをwsl側に全部移してやってみたところ、それでも動かないので、切り分けとして、mysqlをもう一度疑うことにしたんです。その時、参照元の情報を見つけて試したんですが、あっさり解決したということです。そのuse_pure=Trueの解説は公式に譲ります。時間を返してほしい。というか自分の素人さにがっかりした。。。


この記事が気に入ったらサポートをしてみませんか?