Dockerネットワークとポートフォワーディング
コンテナ間の通信の仕組み、ポート公開と単なるEXPOSEの違い、Dockerがufwのルールをバイパスする理由を説明します。
更新日 2026年8月23日
コンテナの問題の半分はネットワーク関連です。サービスがデータベースに接続できない、ポートが使用中、コントロールパネルが突然インターネット全体に公開される。この仕組みを整理しましょう。
3種類のネットワーク
- bridge — デフォルトです。コンテナは内部アドレスを取得して相互に通信し、外部へはホストの NAT を通じて出ていきます。
- host — コンテナはホストのネットワークを直接使用します。ポートの公開は不要で、機能もしません。高速ですが分離はありません。コンテナのポート 80 はホストのポート 80 になります。
- none — ネットワークがまったくありません。不要なタスク向けです。
自分で作成した、または Compose が作成したカスタムネットワークは、デフォルトの bridge と重要な点で1つ異なります。名前解決が機能するのです。app コンテナは db という名前で db コンテナに到達できます。
docker network create backend
docker network ls
docker network inspect backend
Compose では、このようなネットワークがプロジェクトごとに自動で作成されます。
ポートの公開
ports:
- "127.0.0.1:8080:8080" # accessible only from the machine itself
- "80:80" # accessible to the whole internet
左がホスト側のポート、右がコンテナ内のポートです。イメージ内の EXPOSE ディレクティブは何も公開しません。アプリケーションがどのポートで待ち受けるかを示すメモにすぎません。
ルールはシンプルです。外部からアクセスする必要があるものだけを公開します。データベース、コントロールパネル、内部 API は 127.0.0.1 に置き、証明書を持つ Web サーバーがそれらを外部へ公開します。
Docker は
iptablesのルールを自身で書き込み、しかもufwが管理するチェーンより前に行います。-p 8080:8080として公開されたポートは、ufwが「deny」と表示していてもインターネットからアクセスできます。ファイアウォールに頼らず、ポートを127.0.0.1にバインドしてください。
コンテナ間の通信
services:
app:
networks: [frontend, backend]
db:
networks: [backend]
proxy:
networks: [frontend]
ports:
- "80:80"
- "443:443"
networks:
frontend:
backend:
ここではデータベースはアプリケーションからのみアクセスでき、外部に面しているのは Web サーバーだけです。これはどのようなスタックにも適した正しい構成です。
コンテナ内からは、隣接するサービスをサービス名で参照します。postgres://db:5432/app。コンテナ内の localhost というアドレスはホストではなくコンテナ自身を指します。これは latest に次いでよくある間違いです。
ホスト自体で動作しているサービスにコンテナから到達するには、host.docker.internal という名前を使用し、次を追加します。
extra_hosts:
- "host.docker.internal:host-gateway"
診断
docker compose exec app ping -c2 db
docker compose exec app getent hosts db
sudo ss -tulpn | grep LISTEN
docker port <container>
ss はポートが実際にどのインターフェースで待ち受けているかを表示します。0.0.0.0:8080 は外部に公開、127.0.0.1:8080 は公開していません。
よくある間違い
- 「ポートはすでに使用されています」。 別のコンテナまたはホストのサービスが占有しています。
sudo ss -tulpn | grep :80で原因を特定できます。 - 異なる Compose プロジェクトのコンテナは互いに認識できません。 各プロジェクトには独自のネットワークがあります。
networks: { shared: { external: true } }で明示的に接続してください。 - アプリケーションがコンテナ内の
127.0.0.1で待ち受けています。 この場合、公開しても役に立ちません。コンテナの外部から到達できないのです。アプリケーションが0.0.0.0で待ち受けるように設定してください。 - 帯域幅。 ホストあたり最大 500 Mbps を共有します。ファイル配信はそれを他のすべてと共有します。