[Docker] 无需网络共享,通过主机端口实现容器间通信 (host.docker.internal)



标签: Docker, DevOps, 网络, 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 中调用 App-B 的 API。 我不想麻烦地将两个网络连接在一起。 我可以直接调用主机的 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) 设置。