自分用備忘録です。
tl;dr
podman run -d --name <コンテナ名> -p 8080:8080 simple-server python -m http.server 8080 --bind 127.0.0.1
1.起きた現象
2.対応策
3.考察
1.起きた事象
環境:Red Hat Learning(GLS)上のRHEL
事象:コンテナ内のhttpサーバーを起動後、curl http://localhost:8080/Hello.html でコンテンツアクセスしようとしたが、「error 52:empty reply from server」で失敗する。
2.対応策
下記コマンドを実施します。
コマンドをpodman→dockerに変えることで、Dockerでも使える可能性があると思いますが、未検証のため、自己責任でご利用ください。
podman run -d --name http-server -p 8080:8080 simple-server python -m http.server 8080 --bind 127.0.0.1
コマンドの解説:
podman run:コンテナを起動
-d:デタッチド、バックグラウンド起動。ログを見るにはpodman logs コンテナ名(id)
--name:起動するコンテナ名
-p:ホストマシンとコンテナのポートフォワードを行う。 ホスト:コンテナの順で記載
python -m http.server 8080 --bind 127.0.0.1:コンテナ起動時のENTRYPOINT。コンテナ起動時に実行されるコマンド(ENTRYPOINT)を上書きしてしまうので、できればコンテナファイルに記載されているENTRYPOINTやCMDを確認してからの方がベターです。
詳細は下記参照。
python -m http.server:管理者権限でhttp.serverという名前のpythonファイルを実行。
8080:オプション。ポート8080を指定(何も指定せずに起動すると8000で起動されたので、私の環境ではこのオプションは必須でした)
--bind 127.0.0.1:オプション。上記で起動するhttpサーバーを127.0.0.1(ループバックアドレス)にバインドする。
3.原因の考察
localhostが指しているアドレスが、コンテナ内とホストマシンで異なるのが原因です。
何故かというと、コンテナはネームスペースで区切られた空間にあるため、ホストマシンとは完全に別のマシン(というかプロセス)と考えられるからです。
そのためにコンテナ内で起動したhttpサーバーには、CurlコマンドでLocalhostを指定するだけではアクセスができません。
127.0.0.1に明示的にbindして起動したら、何故上手くいったかについてはよくわからない部分もあります。おそらくホストマシン側のlocalhostにbindされたのではないかと思われます。
0.0.0.0にバインドして起動することを推奨する解決策もあります。しかし、こちらの解決策の方がlocalhost(ループバック)アドレスのみにbindして起動しているので、安全性が高いのではないかと考えています。
もちろん環境によっては0.0.0.0にバインドしないと外部からアクセスできないケースもあると思うので、0.0.0.0の方が汎用性は高いと思われます。