Docker

ポート公開と簡単な Web コンテナ

7

ポート公開と簡単な Web コンテナ — Docker Tips

コンテナは外からそのまま届きません。-p ホスト:コンテナ で穴を開けます。nginx を立ててブラウザで開き、ポート競合と EXPOSE の意味も触ります。

参考: Publish ports · docker run -p · EXPOSE · Networking


目次

  1. ポート公開がなぜ必要か
  2. -p HOST:CONTAINER の書き方
  3. nginx コンテナを立てて確認する
  4. ブラウザでの確認手順
  5. ポートが既に使われているとどうなるか
  6. EXPOSE-p の違い
  7. 複数ポート・ランダムポートの公開
  8. うまくいかないとき

ポート公開がなぜ必要か

コンテナは Docker が管理する仮想的なネットワーク空間(ブリッジネットワーク)の中で動いています。コンテナ内で Web サーバーが 80 番ポートで待ち受けていても、ホスト側のブラウザからは何も見えません。ホストの localhost:8080 のようなアドレスからコンテナ内のプロセスへ届けるには、ホストのポートとコンテナのポートを明示的につなぐ 作業が必要です。これが「ポート公開(publish)」です。

用語 意味
ホストポート PC(ローカル環境)側で開くポート番号
コンテナポート コンテナ内のプロセスが実際に listen しているポート番号
公開(publish) ホストポート ⇄ コンテナポートの対応付け

対応付けをしない限り、コンテナのネットワークは既定でホストから閉じています。これは意図しないポート露出を防ぐための安全側の挙動です。


-p HOST:CONTAINER の書き方

docker run-p--publish)は次の形式を取ります。

-p [ホストIP:]ホストポート:コンテナポート[/プロトコル]
記法 意味
-p 8080:80 ホストの 8080 → コンテナの 80
-p 127.0.0.1:8080:80 ホストの localhost からのみアクセス可(外部 NIC からは不可)
-p 8080:80/udp UDP ポートを公開(省略時は TCP)
-p 8080:80 -p 8443:443 複数ポートをまとめて公開

よくある勘違い: -p 80:8080 のように 左右を逆に書くミスです。左(コロンの前)が ホスト側、右(コロンの後)が コンテナ側 です。


nginx コンテナを立てて確認する

公式の nginx イメージはビルド不要で、デフォルトで 80 番ポートを待ち受けます。

docker run -d --name web-demo -p 8080:80 nginx
オプション 意味
-d バックグラウンドで起動(デタッチモード)
--name web-demo コンテナ名を指定
-p 8080:80 ホストの 8080 をコンテナの 80 に接続
nginx 公式イメージ名(タグ省略時は latest

起動状態とポートの対応は次で確認できます。

docker ps --filter name=web-demo

PORTS 列に 0.0.0.0:8080->80/tcp のような表示が出れば、公開が成立しています。より詳細な対応は docker port でも見られます。

docker port web-demo

ブラウザでの確認手順

  1. コンテナが Up 状態であることを docker ps で確認する
  2. ブラウザで http://localhost:8080 を開く
  3. nginx の Welcome ページ("Welcome to nginx!")が表示されれば成功

コマンドラインで確認する場合は PowerShell の Invoke-WebRequest、または curl.exe を使います(PowerShell の curl は別名として動くため curl.exe を明示すると挙動が安定します)。

curl.exe http://localhost:8080

HTML の先頭に <!DOCTYPE html>Welcome to nginx! の文字列が返れば、ホスト→コンテナの通信が通っています。

確認後の後片付け

docker stop web-demodocker rm web-demo

ポートが既に使われているとどうなるか

同じホストポートを複数のコンテナで公開しようとすると、次のようなエラーになります。

Error response from daemon: driver failed programming external connectivityon endpoint web-demo2 (...): Bind for 0.0.0.0:8080 failed:port is already allocated

原因は次のいずれかです。

原因 具体例
別のコンテナが同じホストポートを公開中 web-demo8080 を掴んでいる
ホスト上の別プロセスが使用中 開発用サーバーやほかのアプリが 8080 で listen
直前のコンテナが正しく停止していない docker stop 前に PC を落とした等

対処

# 何が 8080 を使っているか確認docker ps --filter "publish=8080"# 使っていないコンテナを止めるdocker stop web-demo# または別のホストポートを使うdocker run -d --name web-demo2 -p 8081:80 nginx

「コンテナ内側のポート」は複数コンテナで重複しても問題ありません(例えば全部が 80 で listen していてよい)。競合するのは ホスト側のポート だけです。


EXPOSE-p の違い

Dockerfile に書く EXPOSE は、実際にはポートを公開しません。「このイメージはどのポートで listen する想定か」を伝えるドキュメント(メタデータ) です。

FROM nginx:alpineEXPOSE 80
項目 EXPOSE(Dockerfile) -p / --publish(run 時)
実際にホストへ公開するか しない(情報提供のみ) する
書く場所 Dockerfile docker run / Compose の ports
コンテナ間通信への影響 なし(同一ネットワーク内は EXPOSE なしでも到達可) なし
-P(大文字)との関係 EXPOSE した番号を -P でランダムなホストポートへ一括公開できる

つまり EXPOSE だけを書いて -p を付けずに docker run すると、コンテナは起動してもホストからは一切アクセスできません。逆に EXPOSE を書かなくても -p さえ指定すれば公開自体は機能します。EXPOSE は省略しても動くが、読み手への意思表示として書いておく のが実務的な運用です。


複数ポート・ランダムポートの公開

# 複数ポートを個別に公開docker run -d --name multi-demo -p 8080:80 -p 8443:443 nginx# EXPOSE されている全ポートをランダムなホストポートに一括公開docker run -d --name random-demo -P nginxdocker port random-demo

-P(大文字)はポート番号を自分で決めたくない検証時に便利ですが、番号が毎回変わるため docker port での確認が前提になります。恒常的に使うサービスでは -p で固定するほうが扱いやすいです。


うまくいかないとき

症状 原因 対処
port is already allocated ホストポートが他のコンテナ/プロセスで使用中 docker ps --filter "publish=<port>" で特定して停止、または別ポートを使う
ブラウザで localhost:8080 に繋がらない ポート未公開、または公開先を間違えた docker psPORTS 列と -p の左右(ホスト:コンテナ)を確認
コンテナは Up なのに接続できない アプリがコンテナ内の 0.0.0.0 ではなく 127.0.0.1 だけで listen している アプリ側の bind アドレス設定を確認(Docker の問題ではなくアプリ設定の問題)
-p を付けたのに EXPOSE していないポート番号を使ったら失敗する気がする 誤解。EXPOSE の有無は -p の動作に影響しない EXPOSE は必須ではない。-p ホスト:コンテナ の対応が正しければ動く
Windows Defender ファイアーウォールに阻まれる プライベート/パブリックネットワークの許可設定 初回接続時のダイアログで許可、または Windows のファイアーウォール設定を確認
停止済みのはずのコンテナがポートを掴み続けている docker stop せず PC をシャットダウンした docker ps -a で残存コンテナを確認し docker rm で削除

ポート公開は「ホスト側の入口」と「コンテナ側の出口」を対応付ける単純な仕組みですが、左右を混同する・公開し忘れる・番号が衝突する、という 3 パターンでほとんどのトラブルが説明できます。

シェア