【问题标题】:Failing to connect to localhost from inside a container Connection refused无法从容器内连接到 localhost 连接被拒绝
【发布时间】:2018-07-20 12:41:02
【问题描述】:

我目前正在使用 Molecule 测试 Ansible 角色。 基本上,Molecule 会启动一个符合 Ansible 的容器并在其上运行角色。

为了测试容器,Molecule 还使用 Testinfra 嵌入了单元测试。 python 单元测试在容器内运行,因此您可以检查角色的合规性。

由于我正在处理基于 Nginx 的角色,其中一个单元测试只是发出 curl http://localhost:80

我确实收到以下错误消息:

curl: (7) 无法连接到 localhost 80 端口:连接被拒绝

当我:

  • 启动 Vagrant 机器
  • 使用 Ansible 应用角色
  • 通过vagrant ssh连接
  • 发出curl http://localhost 命令

nginx 回答正确。

因此,我认为:

  • 角色工作正常,Nginx 安装正确
  • Docker 有不同的方式来设置网络。在某种程度上,localhost 和 127.0.0.1 已经不一样了

我的问题如下:

  1. 我说的对吗?
  2. 能否克服这种差异,让 curl 发挥作用?

【问题讨论】:

  • 127.0.0.1 在 Docker 中仍然是 localhost - 至少在默认设置下。但是,您的应用程序有时可能会设置为绑定到容器的 veth 接口而不是所有接口。尝试使用ssnetstat 查找您的应用程序绑定的地址。
  • @DanilaKiver:curl http://127.0.0.1 怎么会在 docker 容器中失败,但在 virtualbox 机器上却没有?如果127.0.0.1 仍然是“应该是什么”,这应该可以正常工作。
  • 127.0.0.1 只是一个 IP 地址,分配给特定的接口(通常是lo)。如果应用程序绑定到127.0.0.1/lo 以外的特定地址/接口(例如容器的veth 接口),它将不会响应对127.0.0.1 的请求——这就是套接字的工作方式。这就是为什么我建议查看您的应用程序实际绑定到哪个地址的原因。回答“为什么应用程序在不同的环境中绑定到不同的地址?”问题是下一步,如果你发现我的假设是正确的。
  • 显然,没有端口在监听 (ss -lt): State Recv-Q Send-Q Local Address:Port Peer Address:Port 并且没有进程在运行 (ps -ef | grep -i nginx): ``` root 1454 1453 0 08:04 ? 00:00:00 /bin/sh -c ps -ef | grep nginx 根 1456 1454 0 08:04 ? 00:00:00 grep nginx ``` 当针对 Vagrant 机器的结果完全不同时。

标签: docker nginx ansible molecule


【解决方案1】:

Docker 容器默认在它们自己的网络命名空间中启动。此命名空间包括一个单独的环回接口 (127.0.0.1),它与主机和任何其他容器上的同一接口不同。如果您想从另一个容器或通过主机上的已发布端口访问应用程序,则需要侦听所有接口(0.0.0.0)而不是环回接口。

我经常看到的另一个问题是在连接的某个层(主机,或容器内部),“localhost”名称映射到 /etc/host 文件中的::1 的 IPv6 值,并且在该连接的某处,只有 IPv4 值是有效的(端口发布的位置、应用程序正在侦听的位置,或者主机或 docker 引擎上未启用 IPv6)。因此,请务必尝试直接连接到 IPv4 地址 127.0.0.1,以消除任何潜在的 IPv6 问题。

关于curl 命令以及如何更正它,如果没有更多关于如何运行 curl(它是否在单独的容器中)、如何运行应用程序以及两者如何运行的详细信息,我无法回答这个问题加入网络(您是否在 docker 中创建了一个新网络以运行您的应用程序和单元测试)。典型的解决方案是在 docker 中创建一个新网络,在该网络上运行两个容器,并通过 docker 包含的 DNS 连接到目标的容器或服务名称,例如curl http://my_app/.


编辑:基于 cmets,如果您的应用程序和 curl 命令都在同一个容器中运行,那么 curl http://127.0.0.1/ 应该可以工作。据我所知,curl 不需要任何更改,以使其在容器内部而不是在 VM 上工作。您看到的错误可能是由于应用程序未按预期启动和监听端口,可能是 curl 命令运行过快的竞争条件,或者工具工作方式的基本假设不正确。首先更改单元测试以验证应用程序是否已启动并运行,并使用ps -efss -lt 等命令侦听端口。

【讨论】:

  • 感谢您的回答。 curl 实际上是在同一个容器中运行的。
  • @E.Jaep 如果您在容器内运行curl,您是否也在该容器中运行网络服务器?你用什么命令启动容器?
  • 是的。我用 Ansible 安装了 nginx。
  • @E.Jaep 用 Ansible 在哪里安装了 nginx?在同一个容器中,在不同的容器中,还是您尝试从容器连接到主机?如果 nginx 在同一个容器中,你如何在同一个容器中启动 curl 和 nginx?我们需要查看您的入口点或命令。
  • 基本上,Molecule 会生成一个用于创建容器的 Dockerfile。然后 docker execs 用于在同一个容器上运行 Ansible playbook。一切都发生在 1 个容器内。没有多个容器必须相互通信的概念。
【解决方案2】:

它实际上与 Docker 和 Vagrant 之间的差异(即容器与 VM)无关。

testInfra 代码实际上是从容器/VM 外部运行的,因此subprocess.call(['curl', 'http://localhost']) 失败。

为了从容器/虚拟机运行命令,我应该使用:

host.check_output('curl http://localhost')

【讨论】:

    猜你喜欢
    • 2021-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-04
    相关资源
    最近更新 更多