Dockerネットワーク構造

元記事(Docker Networking Explained)の内容を、よりわかりやすく整理しました。

なぜDockerのネットワークを理解すべきか?

最初は docker run -p 3000:3000 my-app の一行でうまくいく。
でも、PostgresやRedisを追加した途端にこんなエラーが出る。

ECONNREFUSED 127.0.0.1:5432

ラップトップでは動いていたのに、なぜ?
それがDockerネットワークの核心的な問題です。

コンテナは「自分だけの世界」を持っている

各コンテナは独自のネットワーク空間(ネットワーク名前空間)を持ちます。

  • 独自のIPアドレス
  • 独自のルーティングテーブル
  • 独自の localhost

重要:コンテナ内の localhost = そのコンテナ自身であり、ホストPCでも他のコンテナでもない。

ブリッジネットワーク(Bridge Network)

DockerのデフォルトはLinuxの「ブリッジ」という仮想スイッチで各コンテナを繋ぐ方式。

コンテナ eth0
    │
仮想イーサネットペア
    │
Docker ブリッジ(docker0)
    │
ホストのネットワーク

コンテナは 172.17.0.0/16 のようなプライベートIPをもらいます。
外部からは直接アクセスできません。


ポートの公開(Published Ports)

docker run -p 8080:80 nginx

これは「ホストの8080番ポートをコンテナの80番に転送する」という意味。

http://localhost:8080 → ホストの8080 → コンテナの80

同じホストポートを2つのコンテナで使うと競合してエラーになります。
コンテナポートは同じでも、ホストポートは違う番号にする必要があります。

ユーザー定義ブリッジ(推奨)

Docker標準のブリッジより、自分で作ったネットワークを使うのがおすすめ

docker network create app-network

docker run -d --name postgres --network app-network postgres:16
docker run -d --name api --network app-network -p 3000:3000 my-api

これでAPIコンテナは postgres:5432 というコンテナ名でDNS解決できるようになります。

接続先使うべきアドレス
ホストPC → コンテナlocalhost:公開ポート番号
コンテナ → コンテナサービス名:コンテナポート
コンテナ → 自分自身localhost

ローカルホストの罠(最重要!)

これが最もよくある問題です。

# ❌ 間違い(API コンテナ内の localhost = API コンテナ自身)
DATABASE_URL=postgres://user:pass@localhost:5432/app

# ✅ 正解(コンテナ名 or Composeサービス名を使う)
DATABASE_URL=postgres://user:pass@postgres:5432/app

Docker Composeのネットワーク

Composeは自動でプロジェクト専用のネットワークを作ってくれます。

yaml

services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://postgres:secret@db:5432/app  # ← "db"はサービス名
    depends_on:
      - db

  db:
    image: postgres:16
    # ポートを外部公開しない → セキュア

プロダクション的な構成の鉄則: エッジのサービス(NginxやAPIゲートウェイ)だけ公開し
DB・キャッシュ・内部APIは非公開のまま。

yaml

services:
  nginx:  # ← 唯一の公開サービス
    ports: ["80:80"]
  api:    # ← 外部公開なし(Nginxが内部でapi:3000に転送)
    build: ./api
  db:     # ← 外部公開なし
    image: postgres:16

0.0.0.0 へのバインド

ポートマッピングが正しいのにアクセスできない場合
アプリが 127.0.0.1 にしかバインドしていない可能性があります。

# ❌ これだとコンテナ内からしかアクセスできない
server listening on 127.0.0.1:3000

# ✅ すべてのインターフェースで受け付ける
server listening on 0.0.0.0:3000

ホストマシンへのアクセス

コンテナからPC上のサービス(モックサーバーなど)に接続したい場合

  • Docker Desktop(Mac/Windows)host.docker.internal がそのまま使える
  • Linux:明示的に指定が必要
docker run --add-host=host.docker.internal:host-gateway my-app

その他のネットワークモード

モード概要
bridgeデフォルト。ほとんどの用途に対応
hostコンテナとホストがネットワーク共有。Dockerの分離なし
noneネットワーク完全遮断。バッチ処理など
overlaySwarm複数ホスト間の通信
macvlanコンテナに物理ネットワーク上のIPを付与

トラブルシューティング

# ネットワーク確認
docker network ls
docker network inspect app-network

# コンテナに入る
docker exec -it api sh

# DNS解決確認
getent hosts db

# ポート確認
nc -vz db 5432

# HTTP確認
curl http://api:3000/health

# 公開ポート一覧
docker ps

デバッグ時のチェックリスト

  1. クライアントはどこで動いているか?
  2. サーバーはどこで動いているか?
  3. 同じDockerネットワークにいるか?
  4. サーバーは 0.0.0.0 でリッスンしているか?
  5. 通信の方向(内部 / ホスト→コンテナ / コンテナ→ホスト)は?

まとめ

「誰が、誰と話すべきか?」 — これが設計の出発点

  • 各コンテナは独自の localhost を持つ
  • コンテナ同士はサービス名で通信する
  • ホストはポート公開を通じてコンテナと通信する
  • エッジサービスだけ公開し、DB・内部APIは非公開を維持する

コメント

タイトルとURLをコピーしました