[Docker] ネットワーク共有なしで、ホストポートを使用してコンテナ間通信する方法 (host.docker.internal)



タグ: Docker, DevOps, Network, host.docker.internal

1. 問題の状況

開発環境で複数のサービスをDockerで管理することがよくあります。

  • App-A (例: DRF)はnetwork-Aにあります。

  • App-B (例: Nextcloud)はnetwork-Bにあります。

  • 2つのコンテナは同じホストマシンで実行されています。

  • App-Bはホストの8080ポートとバインディングされています。 (例: docker run -p 8080:80 ...)

App-AからApp-BをAPIで呼び出す必要があります。ただし、面倒なので2つのネットワークをブリッジで接続したくありません。ホストの8080ポートに直接アクセスできないのでしょうか?

コンテナ内からlocalhost:8080または127.0.0.1:8080を呼び出すと、これはホストマシンではなく、コンテナ自身を指します。

2. 解決策: host.docker.internal

最も簡単な解決策は、host.docker.internalという特別なDNS名を使用することです。

host.docker.internal: コンテナ内からホストマシンのIPアドレスに解釈される特別なホスト名です。

App-A (DRF)のコードからNextcloudを呼び出す際、URLを次のように設定します。

# DRF (App-A) 内部コード
import requests

# 'localhost'の代わりに'host.docker.internal'を使用します。
NEXTCLOUD_URL = "http://host.docker.internal:8080"

try:
    response = requests.get(NEXTCLOUD_URL)
    print(f"Nextcloud接続成功: {response.status_code}")
except requests.exceptions.ConnectionError:
    print("Nextcloud接続失敗")

コンテナ内でcurlを使ってテストする際も同様です。

# App-Aコンテナ内で実行
curl http://host.docker.internal:8080

3. ⚠️ 注意: Linuxホスト環境設定

Docker Desktop (macOS, Windows)を使用している場合、host.docker.internalはデフォルトで機能します。

しかし、Linuxホスト環境では、この設定を手動で追加する必要があります。host-gatewayという特別なキーワードを使用して、ホストIPをマッピングできます。

方法1: docker runを使用する場合

--add-hostフラグを追加します。

docker run \
  --add-host=host.docker.internal:host-gateway \
  --network network-A \
  my-drf-app-image

方法2: docker-compose.ymlを使用する場合

App-A (DRF)サービスにextra_hostsを追加します。

services:
  drf-app:
    image: my-drf-app-image
    networks:
      - network-A
    extra_hosts:
      # host.docker.internalをホストマシンのIP(host-gateway)にマッピング
      - "host.docker.internal:host-gateway"

# ... (network-Aの定義) ...

4. まとめ

分離されたDockerネットワーク間で通信を行う場合、ネットワークを複雑に接続する必要はありません。

  1. 呼び出し対象のコンテナ(Nextcloud)をホストポート(8080)にバインドします。

  2. 呼び出すコンテナ(DRF)からhttp://host.docker.internal:8080アドレスにリクエストを送ります。

  3. ホストがLinuxの場合、呼び出すコンテナにextra_hosts (host.docker.internal:host-gateway)設定を追加することを忘れないでください。