简介
当另一个进程侦听HAProxy配置为使用的同一接口和TCP端口组合时,或者当HAProxy尝试使用未分配给网络接口的IP地址时,会生成HAProxyCannot Bind Socket
错误消息。这两种错误情况都源于底层操作系统的网络堆栈。
在第一种情况下,当另一个进程已经在使用HAProxy试图绑定到的接口和端口时,Linux上的潜在错误是EADDRINUSE
。问题是,在任何给定时间,只能将单个进程绑定到IP地址和端口组合。
在第二种情况下,当HAProxy试图使用未分配给系统接口的IP地址时,Linux上的基本错误是EADDRNOTAVAIL
。这里的问题是,无法使用操作系统不可用的地址创建IP套接字。
然而,这两个底层错误都会生成相同的HAProxy错误消息,因此要排除无法绑定套接字
错误,需要检查Linx系统上当前使用的套接字和IP地址的列表。
要检测到Cannot Bind socket
错误消息,您需要检查systemctl
和Journal 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)
步骤,转到本教程结尾处的[使用ss
和ps
Jouralctl进行故障排除]部分。另一条突出显示的行表示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
表示端口。
即使您自己的系统可能具有不同的冲突接口和端口,错误也将类似于此处显示的输出。在本教程的下一节中,您将能够使用ss
、ps
和ip
命令来诊断问题。
使用ss
和ps
工具排查问题
要排除`无法绑定套接字‘错误,您需要确定其他进程正在侦听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
确保显示端口号,而不是像‘HTTP或
HTTPS`这样的协议名称。这一点很重要,因为HAProxy可能试图绑定到非标准端口,而服务名称可能与实际端口号相反,令人困惑。-p
输出端口绑定的进程信息。|grep 80
将输出限制为包含字符80
的行,因此需要检查的行更少
<$>[备注]
注意:在此IPv4和下面的IPv6示例中,如果您的输出中没有一行具有匹配的端口,则Cannot Bind socket
错误可能源自EADDRNOTAVAIL
错误。请跳到下一节[使用ip
Utility](# 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无法启动的进程的范围。
有时候,当你用ss
和ps
来排除cannot bind socket
错误消息时,根本不会有任何输出,这意味着错误可能不是由套接字冲突引起的。本教程的下一节将介绍如何使用ip
实用程序解决cannot bind socket
错误。
使用ip
工具排查问题
上一节解释了EADDRINUSE
操作系统错误如何导致Cannot Bind socket
错误消息。但是,如果您检查了ss
和ps
输出,并且您的系统上没有套接字冲突,则该问题可能是由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
实用程序检查系统上可用的网络接口。