タイトルの通り、Docker Composeで踏み台サーバー経由のMySQLサーバーにphpMyAdminでつなぐ方法を記載します。
環境
この記事の作業は、以下の環境で実施しました。
- macOS Ventura (Intel)
- Rancher Desktop
※Rancher Desktopを使用していますが、Docker Desktopでもおそらく問題ありません。
実現したいことと条件
- MySQLサーバーが2台(複数)ある
- MySQLサーバーはそれぞれ踏み台サーバーを経由する必要がある
- 踏み台サーバーはパスフレーズ付きの鍵認証である
- 鍵については共通のものを使用
- MySQLサーバーをphpMyAdminで操作したい
構成
ファイルを作成
以下のファイルを作成します。
.env
使用する環境変数を以下のように定義します。以下の値は一例ですのでそれぞれの環境に合わせ書き換えてください。
BASTION_KEY_FILE=~/.ssh/id_rsa
BASTION_KEY_PASS=~/.ssh/id_rsa_pass
BASTION1_HOST=bastion1.example.com
BASTION1_USER=user1
DB1_HOST=db1.example.com
BASTION2_HOST=bastion2.example.com
BASTION2_USER=user2
DB2_HOST=db2.example.com
上記、環境変数の内容について説明します。
-
BASTION_KEY_FILE
踏み台サーバーのSSHの秘密鍵ファイルのパス -
BASTION_KEY_PASS
踏み台サーバーのパスフレーズが書かれたテキストファイルのパス -
BASTION*_HOST
踏み台サーバーのホスト名(IPアドレス) -
BASTION*_USER
踏み台サーバーに接続するときのユーザー名 -
DB*_HOST
MySQLサーバーのホスト名(踏み台サーバーからアクセスできるもの)
docker-compose.yml
以下にdocker-compose.yml
を以下のように定義します。
サービスは、2台の踏み台サーバー(db1
,db2
)、phpMyAdmin(pma
)として定義しています。
version: "3"
services:
db1: &db_bastion_base
image: alpine
volumes:
- $BASTION_KEY_FILE:/root/.ssh/id_rsa:ro
- $BASTION_KEY_PASS:/root/.ssh/pass:ro
environment:
BASTION_HOST: $BASTION1_HOST
BASTION_USER: $BASTION1_USER
DB_HOST: $DB1_HOST
healthcheck:
test: "nc -zv localhost 3306"
interval: 1s
timeout: 10s
retries: 3
start_period: 1s
command: >
sh -c "
apk add --update-cache --no-cache openssh-client sshpass &&
sshpass -f /root/.ssh/pass -P 'Enter passphrase for key' ssh $$BASTION_USER@$$BASTION_HOST -L *:3306:$$DB_HOST:3306 -N -o StrictHostKeyChecking=no"
db2:
<<: *db_bastion_base
environment:
BASTION_HOST: $BASTION2_HOST
BASTION_USER: $BASTION2_USER
DB_HOST: $DB2_HOST
pma:
image: phpmyadmin/phpmyadmin
ports:
- 8096:80
environment:
PMA_HOSTS: db1,db2
PMA_PORT: 3306
depends_on:
db1:
condition: service_healthy
db2:
condition: service_healthy
-
&db_bastion_base
,*db_bastion_base
db1
とdb2
でほとんどの定義が共通です。そのためアンカーとエイリアスを使用し定義の重複定義を避けています。
&db_bastion_base
がアンカーで、*db_bastion_base
がエイリアスです。なお、これはYAMLの仕様です。
environment:
以外は共通定義のため、db2
では省略できるようにしています。 -
- $BASTION_KEY_PASS:/root/.ssh/pass:ro
ホスト機で定義されたパスフレーズが書かれたテキストファイルをマウントしています。各定義ファイルやコマンドライン引数で直接指定しないように配慮しこのようにしました。(イメージやコマンドライン履歴に残らないように)
これが完全に安全な方法かはわかりませんが、比較的安全と思われるためこの方法にしました。
パスフレーズを消してしまう方法も考えられましたが、その方法も避けました、 -
environment:
(db1
,db2
)
db1
,db2
それぞれの接続情報の環境変数定義です。 -
healthcheck:
踏み台サーバーへの接続が確立しているか確認するための定義です。後述のdepends_on:
で使用しています。 -
command:
apk
コマンドを使用し必要なツールをインストールしています。
その後ssh
コマンドを使用し踏み台サーバーへ接続しMySQLのポートのトンネルを作成しています。
なお、その際にパスフレーズ入力が求められるためsshpass
を使用し自動化しています。 -
PMA_HOSTS
複数のMySQLにつなぐため、そのホスト名(上記で定義した踏み台サーバーのサービス名)をカンマ区切りで指定します。
この環境変数の変数名が複数形であることに注意してください。(1つでけホスト名を指定するためのPMA_HOST
もあります) -
depends_on:
このサービスを起動するための依存関係を定義しています。条件をservice_healthy
とすることにより、上記で定義した、db1
,db2
のhealthcheck:
がパスした後にこのサービスが起動されるようになります。
最後に
MySQL Workbench使えばいいじゃんという意見もありそうですが、値の変更時にBIT型のものが'1'
とかでクエリが生成されエラーになって更新されないという現象がありました。しかも表向きエラーになるわけでもなく気が付けないこともあったのがきっかけでこの方法を取ってみました。
これ以外にも色々なツールはありますが、なんだかんだでphpMyAdminが使いやすいというのもあります。(個人の感想です)