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

简介

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

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

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

然而,这两个底层错误都会生成相同的HAProxy错误消息,因此要排除无法绑定套接字错误,需要检查Linx系统上当前使用的套接字和IP地址的列表。

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

systemctl故障排除

按照本系列开头的如何排除常见HAProxy Errors故障]教程中的故障排除步骤,您在排除无法绑定socket错误消息时的第一步是使用systemctl检查HAProxy的状态。

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

<$>[备注] 注意 :如果您使用的是Ubuntu或Debian派生的Linux发行版,systemctl不会包含HAProxy的输出以及描述该问题的Cannot Bind socket错误消息。请跳至本教程的下一节[使用Journal alctl日志排查故障](# Troublroublem-Using-Jouralctl-Logs),了解如何检查systemd日志以发现冲突的IP地址或端口。 <$>

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

1[label CentOS and Fedora Systems]
2sudo systemctl status haproxy.service -l --no-pager

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

由于您正在排除Cannot Bind socket错误消息,您应该会收到类似于以下内容的输出:

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

此示例systemctl输出包括一些高亮显示的行,这些行来自描述错误的systemd日志。这些行为您提供了进一步排除故障所需的有关错误的所有信息。具体来说,无法绑定套接字[0.0.0.0:80]这行描述的是HAProxy尝试使用的套接字(0.0.0.0:80),因此您可以跳过下面的Utilities](# troubleshooting-with-ss-and-ps-utilities)步骤,转到本教程结尾处的[使用sspsJouralctl进行故障排除]部分。另一条突出显示的行表示HAProxy进程的状态,如果出现Cannot Bind socket错误,它将显示无法启动HAProxy Load Balancer。

如果您的systemctl输出没有给出有关导致错误的IP地址和端口的具体信息(如果您使用的是Ubuntu或Debian,则适用),那么您将需要检查systemd日志中的journalctl输出。下面的部分解释了如何使用journalctl来解决cannot bind socket错误。

使用Journal alctl日志排查问题

如果您的systemctl输出不包含有关Cannot Bind socket错误的详细信息,则应继续使用Journal alctl命令检查systemd日志中的HAProxy。

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

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

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

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

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

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

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

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

如果您使用的是IPv6的HAProxy,那么输出可能还包括一行类似第二行的内容,突出显示了IPv6特定的接口和端口错误,在本例中为:80。前两个::字符表示所有可用的IPv6接口,而末尾的:80表示端口。

即使您自己的系统可能具有不同的冲突接口和端口,错误也将类似于此处显示的输出。在本教程的下一节中,您将能够使用sspsip命令来诊断问题。

使用ssps工具排查问题

要排除`无法绑定套接字‘错误,您需要确定其他进程正在侦听HAProxy尝试使用的IP地址和端口,或者该IP地址是否可供HAProxy使用。

例如,如果将另一台服务器配置为监听所有可用IPv4网络接口上的8080端口,则全套接字为0.0.0.0:8080。如果HAProxy也配置为使用0.0.0.0:8080,则操作系统将抛出EADDRINUSE错误,并且HAProxy将显示Cannot Bind socket错误消息,因为它不能为自己声明套接字。

在前面的)。大多数现代Linux发行版都包含一个名为ss的实用程序,可以用来收集有关系统网络套接字状态的信息。

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

1sudo ss -4 -tlnp | grep 80

`ss‘命令的标志通过以下方式更改其默认输出:

  • -4限制ss只显示与IPv4相关的套接字信息。
  • -t将输出限制为仅tcp套接字。
  • -l显示所有考虑-4-t限制的监听套接字。
  • -n确保显示端口号,而不是像‘HTTPHTTPS`这样的协议名称。这一点很重要,因为HAProxy可能试图绑定到非标准端口,而服务名称可能与实际端口号相反,令人困惑。
  • -p输出端口绑定的进程信息。
  • |grep 80将输出限制为包含字符80的行,因此需要检查的行更少

<$>[备注] 注意:在此IPv4和下面的IPv6示例中,如果您的输出中没有一行具有匹配的端口,则Cannot Bind socket错误可能源自EADDRNOTAVAIL错误。请跳到下一节[使用ipUtility](# troubleshooting-with-the-ip-utility)排查故障》,查看您的系统中有哪些可用的IP地址。 <$>

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

1[secondary_label Output]
2LISTEN 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:(()),特别是pid=40部分。

如果出现与IPv6接口相关的Cannot Bind socket错误,请重复ss调用,这次使用-6标志将接口限制为IPv6网络堆栈,如下所示:

1sudo ss -6 -tlnp |grep 80

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

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

同样,如果您的Journal alctl输出不同于此处突出显示的80,请替换有问题的端口号。

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

1sudo ps -p 40

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

1[secondary_label Output]
2PID TTY TIME CMD
340 ?        00:00:00 nginx

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

需要注意的是,如果您正在诊断无法绑定socket错误,则流程可能不同于nginx,并且端口和IP地址可能不总是0.0.0.0[::]。通常,同一服务器上会使用不同的Web服务器和代理。每个端口都可能尝试绑定到不同的IPv4端口和IPv6接口,以处理不同的Web流量。例如,配置了HAProxy的服务器监听端口80上的IPv4环回地址(也称为本地主机),则会显示如下ss输出:

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

重要的是,将指示特定IP地址和端口的systemctl输出或Journal alctl输出与来自ss的诊断数据相结合,然后再使用ps来缩小导致HAProxy无法启动的进程的范围。

有时候,当你用ssps来排除cannot bind socket错误消息时,根本不会有任何输出,这意味着错误可能不是由套接字冲突引起的。本教程的下一节将介绍如何使用ip实用程序解决cannot bind socket错误。

使用ip工具排查问题

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

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

1sudo ip -4 -c address show
  • -4限制ip只显示与IPv4相关的接口信息。
  • -c在输出中加入颜色编码,便于直观解析。
  • 地址显示显示接口的IP地址,其中包含-4-c标志。

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

 1[secondary_label Output]
 21: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
 3    inet 127.0.0.1/8 scope host lo
 4       valid_lft forever preferred_lft forever
 52: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
 6    inet 203.0.113.1/24 brd 203.0.113.255 scope global eth0
 7       valid_lft forever preferred_lft forever
 8    inet 192.0.2.1/24 brd 192.0.2.255 scope global eth0
 9       valid_lft forever preferred_lft forever
103: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
11    inet 198.51.100.1/24 brd 198.51.100.255 scope global eth1
12       valid_lft forever preferred_lft forever

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

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

1sudo ip -6 -c address show

您应该收到如下所示的输出:

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

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

一旦您有了分配给您的系统的地址列表,您就可以尝试查找与Cannot Bind Socket[x.x:80]错误对应的匹配IP地址。如果没有匹配的IP地址,则HAProxy很可能配置为使用您的系统不可用的IP地址,并且操作系统引发EADDRNOTAVAIL错误而导致Cannot Bind Socket错误。

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

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

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

1[label /etc/haproxy/haproxy.cfg]
2. . .
3frontend main
4        bind 198.51.100.123:80

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

1[label /etc/haproxy/haproxy.cfg]
2. . .
3frontend main
4        bind 198.51.100.1:80

使用正确的IP地址编辑/etc/haxy/haproxy.cfg后,使用systemctl命令重新启动:

1sudo systemctl restart haproxy.service

现在检查HAProxy的状态,并确保输出显示‘ACTIVE(RUNNING)’行:

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

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

结论

在本教程中,您了解了如何对IPv4和IPv6接口上的HAProxyCannot Bind socket错误消息进行故障排除。您了解了如何使用systemctl检查HAProxy服务器的状态并尝试查找错误消息。您还了解了如何使用Journal alctl查看systemd日志,以了解有关无法绑定socket错误的具体信息。

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

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

Published At
Categories with 技术
Tagged with
comments powered by Disqus