通过ssh加速MySQL连接

Database and Ruby, Python, History


公司用亚马逊的EC作为跳板连接MySQL数据库,因为亚马逊服务器在国外,查询一个1M的表都要等300+秒。此外,因为用了跳板,你没法在Terminal中直接连接数据库。接下来,就是要解决这两个问题。

命令行里连接MySQL

背景

本地需要先ssh到JumpBox,在JumpBox上面在mysql -h mysql_server连上MySQL。

#######        #######        #######
 Local    >    JumpBox    >    MySQL
#######        #######        #######

本地用SSL做端口转发

ssh -i ~/.ssh/ssh_server.pem -f -N -L 3309:{host_of_mysql_server}:3306 usr@{host_of_jumpbox}

其中-i ~/.ssh/ssh_server.pem是用来连接jumpbox的证书(无密码登陆方式),3309是本地端口,{host_of_mysql_server}:3306是在host_of_jumpbox上,连接MySQL数据库的3306端口。

在命令行里面连接数据库

这个时候,本地就有一个3309的端口,可以直连远程数据库了。

mysql -h 127.0.0.1 -u db_usr -P 3309 -p

利用docker做端口转发

Dockerfile.ssh-client

FROM alpine:latest
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
# install ssh-client and bash
RUN apk --no-cache add openssh-client bash
# example ssh usage to print version
ENTRYPOINT ["ssh"]

docker-compose.yml

version: '2'
services:
  nbachina:
    image: ssh-client
    volumes:
      - ~/.ssh:/ssh_key:ro
    ports: 
      - 3309:3309
    restart: always
    command: >
      -N -C -T
      -o ServerAliveInterval=60
      -o GatewayPorts=true
      -o ExitOnForwardFailure=yes
      -o StrictHostKeyChecking=no
      -L 3309:{host_of_mysql_server}:3306
      -p 22
      -i /ssh_key/ssh_server.pem
      usr@{host_of_jumpbox}

启动容器,本地开启3309端口。和上面一样,可以用各种MySQL工具通过3309端口连接数据库了。

docker-compose up -d nbachina

不想每次输入密码

mysql_config_editor set --login-path=nbachina --host=127.0.0.1 --port=3309 --user=username --password

连接数据库

mysql --login-path=nbachina

好了。到这里,基本上解决了第二个问题,可以在命令行里面直连数据库了。此外,利用docker是简单关闭SSH端口转发,不用去一堆进程里面慢慢找。接下来就是解决加速的问题。

加速

自己买的是HTTP代理,猜测ShadowSocks应该也是类似的。假设本地9900开启了HTTP Proxy端口。这样ssh到nbachina的连接会先通过本机的9900 Proxy,再连接到jumpbox。jumpbox到代理服务器的速度一般都很快,然后再从代理服务器把数据传输回来。

创建.ssh/config

Host nbachina
Hostname china.nba.com
ProxyCommand socat - PROXY:host.docker.internal:%h:%p,proxyport=9900,proxyauth=proxy_usr:proxy_pwd
User usr_to_access_ssh_server
Port 22
IdentityFile ~/.ssh/ssh_server.pem

SSH端口转发

不再需要指定证书,不再需要指定用户名,直接用host即可。

ssh -N -L 3309:{host_of_mysql_server}:3306 nbachina

接下来容器化

Dockerfile

和上面的Dockerfile类似,只是多了把.ssh/config和pem复制到容器里面。

FROM alpine:latest
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
# install ssh-client and bash
RUN apk --no-cache add openssh-client bash socat
RUN mkdir -p /root/.ssh
COPY docker/ssh/config /root/.ssh/
COPY docker/ssh/ssh_server.pem /root/.ssh/
# example ssh usage to print version
ENTRYPOINT ["ssh"]

docker-compose.yml

注意最后一行就不需要是usr@{host_of_jumpbox},直接用config文件里面定义的host就行了。

version: '2'
services:
  nbachina:
    image: ssh-client
    volumes:
      - ~/.ssh:/ssh_key:ro
    ports: 
      - 3309:3309
    restart: always
    command: >
      -N -C -T
      -o ServerAliveInterval=60
      -o GatewayPorts=true
      -o ExitOnForwardFailure=yes
      -o StrictHostKeyChecking=no
      -L 3309:{host_of_mysql_server}:3306
      nbachina

Reference

  1. https://www.cyberciti.biz/faq/linux-unix-ssh-proxycommand-passing-through-one-host-gateway-server/
  2. https://stackoverflow.com/questions/22635613/what-is-the-difference-between-ssh-proxycommand-w-nc-exec-nc