[Docker] 在無網絡共享的情況下,使用主機端口進行容器間通信 (host.docker.internal)



標籤: Docker, DevOps, Networking, host.docker.internal

1. 問題情況

在開發環境中經常使用 Docker 管理多個服務。

  • App-A (例如: DRF) 在 network-A 上。

  • App-B (例如: Nextcloud) 在 network-B 上。

  • 這兩個容器在同一主機上運行。

  • App-B 綁定到主機的 8080 埠。(例如: docker run -p 8080:80 ...)

App-A 需要通過 API 調用 App-B。我不想麻煩地將這兩個網絡通過橋接連接起來,那我能否直接調用主機的 8080 埠呢?

如果在容器內部調用 localhost:8080127.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

# 使用 'host.docker.internal' 代替 'localhost'
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) 設置。