前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >之前还好好的,为啥现在ping不通了?,你咋不早说?怨我吗

之前还好好的,为啥现在ping不通了?,你咋不早说?怨我吗

作者头像
公众号: 云原生生态圈
发布2024-05-06 17:22:59
1380
发布2024-05-06 17:22:59
举报
文章被收录于专栏:云原生生态圈云原生生态圈

还以为是遇到鬼了,结果发现还是之间太年轻哇。进入正题

背景环境

  • kubernetes 1.26.3
  • CRI Runtime: containerd 1.6.20
  • kube-proxy 代理模式: ipvs
  • network plugin: terway-eniip(aliyun-ack)

问题现象

在进行 poc 测试过程中,随手使用ping了下 svc 的名字,但是发现奇怪的错误

代码语言:javascript
复制
Destination Port Unreachable

明明之前还是好的哇,我记得之前是可以正常通信的哦,很奇怪,之前还是好好的,现在为啥不行了呢?抓狂(`Д´)😫

环境简单了解一下后发现

  • pod->pod ping 正常
代码语言:javascript
复制
root@debug:/# ping -c 1 192.168.110.66
PING 192.168.110.66 (192.168.110.66) 56(84) bytes of data.
64 bytes from 192.168.110.66: icmp_seq=1 ttl=62 time=0.271 ms

--- 192.168.110.66 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.271/0.271/0.271/0.000 ms
  • pod->pod telnet

pod 到 pod 正常,理论这个肯定也是没问题的,顺手试了下

代码语言:javascript
复制
root@debug:/# telnet 192.168.110.66 389
Trying 192.168.110.66...
Connected to 192.168.110.66.
Escape character is '^]'.

都正常,就是 pod->svc 不对,那就是说 pod->pod 的四层网络是正常的,没问题,但是 pod 到 svc 的三层网络出现问题

如果你不太清楚三层四层说的是啥,再去了解在OSI 七层模型。[1]

OSI 三层与四层区别

那这里大概简单说下三层四层之间的区别吧:

  • 三层,即网络层,主要负责数据包的发送和接收,包括 IP 地址处理、路由选择等。在这一层,数据单位被称为“包”(Packet)。网络层的主要协议包括 IP(Internet Protocol)、ICMP(Internet Control Message Protocol)等。
  • 四层,即传输层,主要负责提供端到端的通信服务,包括数据的分段、流量控制、错误检测等。在这一层,数据单位被称为“段”(Segment)或“数据报”(Datagram)。传输层的主要协议包括 TCP(Transmission Control Protocol)、UDP(User Datagram Protocol)等。

以下是四层和三层的主要区别:

  • 数据单位:
    • 三层的数据单位是“包”
    • 四层的数据单位是“段”或“数据报”。
  • 协议:
    • 三层的主要协议是 IP 和 ICMP
    • 四层的主要协议是 TCP 和 UDP。
  • 功能:
    • 三层主要负责数据包的发送和接收,包括 IP 地址处理、路由选择等;
    • 四层主要负责提供端到端的通信服务,包括数据的分段、流量控制、错误检测等。
  • 地址类型:
    • 三层使用 IP 地址
    • 四层使用端口号。
  • 连接类型:
    • TCP(四层协议)提供的是可靠的连接,保证数据的顺序和完整性;
    • 而 IP(三层协议)提供的是不可靠的连接,不保证数据的顺序和完整性。

被什么 🥁 拦截了?

这里就基本清楚了他们的区别了,那猜想估计就是被防火墙 iptables 策略拦截了?

在 k8s pod 中,数据包会首先进入到 iptables 的 PREROUTING 链,然后经过一些列的规则转发到KUBE-SERVICES链上

代码语言:javascript
复制
[root@work-A103 ~]# iptables -t nat -vnL
Chain PREROUTING (policy ACCEPT 832 packets, 57583 bytes)
 pkts bytes target     prot opt in     out     source               destination
 589M   39G KUBE-SERVICES  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
这个规则将所有数据包转发到 KUBE-SERVICES 链。这个规则的目的是处理所有目标地址是 Kubernetes Service 的数据包。
 Chain KUBE-SERVICES (2 references)
 pkts bytes target     prot opt in     out     source               destination
    4   240 RETURN     all  --  *      *       127.0.0.0/8          0.0.0.0/0
所有源地址是 127.0.0.0/8 的数据包会被返回,不会进行任何处理。这是因为这些数据包来自本地主机,不需要被转发。
    2   120 KUBE-LOAD-BALANCER  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* Kubernetes service lb portal */ match-set KUBE-LOAD-BALANCER dst,dst
所有目标地址在 KUBE-LOAD-BALANCER ipset 中的数据包会被转发到 KUBE-LOAD-BALANCER 链。这些数据包的目标是 Kubernetes 的 LoadBalancer Service。
    0     0 KUBE-MARK-MASQ  all  --  *      *      !192.168.0.0/16       0.0.0.0/0            /* Kubernetes service cluster ip + port for masquerade purpose */ match-set KUBE-CLUSTER-IP dst,dst
所有目标地址不在 192.168.0.0/16 网段内,且在 KUBE-CLUSTER-IP ipset 中的数据包会被标记为 MASQUERADE。这是为了对这些数据包进行源地址伪装,以便它们可以被正确地路由回源 Pod。
   48  3662 KUBE-NODE-PORT  all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
所有目标地址是本地地址的数据包会被转发到 KUBE-NODE-PORT 链。这些数据包的目标是 Kubernetes 的 NodePort Service。
   44  3422 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            match-set KUBE-CLUSTER-IP dst,dst
所有目标地址在 KUBE-CLUSTER-IP ipset 中的数据包会被直接接受。这些数据包的目标是 Kubernetes 的 ClusterIP Service。
    2   120 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOAD-BALANCER dst,dst
所有目标地址在 KUBE-LOAD-BALANCER ipset 中的数据包会被直接接受。这些数据包的目标是 Kubernetes 的 LoadBalancer Service。

从上面不同的匹配链上可以看出,到 svc 的流量都匹配到KUBE-CLUSTER-IP这个规则上了,而 ipvs 模式在,所有服务的 clusterIP 都会出现在本机的 kube-ipvs0 网卡上,例如下方

代码语言:javascript
复制
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:16:3e:06:cc:83 brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.252/24 brd 192.168.100.255 scope global dynamic eth0
       valid_lft 304538819sec preferred_lft 304538819sec
    inet6 fe80::216:3eff:fe06:cc83/64 scope link
       valid_lft forever preferred_lft forever
3: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether a2:02:dc:9e:e6:63 brd ff:ff:ff:ff:ff:ff
这里
4: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default
    link/ether ca:40:e8:2f:b5:ac brd ff:ff:ff:ff:ff:ff
    inet 172.16.204.40/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 172.16.0.10/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 172.16.249.238/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 172.16.35.224/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 172.16.28.151/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 172.16.239.249/32 scope global kube-ipvs0

有点门路了,就是 ipvs 搞得鬼

那数据包就必然走到INPUT

代码语言:javascript
复制
[root@work-A103 ~]# iptables -t filter -vnL
Chain INPUT (policy ACCEPT 23 packets, 2224 bytes)
 pkts bytes target     prot opt in     out     source               destination
 926M  265G KUBE-IPVS-FILTER  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes ipvs access filter */
所有数据包都会被转发到 KUBE-IPVS-FILTER 链。这个链的规则用于处理 IPVS 模式下的数据包。这个规则的目的是过滤掉那些目标地址不是 Kubernetes Service 的数据包,以防止它们被错误地发送到 Service 的后端 Pod。
 926M  265G KUBE-PROXY-FIREWALL  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kube-proxy firewall rules */
所有数据包都会被转发到 KUBE-PROXY-FIREWALL 链。这个链的规则用于处理 kube-proxy 的防火墙规则。这个规则的目的是防止非法的网络流量进入或离开 Pod。
 926M  265G KUBE-NODE-PORT  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes health check rules */
所有数据包都会被转发到 KUBE-NODE-PORT 链。这个链的规则用于处理 Kubernetes 的 NodePort Service 的健康检查规则。这个规则的目的是确保只有健康的 Pod 可以接收到流量。
 926M  266G KUBE-FIREWALL  all  --  *      *       0.0.0.0/0            0.0.0.0/0
所有数据包都会被转发到 KUBE-FIREWALL 链。这个链的规则用于处理 Kubernetes 的防火墙规则。这个规则的目的是防止非法的网络流量进入或离开节点。

此处,就可以专门关注一下KUBE-IPVS-FILTER即可

代码语言:javascript
复制
[root@work-A103 ~]# iptables -t filter -vnL KUBE-IPVS-FILTER
Chain KUBE-IPVS-FILTER (1 references)
 pkts bytes target     prot opt in     out     source               destination
    9  1377 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOAD-BALANCER dst,dst
所有目标地址在 KUBE-LOAD-BALANCER ipset 中的数据包会被返回,不会进行任何处理。这些数据包的目标是 Kubernetes 的 LoadBalancer Service。
   18  3740 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            match-set KUBE-CLUSTER-IP dst,dst
所有目标地址在 KUBE-CLUSTER-IP ipset 中的数据包会被返回,不会进行任何处理。这些数据包的目标是 Kubernetes 的 ClusterIP Service。
    0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            match-set KUBE-EXTERNAL-IP dst,dst
所有目标地址在 KUBE-EXTERNAL-IP ipset 中的数据包会被返回,不会进行任何处理。这些数据包的目标是 Kubernetes Service 的外部 IP。
    0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate NEW match-set KUBE-IPVS-IPS dst reject-with icmp-port-unreachable
所有新建连接的数据包,如果它们的目标地址在 KUBE-IPVS-IPS ipset 中,会被拒绝,并发送 ICMP Port Unreachable 消息。这个规则的目的是防止非 Kubernetes Service 的数据包被错误地发送到 Service 的后端 Pod。

到这里基本上距离真相也就不远了,那就是最后一个 ipset,当匹配到我们的 svc 的 ip 在这个 ipset 中的时候,我们的 icmp 就会被拒绝,然后反手送给我们一个Destination Port Unreachable

查看我们的目标 svc 的 IP 是否在KUBE-IPVS-IPS中,可以直接通过

代码语言:javascript
复制
ipset list KUBE-IPVS-IPS |grep $IP

即可获取到。

所有在我们这个版本的 k8s 环境中,filter表下的KUBE-IPVS-FILTER链以及KUBE-IPVS-IPS这个 ipset 导致 pod->svc 的 icmp 三层通信都会中断。

也有人说 svc 本身无实体 它是个虚拟 IP ping 它无意义的,你说你咋不早说呢?

结论

在 k8s 版本 1.24 之前的可以 ping 通,之后的版本的就不可以了 😭

相关 issue

  • issue #119613[2]

加群冲人气

公众号菜单栏联系作者,或者公众号发送"加群",聊啥技术,就是混个脸熟

参考资料

[1]

OSI七层模型: https://mp.weixin.qq.com/s/ag-wVS-6PZjmNudf052GYA

[2]

kubernetes issue 119613: https://github.com/kubernetes/kubernetes/issues/119613

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-04-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云原生生态圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景环境
  • 问题现象
  • OSI 三层与四层区别
  • 被什么 🥁 拦截了?
  • 有点门路了,就是 ipvs 搞得鬼
  • 结论
  • 相关 issue
  • 加群冲人气
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档