もち256ログ
About Note Log
Log
published: 2022-08-20
sshポートフォワードで外部のMySQLに接続できなかった問題

どうも、めちゃくちゃお久しぶりです。
もち256です。

最近は転職したりなどで、3ヶ月くらいブログが更新できていませんでした。
今回は技術的につまずいたところのTipsになります。

はじめに

サーバをリモートコントロールするために使用するsshコマンドですが、このコマンドはサーバにリモートアクセスする以外にも、ポートフォワードを行うことができます。

例えば、下記の図のような場面があると想定します。

下記のように開発機、中継サーバ、DBサーバがあってDBサーバに対して変更を行いたい場合、sshで中継サーバやDBサーバにアクセスをして作業を行うことが多いと思います。

blog_image

今回は中継サーバやDBサーバで作業を行えない場合(作業に必要なコマンドがないなど)、手元の開発機でDBサーバにアクセスを行なって作業をすることとします。

実験用のDockerfile

以下に、Dockerfileとdocker-compose用のファイルを用意しておきました。
実験したい人は「docker compose up」などで試してみてください。

Dockerfile

FROM centos:7

ENV LANG=ja_JP.utf8
ENV LC_ALL=ja_JP.utf8
RUN yum update -y
RUN yum install -y openssh-server
RUN ssh-keygen -A
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN echo "root:root" | chpasswd

ENTRYPOINT [ "/bin/bash" ]

docker-compose.yml

version: "3"
services:
  ssh-server:
    build:
      context: .
      dockerfile: ./Dockerfile
    image: centos:7
    ports:
      - 20022:22
    privileged: true
    tty: true
  mysql-server:
    image: mysql:latest
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_PORT: 3306
    tty: true
networks:
  servers:

上記のファイルを実行した後、下記のコマンドを実行して、中継サーバでsshdを起動しておきます。

# コンテナに接続
docker compose exec ssh-server /bin/bash
# sshdの起動
/usr/sbin/sshd -D

つまずいたところ

手元の開発機からDBサーバにアクセスするためには、下記のsshコマンドを使用して、中継サーバでポートフォワードを行います。

# "ssh-server"はDockerであればローカルホストなど、sshdを実行している端末の名前解決をできるようにしておきます。
ssh -N -L 3306:mysql-server:3306 root@ssh-server -p 20022

上記のコマンドを実行すると、開発機(localhost)の3306番ポートがフォワードされるため、中継サーバ(ssh-server)を介して、DBサーバ(mysql-server)の3306番ポートへ通信することができます。

つまり、sshを実行している開発機の3306番ポートへ接続をしようとすることで、DBサーバの3306番ポートへ接続できるようになります。

ここで、下記のコマンドを実行すると、開発機からDBサーバへアクセスすることができるはずだったのですが...

mysql -h localhost -u root -p
# => ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

なんか、エラーが出てしまいましたね。
どうやら、開発機内のmysql.sockを探しに行き、そんなもの見つからないぞってことらしいです。

まあ、MySQLを実行しているのは別のサーバなので、当たり前なのですが...

上記のエラーですが、下記のコマンドで解決できます。

mysql -h 127.0.0.1 -u root -p
# => Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
# => mysql> 

どうやら、ホスト名で「localhost」を指定すると、mysql.sockを使用した接続になってしまうらしく、「127.0.0.1」を指定することで、この問題を回避できます。

この仕様は、下記ドキュメントに書かれており、同じ意味をもつ単語でも、違う挙動になるため各位気をつけてください、というお話でした。

たとえば、Unix 上の `--host=localhost` では、TCP/IP のポート番号を指定するために `--port`または `-P` オプションが指定されている場合でも、クライアントは Unix ソケットファイルを使用してローカルサーバーへの接続を試みます。

MySQL 8.0 リファレンスマニュアル - コマンドオプションを使用した MySQL Server への接続

ログ一覧へ戻る