linux 网络问题排查手册

这里主要记录一些在实际排查网络问题过程中,觉得非常好用的工具或方法。大多数和 k8s 的网络问题相关

1. iptables 处理规则流程图

出处:https://www.zsythink.net/archives/1199

https://www.myway5.com/wp-content/uploads/2022/12/screenshot-20221210-113850.png

2. 使用 xtables-monitor 追踪数据包在 iptables 规则中的流向

这种场景常用在宿主机上有比较复杂的 iptables 规则,导致在排查问题时比较难发现。比如 k8s 中 pod 访问 svc ip 不通时。

首先在数据包必经的地方添加 TRACE,比如 raw 表的 PREROUTING 就是个好地方。

iptables -t raw -A PREROUTING -p tcp --dport 5432 -j TRACE

添加 TRACE 之后,就可以追踪该数据包后续的流向了。通过 trace 的信息,可以看到数据库的流入流出网卡,mark 值,匹配的 iptables 规则等等。非常容易帮我们判断出问题

xtables-monitor --trace

3. 使用 conntrack 查看连接的生命周期

conntrack 是 linux 网络协议栈提供的能力,顾名思义,conntrack 提供的是连接追踪的能力。这里的连接并不是 tcp 的连接,而且传输层的 5 元组(源IP,源端口,目的IP,目的端口,协议)来唯一确定的连接。像 NAT 之类的功能,都是基于 conntrack 之上的。

# 比如这条命令就可以看 10.233.101.170 这个 pod 访问 svc ip 建立的连接请。
conntrack -p tcp -s 10.233.101.170 -L -o ktimestamp

4. no route to host 怎么解决

这个问题相信大多数人都遇到过,之所以要单独写在这里,是因为遇到过一些小众场景非常难排查。

大多数情况下,这个问题可以通过检查下面几项:

  1. 检查机器上的路由表,是否有通往目的 IP 的路由。
  2. 确认网关配置是否正确,网关路由是否正常。
  3. 抓包检查,这里我们可以选择抓 ARP 包。如:tcpdump -i any arp and host xx.xxx.xx.xx -ne。这种方式看似没什么用,但是非常好用,特别是在网络配置非常复杂(多网卡,多网络平面的 k8s 集群)时。有的时候很难准确判断出出去的数据包命中了什么样的路由。这种情况下,我们可以通过 arp 请求的网关 IP,来判断出路由是哪条,且网关是否正常连通。

5. 路由判断理解是否正确

通过第一点中提供的图,我们可以发现,路由判断只在两个地方发生:

  1. PREROUTING 之后
  2. OUTPUT 之前

也就是说,当数据包通过了这两个地方之后,路由就已经确定了。在这之后做任何数据包的修改都不会再影响路由判断。

实际场景:使用 ip rule 可以创建一些策略路由,比如来自于 10.100.0.0/24 的数据包,mark 值为 0x06 时走什么路由策略。当在 POSTROUTING 链上做 SNAT,set mark 的时候,是不会影响路由的。

6. iptables 与 LVS

https://www.myway5.com/wp-content/uploads/2022/12/nf-lvs.png

正常情况下,LVS nat 模式的流量不能做 SNAT,因为不会经过 POSTROUTING 链。需要增加下的配置来让 LVS 数据包经过 POSTROUTING

net.ipv4.vs.conntrack=1

iptables 在 PREROUTING 阶段做的 mark,在 LVS NAT 后仍然有效。

7. 容器网络不通解决思路

这里的容器网络仅指 docker/nerdctl 部署的容器网络,k8s 情况会更复杂,也要结合 CNI 去看,这里不讨论。

实际使用中,常见的使用方式是部署容器时使用端口(以 443 为例)映射,将宿主机的 port 映射到容器的 port。一般的底层实现都是使用 iptables DNAT,将发到 443 端口的流量 DNAT 到容器的 ip:port。这样再根据本机的路由,将流量通过 docker0/nerdctl1 这样的网桥进行转发即可。

根据以上的背景,一般我们可以检查下面几个地方:

  1. 宿主机的 ip_forward 是否打开:sysctl -a | grep ip_forward。需要确认值为 1,这时候宿主机才会将不属于自己的流量进行 FORWARD。
  2. 宿主机的 bridge-nf-call-iptables 是否打开:sysctl -a | grep bridge。需要确认值为 1,这时候 bridge 设备上的流量就会经过 iptables conntrack。
  3. 检查 DNAT 规则。docker/nerdctl 一般都会在 iptables NAT 表上写这些规则。iptables -t nat -L PREROUTING
  4. 检查 FILTER 表。实际使用中遇到过在宿主机上同时使用 docker 和 nerdctl 的用户,docker 默认将 FILTER 表 FORWARD 链改为 DROP Policy,也就是不匹配 FORWARD 下规则的流量都会丢弃。而 nerdctl 则是默认 ACCEPT。这样 nerdctl 启动的容器网络就会不通。