HAProxy 网络错误:无法绑定套接字


该系列的一部分:
常见的 HAProxy 错误

本教程系列介绍了如何对您在使用HAProxy TCP 和 HTTP 代理服务器时可能遇到的一些最常见错误进行故障排除和修复

本系列中的每个教程都包含对常见 HAProxy 配置、网络、文件系统或权限错误的描述。该系列首先概述了可用于对 HAProxy 进行故障排除的命令和日志文件。后续教程详细检查特定错误。

介绍

cannot bind socket当有另一个进程在侦听 HAProxy 配置使用的同一接口和 TCP 端口组合时,或者当 HAProxy 尝试使用未分配给网络接口的 IP 地址时,会生成HAProxy错误消息。这两种错误情况都源自底层操作系统的网络堆栈。

在第一种情况下,当有另一个进程已经在使用 HAProxy 尝试绑定的接口和端口时,Linux 上的底层错误是EADDRINUSE. 问题是在任何给定时间只能将单个进程绑定到 IP 地址和端口组合。

在第二种情况下,当 HAProxy 尝试使用未分配给系统接口的 IP 地址时,Linux 上的底层错误是EADDRNOTAVAIL. 这里的问题是无法使用操作系统不可用的地址创建 IP 套接字。

但是,这两个底层错误都会生成相同的 HAProxy 错误消息,因此对cannot bind socket错误进行故障排除需要检查 Linx 系统上当前使用的套接字和 IP 地址列表。

要检测cannot bind socket错误消息,您需要检查systemctljournalctl输出以确定导致错误的 IP 地址和端口组合。然后,您可以检查其他正在运行的进程和网络接口,并决定如何解决问题,无论是通过切换服务器、更改 HAProxy 使用的 IP 地址或端口,还是这些选项的任意组合。

故障排除 systemctl

按照本系列开头如何对常见 HAProxy 错误进行故障排除教程中的故障排除步骤进行操作,对cannot bind socket错误消息进行故障排除时的第一步是使用systemctl.

systemctl status在许多情况下,输出将包含解决错误所需的所有诊断信息。它可能包括 HAProxy 正在使用的 IP 地址,以及它试图绑定到的端口。输出还将指示 HAProxy 无法启动的时间,以便您可以确定问题影响 HAProxy 的时间。

注意:如果您使用的是 Ubuntu 或源自 Debian 的 Linux 发行版,systemctl则不包括来自 HAProxy 的输出以及cannot bind socket描述问题错误消息。跳到本教程的下一部分,使用journalctl日志进行故障排除,了解如何检查systemd日志以查找冲突的 IP 地址或端口。

在 CentOS、Fedora 和 RedHat 派生系统上,使用此systemctl命令检查 HAProxy 的状态:

CentOS 和 Fedora 系统
  • sudo systemctl status haproxy.service -l --no-pager

-l标志将确保systemctl输出一行的全部内容,而不是用省略号 ( )替换长行。--no-pager标志会将整个日志输出到您的屏幕,而无需调用这样的工具less,一次只显示一个内容屏幕。

由于您正在对cannot bind socket错误消息进行故障排除,您应该会收到类似于以下内容的输出:

Output
● haproxy.service - HAProxy Load Balancer Loaded: loaded (/usr/lib/systemd/system/haproxy.service; disabled; vendor preset: disabled) Active: failed (Result: exit-code) since Wed 2020-08-19 14:57:05 UTC; 3s ago Process: 138738 ExecStart=/usr/sbin/haproxy -Ws -f $CONFIG -p $PIDFILE (code=exited, status=1/FAILURE) Process: 138736 ExecStartPre=/usr/sbin/haproxy -f $CONFIG -c -q (code=exited, status=0/SUCCESS) Main PID: 138738 (code=exited, status=1/FAILURE) Aug 19 14:57:05 92214d8ff5e2 systemd[1]: Starting HAProxy Load Balancer... Aug 19 14:57:05 92214d8ff5e2 haproxy[138738]: [ALERT] 231/145705 (138738) : Starting frontend main: cannot bind socket [0.0.0.0:80] . . . Aug 19 14:57:05 92214d8ff5e2 systemd[1]: Failed to start HAProxy Load Balancer.

此示例systemctl输出包括systemd日志中描述错误的一些突出显示的行这些行为您提供了有关进一步排除故障所需的错误的所有信息。具体来说,该行cannot bind socket [0.0.0.0:80]描述了 HAProxy 尝试使用的套接字 ( 0.0.0.0:80),因此您可以跳过以下journalctl步骤,转而继续本教程末尾的使用ssps实用程序进行故障排除部分。另一个突出显示的行表示 HAProxy 进程的状态,在出现cannot bind socket错误的情况下会显示Failed to start HAProxy Load Balancer.

如果您的systemctl输出未提供有关导致错误的 IP 地址和端口的特定信息(如果您使用的是 Ubuntu 或 Debian,则适用),则您需要检查日志的journalctl输出systemd以下部分说明如何使用journalctl来排除cannot bind socket错误。

使用journalctl日志进行故障排除

如果您的systemctl输出不包含有关cannot bind socket错误的详细信息,您应该继续使用该journalctl命令检查systemdHAProxy 的日志。

在 Ubuntu 和 Debian 派生系统上,运行以下命令:

  • sudo journalctl -u haproxy.service --since today --no-pager

在 CentOS、Fedora 和 RedHat 派生系统上,使用此命令检查日志:

  • sudo journalctl -u haproxy.service --since today --no-pager

--since today标志将命令的输出限制为仅从当天的 00:00:00 开始记录条目。使用此选项将有助于限制检查错误时需要检查的日志条目的数量。

如果 HAProxy 无法绑定到正在使用的端口,请在输出中搜索与以下日志条目类似的行,特别是包含cannot bind socket本示例中突出显示错误消息的

Output
-- Logs begin at Wed 2020-08-19 19:38:12 UTC, end at Wed 2020-08-19 19:53:53 UTC. -- . . . Aug 19 19:39:21 92214d8ff5e2 systemd[1]: Starting HAProxy Load Balancer... Aug 19 19:39:21 92214d8ff5e2 haproxy[135]: [ALERT] 231/193921 (135) : Starting frontend main: cannot bind socket [0.0.0.0:80] Aug 19 19:39:21 92214d8ff5e2 haproxy[135]: [ALERT] 231/193921 (135) : Starting frontend main: cannot bind socket [:::80] Aug 19 19:39:21 92214d8ff5e2 systemd[1]: haproxy.service: Main process exited, code=exited, status=1/FAILURE Aug 19 19:39:21 92214d8ff5e2 systemd[1]: haproxy.service: Failed with result 'exit-code'. Aug 19 19:39:21 92214d8ff5e2 systemd[1]: Failed to start HAProxy Load Balancer. . . .

输出的第一行突出显示表示 HAProxy 无法绑定到80所有可用 IPv4 接口(由0.0.0.0IP 地址表示上的端口根据您系统的配置,IP 地址可能不同并且仅显示单个 IP。

如果您将 HAProxy 与 IPv6 一起使用,则输出还可能包含像第二行一样的行,该行以 IPv6 特定接口和端口错误突出显示,在本例中为:::80前两个::字符表示所有可用的 IPv6 接口,而尾部:80表示端口。

即使您自己的系统可能有不同的冲突接口和端口,错误也会类似于此处显示的输出。随着从这个输出journalctl,你将能够使用来诊断问题ssps以及ip在本教程的以下部分的命令。

使用ssps实用程序进行故障排除

要对cannot bind socket错误进行故障排除,您需要确定哪些其他进程正在侦听 HAProxy 尝试使用的 IP 地址和端口,或者 IP 地址是否可用于 HAProxy。

例如,如果另一个像 Nginx 这样的服务器被配置为在所有可用的 IPv4 网络接口上侦听端口 8080,则完整的套接字将为0.0.0.0:8080. 如果 HAProxy 也被配置为使用,0.0.0.0:8080那么操作系统将抛出EADDRINUSE错误,并且 HAProxy 将显示一条cannot bind socket错误消息,因为它无法为自己声明套接字。

在上一journalctl节中,某些内容已绑定到所有可用的 IPv4 地址(由 表示0.0.0.0:80)。大多数现代 Linux 发行版都包含一个名为的实用程序ss,可用于收集有关系统网络套接字状态的信息。

以下命令将确定已绑定到端口上 IPv4 接口的进程的名称80如果错误消息中的端口80与以下命令中的端口不同,请确保替换错误消息中的端口

  • sudo ss -4 -tlnp | grep 80

ss命令的标志以下列方式改变其默认输出:

  • -4限制ss为仅显示与 IPv4 相关的套接字信息。
  • -t将输出限制为tcp仅套接字。
  • -l显示所有考虑-4-t限制的侦听套接字
  • -n确保显示端口号,而不是像“http orhttps ”这样的协议名称这很重要,因为 HAProxy 可能会尝试绑定到非标准端口,并且服务名称可能与实际端口号相反。
  • -p 输出有关绑定到端口的进程的信息。
  • | grep 80将输出限制为包含字符80的行,因此您需要检查的行更少

注意:在此 IPv4 和以下 IPv6 示例中,如果您的输出中没有包含匹配端口的行,则您的cannot bind socket错误可能源自EADDRNOTAVAIL错误。跳到下一节使用ip实用程序进行故障排除以检查系统上的可用 IP 地址。

使用所有这些标志,您应该会收到如下输出:

Output
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=40,fd=6))

前三个字段在排除cannot bind socket错误时并不重要,因此可以忽略它们。重要的字段是第四个 ( 0.0.0.0:80),它匹配journalctl您之前发现错误,以及最后一个users:(("nginx",pid=40,fd=6)),特别是pid=40部分。

如果您遇到cannot bind socket与 IPv6 接口相关错误,请重复ss调用,这次使用-6标志将接口限制为 IPv6 网络堆栈,如下所示:

  • sudo ss -6 -tlnp |grep 80

-6标志将ip命令限制为 IPv6 接口。如果 HAProxy 无法绑定到 IPv6 套接字,您应该有如下输出:

Output
LISTEN 0 511 [::]:80 [::]:* users:(("nginx",pid=40,fd=7))

同样,journalctl如果与80此处给出的突出显示不同,请替换输出中的相关端口号

在 IPv4 和 IPv6 错误的这两种情况下,ss输出表明有一个进程 ID 为 40(pid=40在输出中)的程序分别绑定到0.0.0.0:80[::]:80接口。此过程会阻止 HAProxy 启动,因为它已经拥有该端口。要确定程序的名称,请使用这样的ps实用程序,用输出中的进程 ID 代替40本例中突出显示的值:

  • sudo ps -p 40

您将收到类似于以下内容的输出:

Output
PID TTY TIME CMD 40 ? 00:00:00 nginx

nginx输出中突出显示的是正在侦听接口的进程的名称。现在您已经知道阻止 HAProxy 启动的程序的名称,您可以决定如何解决错误。您可以停止nginx进程,重新配置nginx以侦听不同的接口和端口,或重新配置 HAProxy 以避免端口冲突。

重要的是要注意,该过程可能nginx与端口和 IP 地址不同,并且端口和 IP 地址可能并不总是如此,0.0.0.0或者[::]如果您正在诊断cannot bind socket错误。通常,不同的 Web 服务器和代理会在同一台服务器上使用。每个人都可能试图绑定到不同的 IPv4 端口和 IPv6 接口来处理不同的网络流量。例如,配置了 HAProxy 侦听localhost端口上 IPv4 环回地址(也称为)的服务器8080将显示如下ss输出:

Output
LISTEN 0 2000 127.0.0.1:8080 0.0.0.0:* users:(("haproxy",pid=545,fd=7))

systemctl输出或journalctl指示特定 IP 地址和端口的输出与来自 的诊断数据相结合ss,然后ps缩小导致 HAProxy 无法启动的进程的范围,这一点很重要。

有时,当您对cannot bind socket错误消息进行故障排除ssps根本不会有任何输出,这意味着该错误可能不是由套接字冲突引起的。本教程的下一部分将说明如何cannot bind socket使用该ip实用程序错误进行故障排除

使用ip实用程序进行故障排除

上一节解释了EADDRINUSE操作系统错误如何导致cannot bind socket错误消息。但是,如果您已经检查ssps输出并且您的系统上没有套接字冲突,则问题可能是由EADDRNOTAVAIL操作系统错误引起的在这种情况下,HAProxy 可能会尝试绑定到您的操作系统不可用的套接字。

要确定cannot bind socket错误是否由 引起,EADDRNOTAVAIL请使用ip命令检查系统上的 IPv4 和 IPv6 网络接口

  • sudo ip -4 -c address show
  • -4限制ip只显示与 IPv4 相关的接口信息。
  • -c 向输出添加颜色编码,以便更容易在视觉上解析。
  • address show显示接口的 IP 地址,-4-c考虑标志。

在包含该ip工具的任何 Linux 发行版上,您应该会收到类似于以下内容的输出

Output
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 inet 203.0.113.1/24 brd 203.0.113.255 scope global eth0 valid_lft forever preferred_lft forever inet 192.0.2.1/24 brd 192.0.2.255 scope global eth0 valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 inet 198.51.100.1/24 brd 198.51.100.255 scope global eth1 valid_lft forever preferred_lft forever

记下与此输出中突出显示的示例相对应的 IP 地址。您的 IP 地址和网络接口将与此处显示的示例不同。您可能有更多或更少的接口,每个接口都可能有更多或更少的地址分配给它们。重要的部分是记下来自ip.

要检查分配给系统的 IPv6 地址,请使用ip带有如下-6标志命令

  • sudo ip -6 -c address show

您应该收到如下输出:

Output
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000 inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000 inet6 2604:a880:400:d1::3d3:6001/64 scope global valid_lft forever preferred_lft forever inet6 fe80::a4ff:aaff:fec9:24f8/64 scope link valid_lft forever preferred_lft forever

再次注意此示例输出中突出显示的值,并在输出中查找相应的 IPv6 地址。

获得分配给系统的地址列表后,您可以尝试查找与cannot bind socket [x.x.x.x:80]错误对应的匹配 IP 地址如果没有匹配的 IP 地址,则 HAProxy 可能配置为使用您的系统不可用的 IP 地址,并且cannot bind socket错误是由操作系统抛出EADDRNOTAVAIL错误引起的

要解决该错误,您需要编辑您的/etc/haproxy/haproxy.cfg文件,并将一个bind或多个地址更改为基于ip命令输出的系统可用的 IP 地址

例如,如果/etc/haproxy/haproxy.cfg包含bind如下198.51.100.123用作 IP 地址的行,但您的系统已198.51.100.1根据上面的示例输出进行分配,则需要编辑绑定行。

按照这个假设的例子,这个haproxy.cfg片段显示了无效的 IP 地址:

/etc/haproxy/haproxy.cfg
. . .
frontend main
        bind 198.51.100.123:80

bind与示例ip输出中的 IP 地址匹配的正确如下所示:

/etc/haproxy/haproxy.cfg
. . .
frontend main
        bind 198.51.100.1:80

/etc/haproxy/haproxy.cfg使用正确的 IP 地址进行编辑后,使用以下systemctl命令重新启动它

  • sudo systemctl restart haproxy.service

现在检查 HAProxy 的状态并确保输出显示active (running)一行:

  • sudo systemctl status haproxy.service
Output
● haproxy.service - HAProxy Load Balancer Loaded: loaded (/lib/systemd/system/haproxy.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2020-08-19 21:31:46 UTC; 17h ago Docs: man:haproxy(1) file:/usr/share/doc/haproxy/configuration.txt.gz Process: 487 ExecStartPre=/usr/sbin/haproxy -f $CONFIG -c -q $EXTRAOPTS (code=exited, status=0/SUCCESS) . . . Aug 19 21:31:46 d6cdd0c71489 systemd[1]: Started HAProxy Load Balancer.

如果您已经解决了cannot bind socket错误,您的输出应该类似于此示例输出。突出显示的行显示 HAProxy 处于活动状态,并且进程已成功启动。

结论

在本教程中,您学习了如何对cannot bind socketIPv4 和 IPv6 接口上的 HAProxy错误消息进行故障排除您学习了如何使用systemctl来检查 HAProxy 服务器的状态并尝试查找错误消息。您还学习了如何使用journalctl来检查systemd日志以获取有关cannot bind socket错误的特定信息

通过systemd日志中的相应错误消息,您可以了解该ss实用程序以及如何使用它来检查系统网络套接字的状态。之后,您学习了如何将来自ssps实用程序的进程 ID 信息结合起来以查找导致 HAProxy 无法启动的进程名称。

最后,在cannot bind socket出现与不可用 IPv4 或 IPv6 地址相关错误时,您学习了如何使用该ip实用程序检查系统上可用的网络接口。

觉得文章有用?

点个广告表达一下你的爱意吧 !😁