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 作为负载均衡器的优点如下:
- 简单易用:iptables 是 Linux 中默认的防火墙软件,使用广泛,熟练掌握 iptables 的管理员可以很容易地配置 Service 的负载均衡。
- 稳定性高:iptables 在 Linux 中已经经过多年的使用和优化,稳定性得到了很好的保证,可以满足大部分场景下的负载均衡需求。
- 配置灵活:iptables 提供了非常灵活的配置方式,可以根据不同的业务场景和需求进行定制化配置,可以轻松地实现多种转发策略。
但是,使用 iptables 作为负载均衡器也存在一些缺点:
- 性能不够优秀:iptables 的性能相对较差,当集群规模增大时,会带来一定的性能压力。
- 负载均衡粒度较粗:iptables 的负载均衡粒度较粗,只能对 IP 地址进行负载均衡,无法对请求的 Header 信息等进行识别,对于某些需要更精细的负载均衡场景可能无法满足需求。
使用 ipvs 作为负载均衡器的优点如下:
- 性能优秀:ipvs 的性能非常优秀,可以支持高并发和大规模的负载均衡。
- 负载均衡粒度细:ipvs 的负载均衡粒度比 iptables 更细,可以对请求的 Header 信息等进行识别,可以满足更精细的负载均衡场景。
但是,使用 ipvs 作为负载均衡器也存在一些缺点:
- 配置相对复杂:ipvs 的配置比 iptables 更加复杂,需要较高的技术水平和经验。
- 稳定性相对较低: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:
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:
- 每个节点安装ipvs相关依赖
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 的支持。
- 修改配置文件
如果k8s使用的是kubeadm搭建的。那么kube-proxy它的配置文件是默认交由ConfigMap进行管理的。在Kubernetes中,ConfigMap是一种用于管理应用程序配置的对象,它将配置信息存储为键值对的形式,可以被挂载到容器中,或者通过环境变量的形式注入到容器中。
kube-proxy使用的配置文件是通过一个名为kube-proxy的ConfigMap来管理的,这个ConfigMap的名称和命名空间默认为kube-system。可以使用以下命令查看kube-proxy的ConfigMap:
kubectl get configmap -n kube-system kube-proxy -o yaml
在编辑器中修改config.conf.mode的值为"ipvs",如果不指定mode,默认的模式就是iptables
kubectl edit configmap kube-proxy -n kube-system
内容如下:
mode: "ipvs"
修改后,保存并退出即可,修改后的配置信息会被自动更新到kube-proxy的配置文件中,查看一下:
kubectl get configmap -n kube-system kube-proxy -o yaml | grep mode
- 接着删掉kube-proxy的pod,删完后它会马上自动重建,重建后即能加载配置从而使ipvs生效:
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
- 创建一个NodePort类型的Service:
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$
- 查看当前正在运行的虚拟服务和真实服务器的信息:
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$
- 看看能否正常访问:
- 如果要改回使用iptables的代理模式,只需修改kube-proxy配置中的mode为空字符串,它就会默认使用iptables
内容如下:
mode: ""
最后的总结
Kubernetes中的Service是一个抽象层,用于将一组Pod公开为单个网络端点。在实际部署中,Kubernetes提供了两种不同的Service类型:ClusterIP和NodePort。这两种Service类型的实现方式不同,涉及到两种不同的网络代理技术:iptables和IPVS。
- iptables
iptables是一个基于Linux内核的网络数据包过滤工具,用于控制网络数据包的转发。在Kubernetes中,当创建一个ClusterIP Service时,kube-proxy组件会自动为该Service创建一组iptables规则。这些规则将来自Service IP地址和端口的数据包转发到后端Pod的IP地址和端口。
iptables规则的实现方式比较简单,但是当后端Pod数量较多时,iptables规则数量也会随之增加,这可能会对iptables性能产生一定的影响。此外,当Pod数量发生变化时,iptables规则也需要实时更新,这也可能会导致一定的延迟。
- 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的每一条策略是怎样的。辛苦大家保持高度关注,感谢!