这里主要记录一些在实际排查网络问题过程中,觉得非常好用的工具或方法。大多数和 k8s 的网络问题相关
1. iptables 处理规则流程图
出处:https://www.zsythink.net/archives/1199
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 怎么解决
这个问题相信大多数人都遇到过,之所以要单独写在这里,是因为遇到过一些小众场景非常难排查。
大多数情况下,这个问题可以通过检查下面几项:
- 检查机器上的路由表,是否有通往目的 IP 的路由。
- 确认网关配置是否正确,网关路由是否正常。
- 抓包检查,这里我们可以选择抓 ARP 包。如:tcpdump -i any arp and host xx.xxx.xx.xx -ne。这种方式看似没什么用,但是非常好用,特别是在网络配置非常复杂(多网卡,多网络平面的 k8s 集群)时。有的时候很难准确判断出出去的数据包命中了什么样的路由。这种情况下,我们可以通过 arp 请求的网关 IP,来判断出路由是哪条,且网关是否正常连通。
5. 路由判断理解是否正确
通过第一点中提供的图,我们可以发现,路由判断只在两个地方发生:
- PREROUTING 之后
- OUTPUT 之前
也就是说,当数据包通过了这两个地方之后,路由就已经确定了。在这之后做任何数据包的修改都不会再影响路由判断。
实际场景:使用 ip rule 可以创建一些策略路由,比如来自于 10.100.0.0/24 的数据包,mark 值为 0x06 时走什么路由策略。当在 POSTROUTING 链上做 SNAT,set mark 的时候,是不会影响路由的。
6. iptables 与 LVS
正常情况下,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 这样的网桥进行转发即可。
根据以上的背景,一般我们可以检查下面几个地方:
- 宿主机的 ip_forward 是否打开:
sysctl -a | grep ip_forward
。需要确认值为 1,这时候宿主机才会将不属于自己的流量进行 FORWARD。 - 宿主机的 bridge-nf-call-iptables 是否打开:
sysctl -a | grep bridge
。需要确认值为 1,这时候 bridge 设备上的流量就会经过 iptables conntrack。 - 检查 DNAT 规则。docker/nerdctl 一般都会在 iptables NAT 表上写这些规则。
iptables -t nat -L PREROUTING
。 - 检查 FILTER 表。实际使用中遇到过在宿主机上同时使用 docker 和 nerdctl 的用户,docker 默认将 FILTER 表 FORWARD 链改为 DROP Policy,也就是不匹配 FORWARD 下规则的流量都会丢弃。而 nerdctl 则是默认 ACCEPT。这样 nerdctl 启动的容器网络就会不通。