はじめに
DockerでRuby on Rails + MySQLの環境を構築中にいわゆる**「ポートの衝突」**に遭遇したので解決までを記載します。
同じような箇所でハマった方の参考になればと思います。
この記事が役に立つ方
- DockerでRails+MySQLの開発環境を行いたいと考えている
- Docker初心者
この記事のメリット
- ポートの衝突を回避する方法が分かる
環境
- macOS Mojave バージョン10.14.6
- シェル:zsh
- Ruby:2.6.5
- Rails:5.2.2
- MySQL:5.7
- Docker:19.03.5
Dockerfile
こちらを参考に、rubyのバージョンのみ、現行安定版である2.6.5にしています。
丁寧すぎるDocker-composeによるrails5 + MySQL on Dockerの環境構築(Docker for Mac) - Qiita
FROM ruby:2.6.5
RUN apt-get update -qq && \
apt-get install -y build-essential \
libpq-dev \
nodejs
RUN mkdir /app_name
ENV APP_ROOT /app_name
WORKDIR $APP_ROOT
ADD ./Gemfile $APP_ROOT/Gemfile
ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock
RUN bundle install
ADD . $APP_ROOT
docker-compose.yml
version: '3'
services:
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: root
ports:
- "3306:3306"
web:
build: .
command: rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/app_name
ports:
- "3000:3000"
links:
- db
tty: true
エラー内容
$ docker-compose run web rails new . --force --database=mysql --skip-bundle
上記コマンドでrails new
したかったのですが、以下エラーが発生してしまいました。
Error starting userland proxy: listen tcp 0.0.0.0:3306: bind: address already in use
address already in use
とあるので、既にポートが使われているらしい。
ここから解決していきます。
1.ポート番号の変更(これだけでは解決せず)
過去、DockerでMySQLを使用したときもポートは3306を使用したことはあったなと思ったので、ホスト側のポートをずらしてみて検証します。
services:
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: root
ports:
- "3316:3306" # ここを修正。左側はホスト、右側はコンテナを表す。
# コンテナ間の通信は3306が使われるようなので、右側はそのまま。
しかし、同様のエラーが発生。
Error starting userland proxy: listen tcp 0.0.0.0:3306: bind: address already in use
ポートを変えたのに、なぜ?
※今思えば、ここでホスト側で同じポートが使われていないかを以下コマンドで調べることがベストだったかもしれません。無駄撃ちが減ったはず。
$ sudo lsof -i -P | grep "LISTEN"
次の策に移ります。
2.docker-compose down
(これで無事解決)
以下記事をstack overflowで見つけました。(phpですがエラーは同じ)
php - Error starting userland proxy: listen tcp0.0.0.0:3306: bind: address already in use - Stack Overflow
Probably you have already a MySQL service running in port 3306. You should close it first.
Then try to enddocker-compose down
すでにMySQLがポート3306で起動している可能性があるので、とりあえずdocker-compose down
してからもう一度コマンドを実行してみろとのこと。
エラー出てたのに起動してるの?と疑問を抱きつつも、やってみます。
$ docker-compose down
↓
$ docker-compose run web rails new . --force --database=mysql --skip-bundle
↓
無事rails new
出来ました!
一回目のコマンドでエラーが出ながらも起動してしまっていたのか?
スッキリしませんが一応解決です。
おわりに
これまであまりポートを意識することがなかったため、いい勉強になりました
docker-compose.ymlについてもまだ理解不十分なため、次は以下記事を見て勉強しようと思います。
Docker Compose - docker-compose.yml リファレンス - Qiita
参考にさせて頂いたサイト(いつもありがとうございます)
mysql-Dockerを使用するときに「ポートの衝突」を回避する方法 - コードログ
mysql - How do I avoid ‘port collision’ when using docker? - Stack Overflow
Docker Compose - docker-compose.yml リファレンス - Qiita