SSD Nodes Learn メモリ 8GB — 年額 $66
ガイド Matt Connor著者 Matt Connor ・更新日 2026-08-01

Docker ComposeのネットワークとDNS、hostモードを解説

Composeのデフォルトbridge、サービス名DNS、hostモードの使いどころ、複数プロジェクトでのネットワーク共有を解説します。公開ポートがUFWを迂回する注意点も確認できます。

アプリケーションの起動前にComposeが構築するもの

Docker Composeのネットワークは、次のルールで開始します。docker compose upはプロジェクト用のプライベートネットワークを作成し、すべてのサービスを接続します。各サービスは、サービス名で相互にアクセスできます。これを実現するために、networks:の行を1行も記述する必要はありません。Composeのネットワークで混乱しやすい理由の多くは、デフォルト設定がすでに存在することを知らないためです。

小さなファイルを示します。shopというディレクトリに、compose.yamlとして保存してください。

services:
  web:
    image: nginx:1.27
    ports:
      - "8080:80"
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example

起動して、Dockerが作成したものを確認します。

docker compose up -d
docker network ls

一覧に、shop_defaultという名前のネットワークが表示されます。Composeはこれを<project>_defaultと命名します。プロジェクト名のデフォルト値は、ディレクトリ名を小文字にしたものです。docker compose -p myproject up -d、またはファイル内のトップレベルのname: myprojectで上書きできます。ドライバーはbridgeです。これはホスト内部の仮想スイッチです。各コンテナはプライベートサブネット上のアドレスを取得します。外向きのトラフィックは、外部へ出る際にホストのアドレスへ変換されます。

docker compose downは、このネットワークを再び削除します。古いプロジェクトの残存コンテナがネットワークを保持できるのはこのためです。Dockerはerror while removing network: network shop_default has active endpointsで拒否します。接続されたままのコンテナを停止または削除すれば解決できます。

Composeを初めて使う場合は、まずComposeファイルの構成とライフサイクルコマンドを読むとよいでしょう。以下では、プロジェクトを起動および停止できることを前提としています。

サービス名による DNS は初心者が見落とす部分です

ユーザー定義ネットワークでは、Docker が組み込み DNS サーバーを実行し、各コンテナは 127.0.0.11 でそれを利用します。この DNS はサービス名を現在のコンテナアドレスに解決します。そのため、web は設定なしで、ホスト名 db のデータベースにポート 5432 で接続できます。

docker compose exec web getent hosts db

172.18.0.2 db のような行が出力されます。何も出力されない場合、2つのサービスは同じネットワーク上にありません。

ほとんどの人が一度は犯す間違いは、アプリケーション設定で localhost を使うことです。コンテナ内では、localhost はそのコンテナ自身を指します。ホストや別のサービスは指しません。Postgres クライアントはこれを明確に報告します。

could not connect to server: Connection refused
	Is the server running on host "localhost" (127.0.0.1) and accepting
	TCP connections on port 5432?

接続文字列は postgresql://postgres:example@db:5432/postgres にします。ホスト部分にはサービス名を指定します。

後で役立つ重要な点が2つあります。名前は現在実行中のコンテナに解決されるため、docker compose up -d --scale web=3 は1つの名前に3つのアドレスを返します。DNS を無期限にキャッシュするクライアントは、停止したコンテナに固定されます。また、--network を指定しない単純な docker run が使用するレガシーな bridge ネットワークでは、名前解決がまったく機能しません。そのため、2016年のコンテナリンクに関する説明は、現在の環境で確認できる動作と一致しません。

2つのサービスを接続するためにports:は必要ありません

ports:はコンテナのポートをホスト上に公開します。Dockerの外部から到着するネットワークトラフィックに使用します。サービス間の通信とは関係ありません。サービス間の通信は、プロジェクトネットワーク上の全ポート範囲ですでに機能します。

そのため、多くの人がデータベースサービスに追加するports: - "5432:5432"は役に立たず、実害があります。サーバーのパブリックインターフェースでPostgresを公開してしまうためです。削除してください。移行作業のためにノートPCから接続する場合は、"127.0.0.1:5432:5432"でloopbackにバインドし、SSHトンネル経由で接続してください。listening socket、公開ポート、firewallルールの違いについては、Linuxでポートとlistening serviceが機能する仕組みで説明しています。

Composeでは、expose:はドキュメントとしてのみ機能します。同じネットワーク上のコンテナ間で閉じられているものはないため、何も開きません。

network_mode host が適切な場合と、その代償

Host mode ではコンテナ独自のネットワーク namespace を削除し、プロセスがホストのインターフェースを直接使用できるようにします。

services:
  probe:
    image: alpine:3.20
    network_mode: host
    command: sleep infinity

これを必要とする正当な理由があります。ローカルネットワーク上のブロードキャストまたはマルチキャストトラフィックを認識する必要があるプロセスは、bridge の背後からはそのトラフィックを認識できません。bridge はそのトラフィックをコンテナへ転送しないためです。たとえば、メディアサーバーやホームオートメーションハブのデバイス検出が該当します。ホストのインターフェースカウンターを読み取る監視エージェントにも、ホストのインターフェースが必要です。また、アドレス変換の経由を省略できるため、高いパケットレートでは有効です。

代償は明確です。

ports: は機能しなくなります。Docker は、host network mode を使用すると公開ポートが破棄され、コンテナはプロセスが bind するポートをそのまま使用すると警告します。port 8080 を使用する host mode コンテナが2つあると衝突し、2つ目は bind: address already in use で終了します。

サービス名による名前解決は、両方向で利用できなくなります。コンテナは project network に接続されていないため、db を名前解決できません。他のサービスもコンテナを名前解決できません。コンテナが他のサービスへ接続できるのは、通常 127.0.0.1 でホストに公開されたポートを経由する場合だけです。

分離は失われます。host mode コンテナ内のプロセスが 0.0.0.0 に bind すると、apt でインストールしたパッケージと同じように、サーバーのすべてのインターフェースで待ち受けます。パブリックインターフェースも含まれます。ただし、利点も1つあります。このトラフィックは通常の input 経路を通るため、UFW のルールが適用されます。公開ポートには適用されない動作です。

Host mode は Linux Docker Engine の機能です。Docker Desktop では version 4.34 以降でのみサポートされ、事前に有効化する必要があります。さらに、コンテナはホストの IP アドレスに bind できず、処理できるのは TCP と UDP だけです。チームの半数が Linux サーバーを使用し、残りの半数が Docker Desktop を使用している場合、同じファイルでも動作が異なる可能性があります。

ホストのインターフェースが必要な場合に host mode を使用してください。接続問題の解決には使用しないでください。通常は、1つの問題をより難しい問題に置き換えるだけです。

外部ネットワークで2つのComposeプロジェクトを接続する

一方のプロジェクトが作成したネットワークは、別のプロジェクトからは見えません。そのため、同じサーバー上でも、proxy/compose.yaml のリバースプロキシから app/compose.yaml のアプリケーションを確認できません。解決策は、どちらのプロジェクトも所有しないネットワークを使用することです。

次のコマンドを手動で1回だけ実行して作成します。

docker network create edge

次に、各プロジェクトで外部ネットワークとして宣言します。プロキシ側は次のようにします。

services:
  proxy:
    image: traefik:v3.1
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - edge

networks:
  edge:
    name: edge
    external: true

アプリケーション側は次のようにします。

services:
  app:
    image: nginx:1.27
    networks:
      - edge
      - internal
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example
    networks:
      - internal

networks:
  edge:
    name: edge
    external: true
  internal:

external: true は、Composeに新しいネットワークを作成させず、既存のネットワークに接続させます。また、docker compose down でもそのネットワークを残します。独立した name: キーも重要です。これがない場合、Composeは名前が正確に edge のネットワークを探します。これがあると、ファイル内のネットワーク名とホスト上のネットワーク名を別々に指定できます。

ネットワークが存在しない場合、Composeは起動を拒否し、そのネットワークが外部ネットワークとして宣言されているものの見つからないと報告します。先にネットワークを作成してください。

アプリケーションのファイルで internal がどのように設定されているかにも注目してください。データベースはそのプロジェクト専用のネットワークにのみ接続されるため、プロキシからデータベースには到達できず、app だけが到達できます。ネットワークの下に internal: true を追加すると、外部ネットワークへの経路も完全に削除されます。これはデータベースの適切なデフォルト設定です。ただし、設定前に知っておくべき点があります。内部ネットワーク上のコンテナは何もダウンロードできないため、起動時に apt-get update または pip install を実行するentrypointはハングし、その後タイムアウトで失敗します。

ルーティングルールと証明書を含む完全な設定例については、1つのTraefikインスタンスの背後で複数のアプリケーションを実行するを参照してください。

公開ポートはUFWを迂回します

ここは、Composeのネットワーク設定がセキュリティインシデントにつながる部分です。ポートを公開し、UFWが有効でSSH以外をすべて拒否していることを確認しても、サービスにはインターネットからアクセスできます。

sudo ufw status
curl http://203.0.113.10:8080

UFWではポートがブロックされていると表示されます。しかし、curlはページを返します。これは故障ではありません。Dockerは独自のアドレス変換ルールとフォワーディングルールをiptablesに直接書き込みます。公開されたコンテナポート宛てのトラフィックはホストに配信されず、コンテナへ転送されます。そのため、ローカル宛てのトラフィックをUFWが管理するチェーンを通りません。DockerのルールはUFWのルールより先に照合されます。

簡単な対処方法は、必要な場所にだけ公開することです。

    ports:
      - "127.0.0.1:8080:80"

これにより、ホスト側はloopbackにバインドされます。そのため、ポートにはサーバー自体とSSHトンネル経由からアクセスできますが、それ以外の場所からはアクセスできません。公開エントリポイントは、80と443を意図的に公開するreverse proxyの背後に配置してください。公開ポートをフィルタリングする必要がある場合のDOCKER-USERチェーンを含む詳しい説明は、DockerがUFWを直接迂回して公開する理由と修正方法にあります。

4つのコマンドでデバッグする方法

まず、各コンテナが実際に接続しているネットワークを確認します。

docker network inspect shop_default

Containers ブロックには、接続されているすべてのコンテナとそのアドレスが表示されます。この一覧にないサービスは、別のネットワーク上にあるか、host モードで実行されているか、起動していません。

同じネットワークに接続した一時コンテナから名前解決をテストします。これにより、使用中のイメージにツールをインストールする必要がありません。

docker run --rm --network shop_default busybox nslookup db
docker run --rm --network shop_default busybox nc -zv db 5432

nslookup が失敗する場合は、名前解決またはネットワークへの接続に問題があります。nslookup が成功し、nc が失敗する場合、サービスは実行されていますが、そのポートで待ち受けていないか、127.0.0.1 ではなくコンテナ内部の 0.0.0.0 で待ち受けています。後者は開発用サーバーでよく発生します。修正する場所は Docker ではなく、アプリケーションの bind address です。

Docker のバグに見える、もう1つの障害があります。コンテナ間では通信できるのに、オフィスネットワークまたは VPN ネットワーク上のマシンに接続できない場合、Docker のサブネットがそのネットワークと重複している可能性があります。Docker はデフォルトで 172.17.0.0/16 から割り当てます。/etc/docker/daemon.json でアドレスプールを変更します。

{
  "default-address-pools": [
    { "base": "10.200.0.0/16", "size": 24 }
  ]
}

次に sudo systemctl restart docker を実行し、影響を受けるネットワークを再作成します。既存のネットワークは、作成時のサブネットを保持するためです。

FAQ

サービス名でコンテナ同士が接続できないのはなぜですか?

同じネットワーク上にないためです。Compose はすべてのサービスを自動的に <project>_default 上に配置します。ただし、サービスに networks: リストを追加すると、そのリストがそのサービスのネットワークの完全な一覧になり、デフォルトネットワークは暗黙的に追加されなくなります。docker network inspect <network> を実行し、両方のコンテナが Containers ブロックに表示されることを確認してください。また、どちらのサービスも network_mode: host を使用していないことを確認してください。host モードのコンテナは Docker ネットワーク上に存在せず、サービス名を解決できません。

あるサービスから別のサービスに接続する場合、ポートを公開する必要がありますか?

いいえ。Compose ネットワーク上では、各コンテナのすべてのポートに、そのネットワーク上の他のコンテナから到達できます。ports: は、Docker 外部からのトラフィックにコンテナを公開するためだけに使用します。expose: はドキュメント用です。データベースポートの公開は、よくあるうえに危険な習慣です。データベースがサーバーのパブリックインターフェース上に公開されるためです。

bridge ネットワークと host ネットワークの違いは何ですか?

bridge は、コンテナに独自のネットワーク名前空間と仮想スイッチ上のアドレスを割り当てます。コンテナ間の名前解決が自動的に行われ、外向きのトラフィックは変換されます。host は、コンテナからホストのネットワークスタックを直接使用します。独立したアドレス、サービス名による名前解決、ポート公開はなく、ホスト上の他のリスナーから分離されません。デフォルトは bridge です。プロセスがホストのインターフェースを必要としない限り、bridge を使用してください。

2つの異なる Compose ファイルのコンテナを接続するにはどうすればよいですか?

docker network create edge で共有ネットワークを作成し、両方のファイルで external: true を使用してそのネットワークを宣言します。その後、通信が必要なサービスを接続してください。Compose はそのネットワークを作成も削除もしません。作成手順を省略すると、Compose は起動を拒否し、ネットワークが外部ネットワークとして宣言されているが見つからないと報告します。

UFW でポートをブロックしているのに、コンテナがインターネットから到達可能なのはなぜですか?

公開ポートは、Docker が iptables に追加する転送ルールによって処理されるためです。これらのルールは UFW のルールより先に照合されます。また、転送されたトラフィックは、UFW がフィルタリングするチェーンを通過しません。"127.0.0.1:8080:80" でホスト側を loopback にバインドし、公開するものはすべてポート 80 と 443 の reverse proxy の背後に配置してください。