Docker-Compose:当host.docker.internal无法工作时连接主机

4

我的最终目标是允许运行FastAPI应用程序的容器与主机上的MySQL数据库进行通信。

首先我尝试使用host.docker.internal

Dockerfile

FROM debian:latest

RUN apt update && apt install -y \
    netcat \
    iputils-ping

CMD echo "tailing /dev/null" && tail -f /dev/null

docker-compose.yml

version: "3.2"

services:
  test:
    build:
      context: "."
    extra_hosts:
      - "host.docker.internal:host-gateway"

期望表现:ping 能够正常工作,nc -vz 也能够正常工作

特别地,使用 nc -vz 命令,我期望看到类似以下的输出:

root@9fe8de220d44:/# nc -vz host.docker.internal 80
Connection to host.docker.internal (172.17.0.1) port 80 (tcp) succeeded!

实际行为:ping 可用,nc -vz 不可用

root@5981bcfbf598:/# ping host.docker.internal
PING host.docker.internal (172.17.0.1) 56(84) bytes of data.
64 bytes from host.docker.internal (172.17.0.1): icmp_seq=1 ttl=64 time=0.079 ms
64 bytes from host.docker.internal (172.17.0.1): icmp_seq=2 ttl=64 time=0.067 ms
64 bytes from host.docker.internal (172.17.0.1): icmp_seq=3 ttl=64 time=0.068 ms
^C
--- host.docker.internal ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2013ms
rtt min/avg/max/mdev = 0.067/0.071/0.079/0.005 ms
root@5981bcfbf598:/# nc -vz host.docker.internal 80
nc: connect to host.docker.internal (172.17.0.1) port 80 (tcp) failed: Connection refused

在主机上

我在端口80上运行了 Apache。

$ netstat -tulpn
...
tcp6       0      0 :::80                   :::*                    LISTEN      1258/apache2

此外,我的防火墙已配置为允许所有传入的80端口请求:防火墙显示允许所有IPv4和IPv6的HTTP端口80

操作系统和Docker版本:

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.6 LTS
Release:    18.04
Codename:   bionic
$ docker --version
Docker version 20.10.21, build baeda1f

手动指定网络也失败

host.docker.internal 失败后,我按照这里的说明连接到了一个手动指定的网络(在我的情况下是 Ubuntu 18.04 的 Linux 主机):https://dev59.com/zlEG5IYBdhLWcg3wM2Zu#70725882

这是我的设置:

Dockerfile

FROM debian:latest

RUN apt update && apt install -y \
    netcat \
    iputils-ping

CMD echo "tailing /dev/null" && tail -f /dev/null

docker-compose.yml

version: "3.2"

networks:
  test:
    name: test-network
    attachable: true
    ipam:
      driver: default
      config:
        - subnet: 172.42.0.0/16
          ip_range: 172.42.5.0/24
          gateway: 172.42.0.1

services:
  test:
    build:
      context: "."
    networks:
      - test

确认网关

$ docker inspect test-test-1  -f '{{range .NetworkSettings.Networks}}{{.Gateway}}{{end}}'
172.42.0.1

ping正常

root@07f81c211a0c:/# ping 172.42.0.1
PING 172.42.0.1 (172.42.0.1) 56(84) bytes of data.
64 bytes from 172.42.0.1: icmp_seq=1 ttl=64 time=0.056 ms
64 bytes from 172.42.0.1: icmp_seq=2 ttl=64 time=0.068 ms
64 bytes from 172.42.0.1: icmp_seq=3 ttl=64 time=0.065 ms

期望行为:nc -vz成功

根据https://dev59.com/zlEG5IYBdhLWcg3wM2Zu#70725882的说明:

root@9fe8de220d44:/# nc -vz 172.18.0.1 80
Connection to 172.18.0.1 80 port [tcp/http] succeeded!

实际行为:nc -vz失败

root@07f81c211a0c:/# nc -vz 172.42.0.1 80
nc: connect to 172.42.0.1 port 80 (tcp) failed: Connection refused

我做错了什么?

提前感谢您的帮助!


你的设置实际目标是什么?容器中实际运行的程序是什么,当它接收到ping(1)发送的ICMP数据包时会做什么?Docker内部IP地址大多数情况下都是实现细节,你几乎永远不需要查找或手动指定它们。 - David Maze
关于增加更多上下文的观点很好。我在顶部添加了一点: “我的最终目标是允许运行FastAPI应用程序的容器与主机上的MySQL数据库通信。” - AJ Livingston
我所链接的答案解释了为什么你可能想要使用手动指定的网络:"如果你只明确授权从172.17.0.1到主机上本地服务的端口的连接,那么这可能会给你带来一些麻烦。事实上,无法从容器内部ping通该服务的端口,正是因为网关地址(172.22.0.1)不同而导致的。" - AJ Livingston
我在顶部添加了一个部分,显示host.docker.internal以同样的方式失败。希望这足够提供上下文,不会被投票降低评分? - AJ Livingston
1个回答

1

更新

下面的答案适用于连接主机的一般问题,但是如果您想公开具有套接字的特定服务,则有一个更简单的解决方案:挂载套接字!例如,如果您想连接到本地mysql,则可以在docker-compose.yml中添加:

    volumes:
      - /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysqld.sock:ro

对于需要与MySQL主机通信的任何服务,只需简单地指定您要使用Unix套接字即可。如果您正在使用MySQL的URL语法,则可以在SQLAlchemy中指定,例如:

mysql+pymysql://user:passwd@host/db?unix_socket=/var/run/mysqld/mysqld.sock

翻译后的回答

我能够通过https://forums.docker.com/t/how-to-connect-from-docker-container-to-the-host/123318解决了这个问题。

我运行了

$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet XXX.XXX.XXX.XXX  netmask ...

我复制了地址XXX.XXX.XXX.XXX,并在我的docker-compose.yml中用它替换了host-gateway
version: "3.2"

services:
  test:
    build:
      context: "."
    extra_hosts:
      - "host.docker.internal:XXX.XXX.XXX.XXX"

现在,在容器内部:

root@f5836a37815a:/# nc -vz host.docker.internal 80
Connection to host.docker.internal (104.248.221.215) 80 port [tcp/*] succeeded!

我不确定为什么所有使用host-gateway的建议都没有起作用。我认为它应该适用于我的docker(compose)版本。

$ docker version
Client: Docker Engine - Community
 Version:           20.10.21
...
$ docker compose version
Docker Compose version v2.12.2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接