k8s中Service ClusterIP ping不通?

一. Service的类型

先来看看《kubernetes权威指南》中对Service类型的介绍:

  • ClusterIP:kubernetes默认会自动设置Service的虚拟IP地址,仅可被集群内部的客户端应用访问。
  • NodePort:将Service的端口号映射到每个node的一个端口号上,这样集群中的任意Node都可以作为Service的访问入口地址,即:NodeIP:NodePort。
  • LoadBalance:将Service映射到一个已存在的负载均衡器的IP地址上,通常在公有云环境中使用。
  • ExternalName:将Service映射为一个外部域名地址,通过ExternalName字段进行设置。
在权威指南中介绍到ClusterIP是供集群内部访问的,但有天我发现我环境里的ServiceIP在服务器上是能ping通的,那这难道是书上面写的有问题?
[root@k8s-master test-namespace]# kubectl get svc -n test
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
nginx-app-svc   ClusterIP   10.96.240.115   <none>        8090/TCP   14d
[root@k8s-master test-namespace]# ping 10.96.240.115
PING 10.96.240.115 (10.96.240.115) 56(84) bytes of data.
64 bytes from 10.96.240.115: icmp_seq=1 ttl=64 time=0.045 ms
64 bytes from 10.96.240.115: icmp_seq=2 ttl=64 time=0.035 ms
^C
--- 10.96.240.115 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.035/0.040/0.045/0.005 ms

翻阅大量资料后发现,跟KubeProxy的代理模式有很大关系,接下来我们再看看KubeProxy的介绍

二. KubeProxy介绍

kube-proxy 是集群中每个节点(node)上所运行的网络代理, 实现 Kubernetes 服务(Service) 概念的一部分。kube-proxy 维护节点上的一些网络规则, 这些网络规则会允许从集群内部或外部的网络会话与 Pod 进行网络通信。如果操作系统提供了可用的数据包过滤层,则 kube-proxy 会通过它来实现网络规则。 否则,kube-proxy 仅做流量转发。
kubeproxy提供以下几种代理模式:

  • userspace模式:用户空间模式,有kube-proxy完成代理的实现,效率最低,不在推荐使用。
  • iptables模式:kube-proxy通过设置Linux
    Kernel的iptables规则,实现从Service到后端Endpoint列表的负载分发规则,效率很高。但是,如果某个后端Endpoint在转发时不可用,此次客户端请求就会得到失败的响应。这是KubeProxy的默认模式
  • ipvs模式:kube-proxy通过设置Linux Kernel的netlink接口设置ipvs规则,转发效率和支持的吞吐率最高,IPVS模式要求Linux Kernel启用IPVS模块,如果系统未启用IPVS内核模块,kube-proxy会自动切换至iptables模式。
  • kernelspace:Windows Server上的代理模式。
这里我们可以看出kubeproxy默认是iptables模式,我的环境是ipvs模式,那在具体实现上面有什么区别?

iptables:clusterIP 只是 iptables 中的规则,只会处理 ip:port 四层数据包,reject 了icmp。不能 ping 通。
IPVS:clusterIP 会绑定到虚拟网卡 kube-ipvs0,配置了 route路由到回环网卡,icmp 包是 lo 网卡回复的。可以 ping 通。

由此理解了我环境的clusterIP为什么能ping通了,在测试环境也找到了kube-ipvs0的虚拟网卡和虚拟IP地址

[root@k8s-master test-namespace]# ifconfig kube-ipvs0
kube-ipvs0: flags=130<BROADCAST,NOARP>  mtu 1500
        inet 10.106.125.71  netmask 255.255.255.255  broadcast 0.0.0.0
        ether e2:09:df:13:ae:7e  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
[root@k8s-master test-namespace]# ip add
11: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default
    link/ether e2:09:df:13:ae:7e brd ff:ff:ff:ff:ff:ff
    inet 10.106.125.71/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.110.143.22/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.97.55.252/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.104.10.78/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.99.137.44/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.108.95.38/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.111.108.30/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.108.242.176/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.96.0.10/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.108.233.252/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.111.66.62/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.97.43.250/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.103.174.59/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.96.0.1/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.96.240.115/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.98.130.231/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.104.208.98/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever

另外,kube-ipvs0虚拟网卡上面绑定的IP地址个数和k8s service的个数相等

[root@k8s-master test-namespace]# ip add | grep -c 'inet 10'
18
[root@k8s-master test-namespace]# kubectl get svc -A | grep -v None  |wc -l
18

三.KubeProxy模式修改

我的环境是ipvs模式,刚开始创建集群的时候修改过,修改方式如下

[root@k8s-master test-namespace]# kubectl get cm -n kube-system
NAME                                 DATA   AGE
calico-config                        4      22d
coredns                              1      22d
extension-apiserver-authentication   6      22d
kube-proxy                           2      22d
kube-root-ca.crt                     1      22d
kubeadm-config                       2      22d
kubelet-config-1.20                  1      22d
[root@k8s-master test-namespace]# kubectl edit cm kube-proxy -n kube-system
    ...
    detectLocalMode: ""
    enableProfiling: false
    healthzBindAddress: ""
    hostnameOverride: ""
    iptables:
      masqueradeAll: false
      masqueradeBit: null
      minSyncPeriod: 0s
      syncPeriod: 0s
    ipvs:
      excludeCIDRs: null
      minSyncPeriod: 0s
      scheduler: ""
      strictARP: false
      syncPeriod: 0s
      tcpFinTimeout: 0s
      tcpTimeout: 0s
      udpTimeout: 0s
    kind: KubeProxyConfiguration
    metricsBindAddress: ""
    mode: "ipvs"              ##默认这里是空值,需要修改为ipvs
    ...
    ```
**修改完kubeproxy的配置文件,需要重启kubeproxy的pod,逐一删除即可**

查看系统是否开启ipvs模块

[root@iZ8vb05skym8uiglcfnnslZ ~]# lsmod | grep ip_vs
ip_vs_sh               12688  0
ip_vs_wrr              12697  0
ip_vs_rr               12600  0
ip_vs                 145458  6 ip_vs_rr,ip_vs_sh,ip_vs_wrr
nf_conntrack          139264  10 ip_vs,nf_nat,nf_nat_ipv4,nf_nat_ipv6,xt_conntrack,nf_nat_masquerade_ipv4,nf_nat_masquerade_ipv6,nf_conntrack_netlink,nf_conntrack_ipv4,nf_conntrack_ipv6
libcrc32c              12644  3 ip_vs,nf_nat,nf_conntrack

安装ipvsadm来管理ipvs规则

[root@k8s-master test-namespace]# yum -y install ipvsadm
[root@k8s-master test-namespace]# ipvsadm -L -n --stats | grep -A 2 10.96.240.115
TCP  10.96.240.115:8090                  2        8        4      432      224
  -> 10.244.36.79:80                     1        4        2      216      112
  -> 10.244.36.80:80                     1        4        2      216      112

参考链接:https://segmentfault.com/a/1190000039349716