目次

Docker ネットワークチュートリアル:bridge、カスタムネットワーク、コンテナ間通信

アプリケーションがデータベースやキャッシュなど、ほかのコンテナに接続するときは、Docker のネットワークを理解する必要があります。最も重要なポイントは、通信させたいコンテナを同じカスタムネットワークに配置すれば、コンテナ名で相互に接続できることです。

Docker のカスタムネットワークとポートの対応を示す図
ブラウザーから -p で対応付けたホストのポートを通じて app に接続します。app はカスタムネットワーク内で db という名前を使ってデータベースに接続します。データベースを外部に公開する必要はありません

ネットワークドライバー

Docker をインストールすると、次の 3 つのネットワークがあらかじめ用意されています。

$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
a74caef4acb9   bridge    bridge    local
b9a49b39804b   host      host      local
87a8a7fd2cd9   none      null      local
ドライバー説明
bridgeデフォルトです。コンテナには独自の IP アドレスが割り当てられ、仮想ネットワーク内に配置されます
hostコンテナがホストのネットワークを直接使い、分離されません(Linux で最も完全に機能します)
noneネットワークがありません
overlay複数のホストにまたがります(Docker Swarm)
macvlanコンテナを物理マシンのようにローカルネットワーク上に表示します

デフォルト bridge の制限

ネットワークを指定しない場合、コンテナは bridge という名前のデフォルトネットワークに接続されます。このネットワークでは、コンテナ同士を名前で接続できません。

$ docker run -d --name web1 nginx:1.30
b1d3fb9024c112c5990d9ac85012cd3f5e38c114ab4409a06f960c6d8cdb496e

$ docker run --rm alpine:3.23 ping -c 1 -W 2 web1
ping: bad address 'web1'

$ docker inspect --format '{{.NetworkSettings.IPAddress}}' web1

template parsing error: template: :1:18: executing "" at <.NetworkSettings.IPAddress>: map has no entry for key "IPAddress"

$ docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web1
172.18.0.2

$ docker run --rm alpine:3.23 ping -c 1 172.18.0.2
PING 172.18.0.2 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.058 ms

--- 172.18.0.2 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.058/0.058/0.058 ms

$ docker rm -f web1
web1
  • 名前 web1 では見つかりません(bad address)が、IP アドレス 172.18.0.2 なら接続できます。
  • ただし、IP アドレスは Docker が自動的に割り当てるため、コンテナを作り直すと変わる可能性があります。設定に固定値として記述することはできません。

Docker 29 での変更点:以前のバージョンでは {{.NetworkSettings.IPAddress}} を使ってコンテナの IP を取得できましたが、Docker 29 ではこのフィールドが削除されました(上記の template parsing error)。代わりに {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}} を使ってください。

そのため、実際にはほとんどの場合、カスタムネットワークを作成します。

カスタムネットワーク:名前で相互接続する

docker network create appnet
docker run -d --name db --network appnet -e POSTGRES_PASSWORD=secret postgres:18
$ docker network create appnet
fadfeb6028cb78335fa94cfd7536265256a914cc461caae1026b6ebb21e9d7a0

$ docker run -d --name db --network appnet -e POSTGRES_PASSWORD=secret postgres:18
227033e27591e6a1c195a6d63a141aaf4486c6285477792fe3080e1d4deeb2c0

$ docker run --rm --network appnet alpine:3.23 ping -c 2 db
PING db (172.19.0.2): 56 data bytes
64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.069 ms
64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.092 ms

--- db ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.069/0.080/0.092 ms

$ docker run --rm --network appnet -e PGPASSWORD=secret postgres:18 psql -h db -U postgres -c "SELECT version();"
                                                      version
--------------------------------------------------------------------------------------------------------------------
 PostgreSQL 18.6 (Debian 18.6-1.pgdg13+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit
(1 row)


$ docker network inspect appnet --format "{{range .Containers}}{{.Name}} {{.IPv4Address}}{{println}}{{end}}"
db 172.19.0.2/16
  • appnet 内では、Docker の内蔵 DNS が db という名前をデータベースコンテナの IP アドレスに解決します。
  • PostgreSQL クライアントから -h db を指定して接続でき、データベースのバージョン(PostgreSQL 18.6)を確認できました。
  • データベースコンテナには**-p を指定していません**。ホストや外部から接続できるのは、同じネットワーク内のコンテナだけなので、より安全です。

アプリケーションの接続設定でも、同じようにコンテナ名を指定します。たとえば、次のようにします。

docker run -d --name app --network appnet -p 3000:3000 \
  -e DATABASE_URL=postgres://postgres:secret@db:5432/postgres \
  myapp

注意点:

  • コンテナ間の接続には、コンテナ内のポート(5432)を使います。-p は関係ありません。
  • ホストや外部からアクセスさせるサービス(Web サイトなど)に限り、-p が必要です。
  • 接続先の名前には、web や app のようにトップレベルドメインと同じ単語を使わないでください。同じネットワーク内では問題ありませんが、ネットワーク外から名前を検索すると予期しないアドレスに解決され、デバッグ時に誤った判断につながることがあります。

1つのコンテナを複数のネットワークに接続する、ネットワークエイリアス

$ docker network create appnet
77fadbc5633854c9e75fd9aa65325d0155ad33f5de453abac7f15f6766402bee

$ docker run -d --name app --network appnet nginx:1.30
25b4c1d92caeef5ca8765daf2f3ad6247982cacfad4914000ded8a0a455df851

$ docker network create frontend
45a9ab78fddb9f1b47a22b9ce156144286888c42eadc2b4f589986fe1f98cee0

$ docker network connect frontend app

$ docker inspect --format '{{range $k, $v := .NetworkSettings.Networks}}{{$k}} {{$v.IPAddress}}{{println}}{{end}}' app
appnet 172.19.0.2
frontend 172.20.0.2


$ docker run -d --name search --network appnet --network-alias es nginx:1.30
43b07713e7ec032d21e37fdf690064b389f798ed26b2715e7ea18c15840647af

$ docker run --rm --network appnet alpine:3.23 getent hosts es
172.19.0.3        es  es

$ docker rm -f app search
app
search

$ docker network rm appnet frontend
appnet
frontend
  • docker network connect は実行中のコンテナを別のネットワークに接続します。app は現在、2つのIPアドレスを持っています。これは分離によく使われます。フロントエンドネットワークにはNginxとアプリケーションを、バックエンドネットワークにはアプリケーションとデータベースを接続すると、Nginxからデータベースに接続できなくなります。
  • --network-alias es を指定すると、同じネットワーク上の他のコンテナからも、名前 es で search に接続できます。複数のコンテナに同じエイリアスを設定すると、DNSは複数のIPアドレスを返します。

ネットワークを管理する

docker network create appnet
docker network ls
docker network inspect appnet               # コンテナとIPアドレスを確認
docker network connect appnet コンテナ名       # 実行中のコンテナをネットワークに接続
docker network disconnect appnet コンテナ名
docker network rm appnet
docker network prune                        # 未使用のネットワークを削除

ポートマッピング:プログラムは 0.0.0.0 でリッスンする必要があります

-p 8000:8000 を指定すると、Dockerはホストの8000番ポートに届いたトラフィックを、コンテナのネットワークインターフェース上の8000番ポートに転送します。そのため、コンテナ内のプログラムは**0.0.0.0(すべてのインターフェース)でリッスンする必要があります**。127.0.0.1(コンテナ自身のlocalhost)だけでリッスンしてはいけません。Python組み込みのWebサーバーで違いを確認しましょう。

$ docker run -d --name localonly -p 8000:8000 python:3.14-slim python -m http.server 8000 --bind 127.0.0.1
246edb96a9affefaab188ac7d5ceec2fb103b511bdac352cca6ed3a80ae6764a

$ curl -sS http://localhost:8000
curl: (52) Empty reply from server

$ docker rm -f localonly
localonly

$ docker run -d --name allif -p 8000:8000 python:3.14-slim python -m http.server 8000 --bind 0.0.0.0
438fa44edf6aec790a7e6b2bfcdb7af33c16a14c661c50b8d9564ff52844e5e6

$ curl -s http://localhost:8000 | head -n 3
<!DOCTYPE HTML>
<html lang="en">
<head>

$ docker rm -f allif
allif
  • 127.0.0.1 だけでリッスンしていると、ポートをマッピングしていても curl は Empty reply from server を返します。トラフィックはコンテナに届いていますが、プログラムはコンテナ自身のlocalhostで待ち受けているため、受信できません。
  • 0.0.0.0 でリッスンするように変更すれば、正常に動作します。

多くの開発用サーバーは、デフォルトでlocalhostだけをリッスンします。コンテナ内で実行するときは、次のように明示してください。

flask run --host 0.0.0.0
uvicorn main:app --host 0.0.0.0
vite --host 0.0.0.0

コンテナからホストに接続する

コンテナからホスト上のサービス(たとえばホスト上で動作しているデータベース)にアクセスするには、特殊な名前 host.docker.internal を使います。

$ docker run --rm alpine:3.23 getent hosts host.docker.internal

$ docker run --rm --add-host=host.docker.internal:host-gateway alpine:3.23 getent hosts host.docker.internal
172.18.0.1        host.docker.internal  host.docker.internal
  • Docker Desktop(Windows、macOS):host.docker.internal を標準でサポートしています。
  • Linux:デフォルトではこの名前を使えません(最初のコマンドは何も出力しません)。--add-host=host.docker.internal:host-gateway を追加すると、Dockerネットワーク上のホストのアドレスに名前解決されます。

ホスト上のサービスも、127.0.0.1 だけではなく、コンテナから接続できるインターフェースでリッスンする必要があります。

hostネットワークとnoneネットワーク

docker run -d --network host nginx:1.30

コンテナはホストのネットワークインターフェースを直接使います。nginxが80番ポートでリッスンすると、ホストの80番ポートを使います。-p は不要です(指定しても無視されます)。パフォーマンスは最も高い一方、分離は失われ、ホスト上のプログラムとポートを取り合うこともあります。Docker Desktopでの動作はLinuxと完全には同じではありません。

一方、--network none を指定すると、ネットワークはなく、ローカルループバックインターフェースだけが使えます。

$ docker run --rm --network none alpine:3.23 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever

ネットワーク接続が不要な処理や、ネットワークに接続すべきでない処理(信頼できないファイルの処理など)に適しています。

トラブルシューティング

コンテナ間でlocalhostに接続できない

コンテナごとに独自の localhost があります。app コンテナ内で localhost:5432 に接続すると、データベースコンテナではなく app 自身に接続します。代わりに db:5432 のようにコンテナ名を使ってください。

ホストからコンテナに接続できない

次の順に確認してください。

  1. docker ps を実行し、PORTS 列に 0.0.0.0:8080->80/tcp があるか確認します。
  2. コンテナ内のプログラムが 0.0.0.0 でリッスンしているか確認します(前述の Empty reply from server が典型的な症状です)。
  3. ホストのファイアウォールまたはクラウドのセキュリティグループで、そのポートが許可されているか確認します。

コンテナからインターネットに接続できない

多くの場合、DNSの問題です。/etc/docker/daemon.json(Docker DesktopではSettings → Docker Engine)でDNSを指定し、変更後にDockerを再起動します。

{ "dns": ["1.1.1.1", "8.8.8.8"] }

Docker Compose を使うと、Composeがプロジェクト用のネットワークを自動で作成します。サービス間はサービス名を使って直接接続できます。

まとめ

  • デフォルトのbridgeネットワークでは名前解決できないため、コンテナ間の通信にはカスタムネットワークを使います。
  • カスタムネットワークでは、コンテナ名または --network-alias を使って相互に接続します。
  • プログラムが 0.0.0.0 でリッスンしていないと、ポートマッピングは機能しません。
  • コンテナからホストへは host.docker.internal を使って接続します。

練習問題

練習 1:ネットワーク lab を作成し、cache という名前の redis:8-alpine コンテナを起動してそのネットワークに接続します。次に、別のコンテナから redis-cli -h cache ping を実行して確認してください。

解答
docker network create lab
docker run -d --name cache --network lab redis:8-alpine
docker run --rm --network lab redis:8-alpine redis-cli -h cache ping

出力は PONG です。ネットワークコマンドについては docker network を参照してください。

よくある質問

コンテナ内で localhost を使っても、別のコンテナに接続できないのはなぜですか?

各コンテナには独自のネットワークがあり、localhost はそのコンテナ自身を指します。別のコンテナに接続するには、両方を同じカスタムネットワークに配置し、コンテナ名を使って接続してください。

コンテナからホスト上で実行中のサービスに接続するにはどうすればよいですか?

Docker Desktop では host.docker.internal を使います。Linux では --add-host host.docker.internal:host-gateway を追加してください。詳しくは、この章の「コンテナからホストに接続する」をご覧ください。

Docker 29 でコンテナの IP を取得するにはどうすればよいですか?

{{.NetworkSettings.IPAddress}} は削除されました。代わりに docker inspect -f "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" コンテナ を使ってください。

更新日 2026年10月14日