この前案件でDocker+cakePHP3の仮想環境を作っていたのですが、構築したDBサーバーに接続できない!
そして、色々調べてみるとポート番号が競合してたと判明。
今まで正直、ポート番号って無意識に仮想環境構築していたから、解決まで引くほど時間が掛かった、、、。
そこで!議事録の意味も込めてポート番号問題が発生して解決までの流れを書き留めときます。
仮想環境についてちょっと詳しくなりたい人、ちょうどポートについて調べている人の手助けになれば幸いです。
0.何が起きた?
まず、状況説明から、、、。
・cakePHP3(PHPのフレームワーク)
・Docker(仮想環境実行ツール)
・MySQL Workbench(MySQLの管理ツール)
・MySQLサーバーのポート番号:3306
以上の条件で開発環境を構築。
しかし、MySQL Workbenchから仮想環境のMySQLサーバーへ接続できない。なんで?
ちなみに、DockerのDBコンテナにアクセスしてSQLサーバーに繋ぐと接続できる。なんで?
そして、もしや!と思いdocker-compose.yml(Dockerの仮想環境を設定するファイル)を3306から3307で設定するとMySQL Workbenchでも接続できた!
ということは、ポートに問題がある!と言う考えに至った訳です。
1.そもそもポートとは何か?
まず、「①ポートって通信機器に使われるLANポートやUSBポート」、「②TCP/IP通信で使われるポート」の2種類があるんですが、ここでは②の方を取り上げます!
TCP/IPとは、インターネット通信するときの約束事のようなもの。
例えば、手紙を届けるには住所、宛先、手紙の内容が必要ですよね?インターネットでも世界共通でも通信方法が共通化されています。
そして、通信先(手紙で言う住所)を役割を担っているのがIPアドレス。
例えば、GoogleだったらIPアドレスは172.217.175.110。実際IPアドレス直接売ってもGoogleのトップページへ行けます。
もちろん、仮想環境を作るときもIPアドレスは必要です!
しかし、仮想環境を作る時、通信する相手は「自分自身」。そのため、自分自身専用のIPアドレスが設定されます。
※127.0.0.1これをlocalhostと呼びます。
でも、仮想環境って案件ごとにたくさん作るし、用意するサーバーもたくさん!
127.0.0.1で通信しても、どのサーバーにアクセスしたらいいか判断できません。
そこで、必要なのがポート番号です。
WEBサーバーなら80番、DBサーバーなら3306番と、設定されたポート番号を指定することで、
「このサーバーにアクセスしますよ!」と伝えることができるのです。
※logalhostの場合、127.0.0.1:8889(もしくはlocalhost:8889)というように「:」を付けて指定します。
そして、仮想環境を構築するときは、「このサーバーはこのポート番号だよ」という風に指定しておく必用があります!
2.じゃあDockerでポート番号はどう指定している?
もちろん、Dockerでもポートを指定するところはあります!
じゃあどこ?それはズバリdocker-compose.ymlというファイルです!
例えば、DBコンテナを決める部分
db:
container_name: db
image: mysql:5.7.39
environment:
- MYSQL_DATABASE={パスワード}
- MYSQL_USER={ユーザーネーム}
- MYSQL_PASSWORD={パスワード}
- MYSQL_RANDOM_ROOT_PASSWORD=yes
- TZ=Japan
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
ports:
- "3306:3306"
volumes:
- db-korn:/var/lib/mysql:cached
platform: linux/x86_64
この赤のportsという部分。
「3306:3306」がありますね。
これは、「ポート番号を3306で指定してアクセスしてきたら3306ポートのサーバーにアクセスしてね!」という意味です。
ちなみに、Dockerはdocker-compose.ymlファイルを変更することでポートを変更できます。
※だいたいDBサーバーはポート3306に設定することが多いですね。なんでだろう。
しかし、MAMPだとDBサーバーは3306番に設定可能です!
だから、MAMPを立ち上げてDockerを立ち上げてたら、DBサーバーのIPアドレスはどっちも「127.0.0.1:3306」。
つまり、ポートも被って競合しちゃうことがあります。
3.ポートが競合するとどうなる?
普通は、サーバーが起動できません。
しかし、私の場合ポート競合していたのはデーモン(元々MACに備わっているOS)のMySQLとDoker仮想環境のMySQL。
そのため、仮想環境のMySQLサーバーは立ち上がりました。
そして、MySQL Workbench(MySQLの管理ツール)でポート3306で接続しようとするとデーモン側に接続しようとして失敗する自体に!
ポート自体を理解できなかった私。
先輩のサポートなしでは到底たどり着かなかった答えでしょう。
4.ポート競合の対処方法(私の場合)
コマンドで3306番ポートを使っているか確認
まずは、コマンドで他のアプリケーションが3306番ポートを使っていないか確認。
sudo lsof -P -i:3306
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
MySQLWork 386 {ユーザー名} 14u IPv4 0x7f67e772a605 0t0 TCP localhost:50882->localhost:3306 (CLOSE_WAIT)
すると、3306番を使っているプロセス(実行している処理)の一覧が表示されます。
ここの「PID」に注目!
PIDとは、プロセスIDの略でプロセスを特定するのに必用なもの。
プロセスを指定するときにもPIDが必用なので、「PIDは大事!」と覚えておきましょう!
PIDを特定してKILLする
1番簡単な方法は、今3306番で行われているプロセスを終了させる方法です。
コマンドにて
sudo kill -9 386←ここはプロセスID
先程検索したPIDを指定して削除!
もう一度「sudo lsof -P -i:3306」コマンドを打って、一覧にプロセスが表示されなければKILLできたということです。
KILLできない場合はどうする?
私の場合、なぜか3306番ポートのプロセスが消えませんでした、、、。
PIDをアクティビティモニタ(MACに備わってるプロセスを見るアプリ)で称号してみると、3306番を使っていたのはmysqldと判明。
mysqldは、デーモン(マックOSの中で常駐しているソフト)を表す表記で、これがKILLではなかなか消せない。
そこで、デーモン側のMySQLが利用しているポート番号を書き換えることにしました!
MySQLのポートを変更
MySQLの設定ファイルはmy.cnfというファイルで行われます。
そのファイルを編集!
vim /usr/local/etc/my.cnf
[mysqld]の下にポートを追加します。※今回は3300に変更
[mysqld]
# Only allow connections from localhost
bind-address = 127.0.0.1
port=3300
これでMySQL Workbenchで3306ポートに接続しても、Docker仮想環境のMySQLサーバーに接続されるようになりました!あぁ、長い戦いだった、、、。
5.ポート番号の競合を起こさないために
自分の反省点から、「ポートの理解」と「管理」がかなり大切だと思いました。
正直、今回のトラブルまではポートを意識したことがなったので、、、。
しかも、MAMPやXAMPはポートを自動的に振り分けて環境を作ってくれるので、かなり便利!な反面、ポート設定の知見が薄れることもあります。
そのため、仮想環境を作るときはポートの設定ができなくても、設定しているファイルくらいは知るようにします。
そして、仮想環境を複数持っている場合はポート管理も重要。
ポート番号を一覧にしたり、被らないようにチームで共有したりと、結構周りを巻き込んだ動きが必用かと思います。
でも、今回のことで結構ポートの奥深さを知れたしラッキーでした!