Day3の深掘り:ポートフォワーディングとコンテナネットワークの本質
Day3でやったことは「nginxを起動してブラウザからアクセスする」でしたが、その裏ではかなり多くのことが起きています。
ここを深掘りすると、「なんとなく動いている」状態から「仕組みを理解してコントロールできる」状態に一段レベルアップできます。
ホストとコンテナは“別世界”という前提
ネットワーク的には別のマシンと考える
あなたのPC(ホスト)とコンテナは、ネットワーク的には「別のマシン」として扱われます。
同じPCの中にいるのに、論理的には別世界です。
コンテナの中には独自のIPアドレス空間があり、独自のポート番号の世界があります。
nginxはその「コンテナの世界」の80番ポートで待ち受けています。
しかし、そのままではホスト側から直接80番ポートに届きません。
ここで必要になるのが、ホストとコンテナの世界をつなぐ「橋」としてのポートフォワーディングです。
ポートとは何かを一度ちゃんと整理する
「同じ住所の中の部屋番号」というイメージ
IPアドレスが「建物の住所」だとしたら、ポート番号は「部屋番号」です。
同じPC(同じIPアドレス)の中で、複数のアプリが同時に通信できるのは、ポート番号で区別しているからです。
例えば、ブラウザから
http://localhost:8080
にアクセスするとき、ブラウザは「自分のPCの8080番ポートに行きたい」と言っています。
しかし、nginxはコンテナの中の80番ポートで待っています。
このズレを埋めるのが -p 8080:80 です。
-p 8080:80 の本当の意味をもう一段深く理解する
左側と右側の世界
-p 8080:80 の左側はホスト側、右側はコンテナ側です。
つまり、「ホストの8080番ポートに来た通信を、コンテナの80番ポートに転送する」というルールを作っています。
このとき、ブラウザはコンテナの存在を知りません。
ブラウザは「localhost:8080」に話しかけているだけで、その先でDockerがコンテナに橋渡ししているだけです。
この「コンテナの存在を意識させない」というのが、Dockerが実務で使いやすい理由の一つです。
ポート番号を変えたらどうなるか
例:-p 3000:80 にした場合
もし次のように起動したらどうなるでしょうか。
docker run -d -p 3000:80 nginx
この場合、コンテナの中でnginxが待っているポートは相変わらず80番ですが、
ホスト側からは http://localhost:3000 でアクセスすることになります。
つまり、「コンテナの中の設定は変えずに、外からの入口だけ変える」ことができます。
実務では、複数のコンテナを同時に動かすときに、ホスト側のポートを変えて使い分けることがよくあります。
複数のnginxコンテナを同時に動かすイメージ
ホスト側ポートが衝突すると起動できない
例えば、次の2つを同時に起動しようとするとします。
docker run -d -p 8080:80 nginx
docker run -d -p 8080:80 nginx
2つ目はエラーになります。
理由は、ホストの8080番ポートはすでに1つ目のコンテナが使っているからです。
同じ建物の同じ部屋番号を、二つの部屋に割り当てることはできません。
しかし、次のようにホスト側のポートを変えれば、同時に動かせます。
docker run -d -p 8080:80 nginx
docker run -d -p 8081:80 nginx
この場合、
1つ目は http://localhost:8080
2つ目は http://localhost:8081
でアクセスできます。
コンテナの中ではどちらも80番ポートで待っているのに、外からは別々に見える、というのがポイントです。
コンテナの中から見た世界
コンテナは「自分が世界の中心」だと思っている
コンテナの中に入って curl localhost などをすると、
それは「コンテナの中のlocalhost=コンテナ自身」を指します。
ホストのlocalhostとは別物です。
つまり、
ホストから見た localhost と
コンテナから見た localhost は
同じ言葉でも指している対象が違います。
この感覚が身につくと、「あれ?どっちのlocalhostだっけ?」という混乱が減ります。
セキュリティ視点で見るポートフォワーディング
不要なポートは開けない、という基本原則
ポートを開けるということは、「外部からの入口を増やす」ということです。
実務では、必要なポートだけを開け、不要なポートは絶対に公開しない、というのが基本です。
例えば、nginxの80番ポートは外部公開してもよいケースが多いですが、
データベースコンテナのポート(例:3306など)は、外部に公開せず、内部ネットワークだけで使うのが一般的です。
Dockerの -p は「外部に公開するポートを増やす操作」なので、
便利であると同時に、慎重に扱うべきスイッチでもあります。
よくあるつまずきポイントと考え方
ブラウザで開いても何も表示されない場合
まず確認すべきことは、コンテナが本当に動いているかどうかです。docker ps で nginx コンテナが Up になっているかを確認します。
次に、ポート番号の指定ミスを疑います。
コマンドで -p 8080:80 としたのに、ブラウザで http://localhost:80 を開いていないか、などです。
それでもダメな場合は、ファイアウォールやセキュリティソフトがポートをブロックしている可能性もあります。
このあたりはOSや環境によって挙動が変わるので、「ネットワーク的にどこで止まっているか」を一つずつ切り分けていく癖をつけると、トラブルシューティング能力が上がります。
Day3のゴールの再定義:「ポートフォワーディングを説明できる」
ここまで深掘りしたうえで、Day3のゴールをもう一度言語化すると、次のようになります。
ホストとコンテナはネットワーク的に別世界であり、コンテナの中のポートにはそのままでは届かない。-p ホストポート:コンテナポート という指定で、ホストの入口とコンテナの入口を橋渡しできる。
ブラウザはコンテナの存在を知らず、あくまでホストのポートにアクセスしているだけだが、その裏でDockerが転送している。
複数コンテナを動かすときは、ホスト側ポートを変えることで共存させられる。
ポートを開けることは入口を増やすことなので、セキュリティ的には必要最小限にするのが原則である。
ここまで自分の言葉で説明できれば、Day3は「実務の入口」というより、すでに「実務の基礎」をしっかり踏み込めているレベルです。
