はじめに
Docker でコンテナの起動時に以下のようなエラーが生じました。
docker: Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint conflict-test (c73c99ba5cbaeac0c0ce83e5cfeffc0354d68843ed320c4bfcea37ad05f26bd1): failed to bind host port for 0.0.0.0:8080:172.17.0.2:8080/tcp: address already in use
エラーメッセージを確認すると、ホスト側の8080ポートがすでに別のプロセスによって使用されているため、コンテナのポート割り当てに失敗していることが分かります。
今回は、どのプロセスが対象のポートを使用しているのかを調査し、ポート競合の原因を特定する方法について紹介します。
ポートの競合が発生する理由
同じIPアドレス・ポート番号の組み合わせを複数のプロセスが同時に待ち受けることはできません。
例)
アプリケーションA が ホスト側8080番ポート を使用していると、Dookcer コンテナに ホスト側8080番ポート を割り当てることができません。
競合したポートの調査
調査対象ポートを使用しているプロセスの特定
lsof -i :8080
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python3 2043035 john-doe 3u IPv4 10809101 0t0 TCP *:http-alt (LISTEN)
プロセスID からプロセスの詳細を確認する
ps -fp コマンドでプロセスの詳細を確認する。
ps -fp 2043035
UID PID PPID C STIME TTY TIME CMD
john-d+ 2043035 2040514 0 13:27 pts/0 00:00:00 python3 -m http.server 8080
すると、python3 -m http.server 8080 で簡易サーバーを起動しており、これが、:8080が利用していることがわかりました。
プロセスを kill する
python3 -m http.server 8080 が使用されていない前提で記述します。プロセスを kill するかは読者様の判断に任せます。
先程の調査で判明したプロセス ID を指定して kill を実行します。
kill 2043035
プロセスが 消えたことを確認する
コマンドを実行して出力がなければ、プロセスのkill が成功しています。
ps -fp 2043035
コンテナの起動
プロセスが kill されたので、ホスト側8080番ポート でコンテナを起動します。
$ docker run -d -p 8080:80 --name test-image test
4e6581f468b0f6e865b00710c237aa44591a93080276ed0b6a8e4b5c412fa16e
問題なく起動されていることがわかります。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4e6581f468b0 test "node ./app.js" 13 seconds ago Up 13 seconds 8080/tcp, 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp test-image
おわりに
今回は、Dockerのコンテナ起動時に発生したポート競合エラーを例に、Linux上で使用中のポートを調査する方法について紹介しました。
ポート競合が発生した場合は、以下の流れで原因を特定できます。
- lsofコマンドで対象ポートを使用しているプロセスを特定する
- psコマンドでプロセスの詳細を確認する
- 不要なプロセスであればkillコマンドで停止する
Docker環境では、ローカル開発中に以前起動したコンテナやアプリケーションがポートを占有しているケースがあります。
エラーメッセージだけを見ると原因が分かりづらい場合もありますが、使用中のポートとプロセスを順番に確認することで、原因を切り分けることができます。
Linux環境でサービスやコンテナのトラブルシューティングを行う際は、今回紹介した調査手順を活用してみてください。