《做一个不背锅的运维:简单说说K8S的Service底层》

2023-03-21 21:27:50 浏览数 (1)

Service的底层

Kubernetes Service的底层实现可以使用两种网络模式:iptables和ipvs。

在Kubernetes中,Service是一个抽象的逻辑概念,用于公开应用程序的网络服务。它将一组Pod封装在一个虚拟IP地址后面,可以通过该IP地址和相应的端口号访问这些Pod。而底层实现Service的网络模式,可以通过kube-proxy来进行设置。

Kubernetes早期版本中,kube-proxy默认使用iptables实现Service,即通过iptables规则来实现请求的转发和负载均衡。而在Kubernetes 1.11版本之后,新增了对IPVS的支持。IPVS是一种高性能的、基于内核的负载均衡器,可以提供更高的性能和更丰富的负载均衡算法。

相比之下,iptables在规则较多时可能会影响性能,而IPVS的性能更高,且可以支持多种负载均衡算法,例如RR、LC、WRR等。因此,在高并发、高负载的场景下,使用IPVS作为Service的底层实现是更为合适的选择。

优缺点

Kubernetes Service 底层使用 iptables 和 ipvs 作为负载均衡的实现方式,其实两者都是各有优缺点的,下面好好聊聊:

使用 iptables 作为负载均衡器的优点如下:

  1. 简单易用:iptables 是 Linux 中默认的防火墙软件,使用广泛,熟练掌握 iptables 的管理员可以很容易地配置 Service 的负载均衡。
  2. 稳定性高:iptables 在 Linux 中已经经过多年的使用和优化,稳定性得到了很好的保证,可以满足大部分场景下的负载均衡需求。
  3. 配置灵活:iptables 提供了非常灵活的配置方式,可以根据不同的业务场景和需求进行定制化配置,可以轻松地实现多种转发策略。

但是,使用 iptables 作为负载均衡器也存在一些缺点:

  1. 性能不够优秀:iptables 的性能相对较差,当集群规模增大时,会带来一定的性能压力。
  2. 负载均衡粒度较粗:iptables 的负载均衡粒度较粗,只能对 IP 地址进行负载均衡,无法对请求的 Header 信息等进行识别,对于某些需要更精细的负载均衡场景可能无法满足需求。

使用 ipvs 作为负载均衡器的优点如下:

  1. 性能优秀:ipvs 的性能非常优秀,可以支持高并发和大规模的负载均衡。
  2. 负载均衡粒度细:ipvs 的负载均衡粒度比 iptables 更细,可以对请求的 Header 信息等进行识别,可以满足更精细的负载均衡场景。

但是,使用 ipvs 作为负载均衡器也存在一些缺点:

  1. 配置相对复杂:ipvs 的配置比 iptables 更加复杂,需要较高的技术水平和经验。
  2. 稳定性相对较低:ipvs 的稳定性相对较低,需要管理员经常进行监控和维护。

使用 iptables 和 ipvs 作为 Kubernetes Service 的负载均衡器都有其优点和缺点,具体使用哪种方式需要根据实际场景和需求进行权衡。

kube-proxy

kube-proxy 是一个网络代理,它监视 Kubernetes Service 的变化,然后自动更新本地的网络规则,以实现负载均衡和流量转发功能。

当 Kubernetes 中创建了一个 Service 对象时,kube-proxy 会根据 Service 的定义生成相应的虚拟 IP 地址,并为该 IP 地址配置负载均衡规则,以将流量转发到后端 Pod 上。

除了负载均衡和流量转发的功能之外,kube-proxy 还负责维护 Kubernetes 集群中的网络拓扑结构,并为 Pod 分配 IP 地址。因此,kube-proxy 是 Kubernetes 集群中非常重要的组件之一,它确保了网络流量的顺畅和应用程序的可用性。

Kube-proxy默认使用iptables作为Service的实现方式,下面可以看到kube-proxy的启动Log:

代码语言:txt复制
tantianran@test-b-k8s-master:~$ kubectl logs kube-proxy-6bdwl -n kube-system
...
I0320 00:43:35.602674       1 server_others.go:206] "Using iptables Proxier" # 这条log告诉你 使用的是 iptables 的代理模式
...

修改成ipvs模式

kube-proxy 支持两种负载均衡模式,默认是 iptables 模式,使用的模式可以在 kube-proxy 配置中进行指定,下面修改成IPVS:

  1. 每个节点安装ipvs相关依赖
代码语言:txt复制
sudo apt-get install -y ipset ipvsadm linux-modules-extra-$(uname -r) # Ubuntu
yum install -y ipset ipvsadm kernel-modules-extra # CentOS

# 确认 IPVS 模块已加载,如果输出结果中包含 ip_vs 和 nf_conntrack_ipv4,则表示 IPVS 模块已加载。
lsmod | grep -e ip_vs -e nf_conntrack_ipv4

确保在每个节点上都安装了这些软件包,并且它们的版本相同,这样才能确保集群中的所有节点都具备 IPVS 的支持。

  1. 修改配置文件

如果k8s使用的是kubeadm搭建的。那么kube-proxy它的配置文件是默认交由ConfigMap进行管理的。在Kubernetes中,ConfigMap是一种用于管理应用程序配置的对象,它将配置信息存储为键值对的形式,可以被挂载到容器中,或者通过环境变量的形式注入到容器中。

kube-proxy使用的配置文件是通过一个名为kube-proxy的ConfigMap来管理的,这个ConfigMap的名称和命名空间默认为kube-system。可以使用以下命令查看kube-proxy的ConfigMap:

代码语言:txt复制
kubectl get configmap -n kube-system kube-proxy -o yaml

在编辑器中修改config.conf.mode的值为"ipvs",如果不指定mode,默认的模式就是iptables

代码语言:txt复制
kubectl edit configmap kube-proxy -n kube-system

内容如下:

代码语言:txt复制
mode: "ipvs"

修改后,保存并退出即可,修改后的配置信息会被自动更新到kube-proxy的配置文件中,查看一下:

代码语言:txt复制
kubectl get configmap -n kube-system kube-proxy -o yaml | grep mode
  1. 接着删掉kube-proxy的pod,删完后它会马上自动重建,重建后即能加载配置从而使ipvs生效:
代码语言:txt复制
kubectl get pod -n kube-system | grep kube-proxy | awk '{print $1}' | xargs kubectl delete pod -n kube-system
pod "kube-proxy-dh5rv" deleted
pod "kube-proxy-nt8qz" deleted
pod "kube-proxy-pkspb" deleted
  1. 创建一个NodePort类型的Service:
代码语言:txt复制
tantianran@test-b-k8s-master:/etc/kubernetes$ kubectl create svc nodeport test-goweb --tcp=80:8090 --node-port=30010
service/test-goweb created
tantianran@test-b-k8s-master:/etc/kubernetes$ kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        114d
test-goweb   NodePort    10.104.238.165   <none>        80:30010/TCP   8s
tantianran@test-b-k8s-master:/etc/kubernetes$ 
  1. 查看当前正在运行的虚拟服务和真实服务器的信息:
代码语言:txt复制
tantianran@test-b-k8s-master:/etc/kubernetes$ sudo ipvsadm -Ln | grep 30010
TCP  172.17.0.1:30010 rr
TCP  192.168.11.13:30010 rr
TCP  10.244.82.0:30010 rr
tantianran@test-b-k8s-master:/etc/kubernetes$ sudo ipvsadm -Ln | grep 8090
  -> 10.244.240.3:8090            Masq    1      0          0         
  -> 10.244.240.14:8090           Masq    1      0          0         
  -> 10.244.240.23:8090           Masq    1      0          0         
  -> 10.244.240.34:8090           Masq    1      0          0         
  -> 10.244.240.45:8090           Masq    1      0          0         
  -> 10.244.240.46:8090           Masq    1      0          0         
  -> 10.244.240.3:8090            Masq    1      0          0         
  -> 10.244.240.14:8090           Masq    1      0          0         
  -> 10.244.240.23:8090           Masq    1      0          0         
  -> 10.244.240.34:8090           Masq    1      0          0         
  -> 10.244.240.45:8090           Masq    1      0          0         
  -> 10.244.240.46:8090           Masq    1      0          0         
  -> 10.244.240.3:8090            Masq    1      0          0         
  -> 10.244.240.14:8090           Masq    1      0          0         
  -> 10.244.240.23:8090           Masq    1      0          0         
  -> 10.244.240.34:8090           Masq    1      0          0         
  -> 10.244.240.45:8090           Masq    1      0          0         
  -> 10.244.240.46:8090           Masq    1      0          0         
  -> 10.244.240.3:8090            Masq    1      0          0         
  -> 10.244.240.14:8090           Masq    1      0          0         
  -> 10.244.240.23:8090           Masq    1      0          0         
  -> 10.244.240.34:8090           Masq    1      0          0         
  -> 10.244.240.45:8090           Masq    1      0          0         
  -> 10.244.240.46:8090           Masq    1      0          0         
tantianran@test-b-k8s-master:/etc/kubernetes$ 
  1. 看看能否正常访问:
图片图片
  1. 如果要改回使用iptables的代理模式,只需修改kube-proxy配置中的mode为空字符串,它就会默认使用iptables

内容如下:

代码语言:txt复制
mode: ""

最后的总结

Kubernetes中的Service是一个抽象层,用于将一组Pod公开为单个网络端点。在实际部署中,Kubernetes提供了两种不同的Service类型:ClusterIP和NodePort。这两种Service类型的实现方式不同,涉及到两种不同的网络代理技术:iptables和IPVS。

  1. iptables

iptables是一个基于Linux内核的网络数据包过滤工具,用于控制网络数据包的转发。在Kubernetes中,当创建一个ClusterIP Service时,kube-proxy组件会自动为该Service创建一组iptables规则。这些规则将来自Service IP地址和端口的数据包转发到后端Pod的IP地址和端口。

iptables规则的实现方式比较简单,但是当后端Pod数量较多时,iptables规则数量也会随之增加,这可能会对iptables性能产生一定的影响。此外,当Pod数量发生变化时,iptables规则也需要实时更新,这也可能会导致一定的延迟。

  1. IPVS

IPVS是一个高性能的网络代理工具,用于将来自客户端的请求转发到后端的服务。在Kubernetes中,可以使用IPVS来代替iptables作为Service的后端负载均衡器。

与iptables不同,IPVS是基于内核模块的形式实现的。在Kubernetes中,kube-proxy组件会自动加载IPVS内核模块,并使用IPVS来实现Service的后端负载均衡。IPVS的优势在于它可以高效地处理大规模的负载均衡,因此在大规模集群中使用IPVS可以提高集群的性能和稳定性。

需要注意的是,IPVS的配置相对于iptables来说要复杂一些,需要额外的工具来管理。同时,IPVS需要更多的内存和CPU资源,因此在使用IPVS时需要考虑到集群的资源限制。

好了,本篇的分享就到这里。下一篇的话呢,我会继续在k8s中创建一个deployment和service,并分析service底层的iptables和ipvs的每一条策略是怎样的。辛苦大家保持高度关注,感谢!

本文转载于WX公众号不背锅运维:https://mp.weixin.qq.com/s/gqet-QabvxqnWhdxAOO6Cg

0 人点赞