前回の話、 MySQLサーバーのDBバックアップ及び、ローカル端末への保存を自動化する の応用で、Docker内のMySQLにparamiko経由でdumpファイルを取得しようとしたら上手くいかずに困った話。
以下のソースでは、docker execコマンドで docker_dbコンテナにログインし、MySQLのdumpファイルを出力しようとしているが、このままだと処理が空振りする。
#!/usr/bin/python
# coding:utf-8
import sys
import paramiko
from scp import SCPClient
# 用途により書き換える------------------------------------------
# サーバーへの接続情報を設定
IP_ADDRESS = '11.22.233.111'
USER_NAME = 'centos'
KEY_FILENAME = '/Users/centos/.ssh/hoge.pem'
# サーバー上で実行するコマンドを設定(ここで嵌る)
CMD = 'cd /home/DockerCon ; \
docker exec -it docker_db /bin/bash \
-c "mysqldump -uroot -ppassword MyDB > dump.sql"'
# サーバー上で取得するファイル名とその格納先を設定
GET_FILE_NAME = 'dump.sql'
GET_FILE_PATH = '/home/centos/DockerCon'
# サーバーで取得したファイルの保存先(ローカル)を指定。
# 今回はos.getcwd()でこのファイルが置かれている場所を指定している。
LOCAL_FILE_DOWNLOAD_PATH = '/Users/user'
# ----------------------------------------------------------
# ssh接続(接続に失敗した場合はエラー出力する)
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.WarningPolicy())
client.connect(IP_ADDRESS, username=USER_NAME, key_filename=KEY_FILENAME, timeout=5.0)
# コマンドの実行
stdin, stdout, stderr = client.exec_command(CMD) # 障害元
for line in stdout:
print(line.strip())
# spcでリモートファイルをローカルにコピー
with SCPClient(client.get_transport()) as scp:
scp.get(GET_FILE_PATH + GET_FILE_NAME, LOCAL_FILE_DOWNLOAD_PATH)
# ssh接続断
client.close()
del client, stdin, stdout, stderr
sys.exit(0)
原因
paramikoでコマンドを実行する際に「get_pty=True」を設定する必要があった。
# 修正前
stdin, stdout, stderr = client.exec_command(CMD)
# 修正後
stdin, stdout, stderr = client.exec_command(CMD, get_pty=True)
この設定をすることで疑似端末を割当てられる。
それによってターミナルを使って作業するとき同じようにコマンドを実行できるようになる。
基本的には、複数行コマンドを実行する際に必要になるようだ。
なんだこれ凄く重要じゃないか。
マニュアル
http://docs.paramiko.org/en/stable/api/channel.html
今日一番の収穫。