目次
Docker ネットワークチュートリアル:bridge、カスタムネットワーク、コンテナ間通信
アプリケーションがデータベースやキャッシュなど、ほかのコンテナに接続するときは、Docker のネットワークを理解する必要があります。最も重要なポイントは、通信させたいコンテナを同じカスタムネットワークに配置すれば、コンテナ名で相互に接続できることです。
ネットワークドライバー
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 のようにコンテナ名を使ってください。
ホストからコンテナに接続できない
次の順に確認してください。
docker psを実行し、PORTS列に0.0.0.0:8080->80/tcpがあるか確認します。- コンテナ内のプログラムが
0.0.0.0でリッスンしているか確認します(前述のEmpty reply from serverが典型的な症状です)。 - ホストのファイアウォールまたはクラウドのセキュリティグループで、そのポートが許可されているか確認します。
コンテナからインターネットに接続できない
多くの場合、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日