🐳

[Docker]0.0.0.0でサーバーを立てる理由(Python)

2022/02/19に公開

はじめに

Dockerコンテナ内でサーバーを立てる際、127.0.0.1(localhost)でlistenするとERR_EMPTY_RESPONSEとなってしまいますが、0.0.0.0でlistenするとアクセスできます.
Dockerを使っていないときは127.0.0.1(localhost)でlistenしていてもアクセスできたので、Dockerを使うとなぜ0.0.0.0でlistenしないといけないのか気になり、この記事を書くに至りました.

Demo

まず、前提としてlistenするアドレスとアクセスの可否についてまとめる.今回はPython(Django)でdemoを行いました.
今回、Demoの内容については結果をまとめるにとどめます.もし興味がある場合は次のリポジトリで確認できます.
https://github.com/shake551/docker-python-demo

Demo結果

行はアクセスするURL、列はlistenするアドレスごとに結果をまとめました.

127.0.0.1:8000 0.0.0.0:8000
http://127.0.0.0.1:8000/ ERR_EMPTY_RESPONSE 正常
http://0.0.0.0:8000/ ERR_EMPTY_RESPONSE 正常

表からもわかるように、127.0.0.1でサーバーを立てた場合はアクセスできないが、0.0.0.0でサーバーを立てた場合はアクセスできるという結果となった.
ここで気になるのが

  • なぜ0.0.0.0でサーバーを立てないとアクセスできないのか
  • 0.0.0.0でサーバーを立てた時、http://127.0.0.0.1:8000/http://0.0.0.0.0:8000/どちらでもアクセスできるのはなぜか(0.0.0.0とはなにを指すのか)

ということです.

本題

さて、本題に入りましょう.

127.0.0.1(localhost)でlistenするとなんでだめ?

今回、127.0.0.1でlistenしているのはDockerコンテナであり、ローカルマシンの127.0.0.1とは違います.そのため、ローカルマシンでhttp://127.0.0.0.1:8000/にアクセスしても、Dockerコンテナの127.0.0.1にはアクセスできないため、エラーとなってしまいます.

じゃあ0.0.0.0って?

サーバーでの0.0.0.0

0.0.0.0でサーバーを立てると、そのホストの全てのインターフェースでlistenします.また、127.0.0.1でサーバーを立てた場合と比較すると、0.0.0.0で起動した場合は同一ネットワーク内の別ホストからアクセス可能ですが、127.0.0.1でサーバーを立てた場合は他のホストからはアクセスできないという点が異なっています.今回の場合、ホストはDockerコンテナです.

※以下、サーバー側は0.0.0.0でlistenしているとします.

宛先としての0.0.0.0

宛先としての0.0.0.0とは今回で言うと、webページを見るためにアクセスするhttp://0.0.0.0:8000/0.0.0.0にあたります.

では、この宛先が意味するところを順を追って確認していきましょう.
まず、http://0.0.0.0:8000/というのは、ざっくり言うとhttpというプロトコルを用いて、IPアドレスが0.0.0.0の8000番ポートにリクエストを投げてねという意味です.
しかし、RFC6890によると0.0.0.0は無効な宛先のアドレスとされているようです.つまり、今回のhttp://0.0.0.0:8000/では無効なアドレスに向かってリクエストを投げているということになります.

なぜ無効なアドレスであるはずの0.0.0.0にアクセスできるのか

前述の通り、0.0.0.0は無効なアドレスであるはずですがアクセスできています.その理由は、OSがよしなに書き換えてくれているからです.具体的には、宛先アドレスが0.0.0.0だった場合、送信元アドレスか127.0.0.1に書き換えてくれるようです.

まとめ

  • Dockerコンテナ内で127.0.0.1(localhost)でサーバーを立ててもローカルマシンの127.0.0.1(localhost)とは異なるため、アクセスできない.
  • 0.0.0.0でサーバーを立てるとそのホストの全てのインターフェースでlistenするため、ローカルマシンからもアクセスできる.
  • 宛先アドレスを0.0.0.0にするとOSが送信元アドレスか127.0.0.1に書き換えてくれる.

参考文献

Discussion