Dockerとポートフォワード

Dockerでのコンテナ設定でよく見かけるのが、ポートフォワードの設定である。ポートフォワードという単語は大学1回生に初めて聞いたが、意味がよくわからずに終わり、最近よく聞くようになってようやく理解したという背景がある。Dockerとポートフォワード、概要について同じタイミングで理解が進んできているので、まとめてみる。

単語の定義

Docker

Dockerは、コンテナを管理するための技術である。公式サイトでは以下のように説明されている。

Docker はアプリケーションを開発(developing)、移動(shipping)、実行(running)するためのオープンなプラットフォームです。Docker はインフラストラクチャ とアプリケーションを切り離すため、ソフトウェアを短時間で提供できます。Docker があれば、アプリケーションを管理するのと同じ方法で、あなたのインフラも管理できます。Docker 的な手法を最大限活用しますと、テストやコードのデプロイを素早くできますので、コードを書いてから、プロダクション(実行環境)で動かすまでにかかる時間を著しく軽減できます。

https://docs.docker.jp/get-started/overview.html

ポートフォワード

ポートフォワードは、あらかじめ設定された特定のポートで受け付けた通信を別の特定のポートに流すための仕組みである。あるサイトでは、以下の通り説明されている。

「ポートフォワーディング」とは、インターネットから特定のポート番号宛てに届いたパケットを、あらかじめ設定しておいたLAN側の機器に転送する機能です。
1つのグローバルIPアドレスでポート毎に複数のサーバーへ振り分けを行ったり、ポート変換を行うことができます。

https://www.idcf.jp/words/port-forwarding.html#:~:text=「ポートフォワーディング」とは、,行うことができます。

Dockerとポートフォワードの設定

Dockerでコンテナを作成する際、ポートフォワードを指定することで、コンテナを起動しているホストコンピュータが特定のポート宛の通信を受信した場合、コンテナへ流すことができる。

例えば、以下のコマンドでコンテナを作成すると、ポートフォワード「13306:3306」が設定される。

docker run --name test_mysql -p 13306:3306 -e MYSQL_ROOT_PASSWORD="password" mysql:latest

これは、ホストコンピュータがポート13306宛の通信を受信した場合、コンテナtest_mysqlのポート3306へと通信を流す。なお、ポート3306は、MySQLで通常使われるポートである。

ポートフォワードの設定がうまくいかない例

ポートフォワード「13306:3306」が設定されたコンテナtest_mysqlが作成された状態で、以下のコマンドで別のコンテナtest2_mysqlを作成してみる。

docker run --name test2_mysql -p 13306:3306 -e MYSQL_ROOT_PASSWORD="password" 
mysql:latest

これは、test_mysqlと同じポートフォワード「13306:3306」を設定しようとしている。しかし、このコマンドを実行すると以下のエラーが出る。

docker: Error response from daemon: driver failed programming external connectivity 
on endpoint test3_mysql (3a381ade73448aea18d36aa8f610e645201ae0a5db30ec8d086ae95a5f89066f): 
Bind for 0.0.0.0:13306 failed: port is already allocated.

エラー文を読むと、ポートがすでに割り振られていると怒られる。では、ポートフォワードを「23306:3306」に変えて以下のコマンドを実行してみる。

docker run --name test2_mysql -p 23306:3306 -e MYSQL_ROOT_PASSWORD="password" 
mysql:latest

これは実行に成功する。上のエラー文は、ホスト側で設定したポートが重複していたのが原因で怒られていた。ポートの重複が許されてしまうと、そのポートでの通信を受信するとどちらに流したらいいかが分からなくなるからである。今回の場合、ポート13306で通信を受信すると、コンテナtest_mysqlとコンテナtest2_mysqlのどちらに流したらいいかがわからなくなる。

では、コンテナ側のポートはtest_mysql、test2_mysqlどちらも3306で重複しているが、両方とも問題なく起動しているのはなぜか。これは、異なるコンテナ間は独立した環境だからである。完全に別々のコンピュータが分かれて起動しているイメージである。つまり、ポートが重複していても、コンテナtest_mysqlのポート3306、コンテナtest2_mysqlのポート3306という形で指定してあげると、通信を流す先が一意に決まる。なので、ポートの重複が許される。

この記事が気に入ったらサポートをしてみませんか?