无IP地址的网卡如何接收报文并通过IPVS转发至本地路由表?
这个问题我之前在帮团队部署裸金属K8s的OpenELB负载均衡时刚好踩过坑,核心原因其实是Linux内核的报文接收规则和IPVS的工作逻辑在共同起作用,咱们一步步理清楚怎么解决:
为什么无IP的网卡收不到报文?
Linux内核默认有个“本机IP匹配检查”:当网卡收到IP报文时,会先验证这个报文的目的IP是不是本机任何一个接口的IP(包括VIP、别名IP),如果都不匹配,哪怕你已经通过ARP公告把VIP和网卡MAC绑定了,内核也会直接把报文丢弃——根本到不了IPVS那一步。你之前设个随机IP能正常工作,就是因为这个随机IP让内核把该网卡纳入了“本机合法接口”的范围,顺带允许了这个接口上的VIP报文通过检查。
解决步骤(无需给网卡分配业务网段IP)
1. 把VIP标记为“本机本地路由”
首先要让内核明确知道:192.168.41.71这个VIP是属于本机的,不管哪个网卡收到它的报文都要接收。执行这条命令:
ip route add local 192.168.41.71 dev lo scope host
这条命令会把VIP绑定到lo回环接口的本地路由表,内核会直接把所有目的IP为这个VIP的报文拉到本地处理,不需要依赖承载网卡的IP。
2. 调整ARP相关的内核参数(适配OpenELB的MAC公告)
因为你用OpenELB公告了VIP和目标网卡MAC的绑定,要避免内核乱响应ARP请求或者发错ARP包,调整以下两个参数(把<你的网卡名>换成实际的网卡,比如eth0):
# 只响应目的IP是本机路由中存在的IP的ARP请求(包括我们刚加的VIP) sysctl -w net.ipv4.conf.<你的网卡名>.arp_ignore=2 # 发送ARP请求时,优先用本机匹配的IP作为源IP,避免无IP网卡发ARP时出错 sysctl -w net.ipv4.conf.<你的网卡名>.arp_announce=2
如果要让这些参数重启后生效,把它们写到/etc/sysctl.conf里就行。
3. 确保IPVS规则正确指向后端Pod
你的IPVS规则应该已经配置了VIP的转发策略,这里再确认下格式(以TCP端口80为例):
# 添加VIP的IPVS虚拟服务 ipvsadm -A -t 192.168.41.71:80 -s rr # 把流量转发到后端Pod(替换成你的实际PodIP和端口) ipvsadm -a -t 192.168.41.71:80 -r 10.244.1.5:80 -m
这里-m是用NAT模式转发,适合大多数K8s场景;如果是直接路由模式,换成-g就行。
4. 关闭反向路径过滤(按需)
有些环境下,Linux的反向路径过滤会因为“报文的源IP和接收网卡的路由不匹配”丢弃报文,所以可以临时关闭测试:
sysctl -w net.ipv4.conf.<你的网卡名>.rp_filter=0 sysctl -w net.ipv4.conf.all.rp_filter=0
如果测试后没问题,同样可以写到sysctl.conf里持久化。
验证方法
配置完后,可以在外部机器ping 192.168.41.71,同时在K8s节点上用tcpdump -i <你的网卡名> host 192.168.41.71抓包,看看能不能收到报文;再用ipvsadm -Ln查看IPVS的连接统计,确认流量是否已经转发到后端Pod。
备注:内容来源于stack exchange,提问作者EvenZhang

