k8s 中的 service 如何找到绑定的 Pod 以及如何实现 Pod 负载均衡
k8s 中的 service 如何找到绑定的 Pod 以及如何实现 Pod 负载均衡
前言
Service 资源主要用于为 Pod 对象提供一个固定、统一的访问接口及负载均衡的能力。
service 是一组具有相同 label pod 集合的抽象,集群内外的各个服务可以通过 service 进行互相通信。
当创建一个 service 对象时也会对应创建一个 endpoint 对象,endpoint 是用来做容器发现的,service 只是将多个 pod 进行关联,实际的路由转发都是由 kubernetes 中的 kube-proxy 组件来实现,因此,service 必须结合 kube-proxy 使用,kube-proxy 组件可以运行在 kubernetes 集群中的每一个节点上也可以只运行在单独的几个节点上,其会根据 service 和 endpoints 的变动来改变节点上 iptables 或者 ipvs 中保存的路由规则。
endpoint
endpoint 是 k8s 集群中的一个资源对象,存储在 etcd 中,用来记录一个 service 对应的所有 pod 的访问地址。
service 通过 selector 和 pod 建立关联。k8s 会根据 service 关联到 pod 的 podIP 信息组合成一个 endpoint。
如果 service 没有 selector 字段,当一个 service 被创建的时候,endpoint controller 不会自动创建 endpoint。
$ kubectl get svc -n study-k8s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
go-web-svc ClusterIP 10.233.55.112 <none> 8000/TCP 9d
$ kubectl get endpoints -n study-k8s
NAME ENDPOINTS AGE
go-web-svc 10.233.111.171:8000,10.233.111.172:8000,10.233.72.153:8000 + 2 more... 9d
栗如
上面的 service go-web-svc,就有一个对应的 endpoint,ENDPOINTS 里面展示的就是 service 关联的 pod 的 ip 地址和端口。
其中 endpoint controller 负载维护 endpoint 对象,主要的功能有下面几种
1、负责生成和维护所有endpoint对象的控制器;
2、负责监听 service 和对应 pod 的变化;
3、监听到 service 被删除,则删除和该 service 同名的 endpoint 对象;
4、监听到新的 service 被创建,则根据新建 service 信息获取相关 pod 列表,然后创建对应 endpoint 对象;
5、监听到 service 被更新,则根据更新后的 service 信息获取相关 pod 列表,然后更新对应 endpoint 对象;
6、监听到 pod 事件,则更新对应的 service 的 endpoint 对象,将 podIp 记录到 endpoint中;
kube-proxy
kube-proxy 是 Kubernetes 的核心组件,部署在每个 Node 节点上,它是实现 Kubernetes Service 的通信与负载均衡机制的重要组件; kube-proxy 负责为 Pod 创建代理服务,从 apiserver 获取所有 server 信息,并根据 server 信息创建代理服务,实现server到Pod的请求路由和转发,从而实现K8s层级的虚拟转发网络。
在 k8s 中提供相同服务的一组 pod 可以抽象成一个 service,通过 service 提供统一的服务对外提供服务,kube-proxy 存在于各个 node 节点上,负责为 service 提供 cluster 内部的服务发现和负载均衡,负责 Pod 的网络代理,它会定时从 etcd 中获取 service 信息来做相应的策略,维护网络规则和四层负载均衡工作。k8s 中集群内部的负载均衡就是由 kube-proxy 实现的,它是 k8s 中内部的负载均衡器,也是一个分布式代理服务器,可以在每个节点中部署一个,部署的节点越多,提供负载均衡能力的 Kube-proxy 就越多,高可用节点就越多。
简单点讲就是 k8s 内部的 pod 要访问 service ,kube-proxy 会将请求转发到 service 所代表的一个具体 pod,也就是 service 关联的 Pod。
同理对于外部访问 service 的请求,不论是 Cluster IP+TargetPort 的方式;还是用 Node 节点 IP+NodePort 的方式,都被 Node 节点的 Iptables 规则重定向到 Kube-proxy 监听 Service 服务代理端口。kube-proxy 接收到 Service 的访问请求后,根据负载策略,转发到后端的 Pod。
kube-proxy 的路由转发规则是通过其后端的代理模块实现的,其中 kube-proxy 的代理模块目前有四种实现方案,userspace、iptables、ipvs、kernelspace 。
userspace 模式
userspace 模式在 k8s v1.2 后就已经被淘汰了,userspace 的作用就是在 proxy 的用户空间监听一个端口,所有的 svc 都转到这个端口,然后 proxy 内部应用层对其进行转发。proxy 会为每一个 svc 随机监听一个端口,并增加一个 iptables 规则。
从客户端到 ClusterIP:Port 的报文都会通过 iptables 规则被重定向到 Proxy Port,Kube-Proxy 收到报文后,然后分发给对应的 Pod。

userspace 模式下,流量的转发主要是在用户空间下完成的,上面提到了客户端的请求需要借助于 iptables 规则找到对应的 Proxy Port,因为 iptables 是在内核空间,这里就会请求就会有一次从用户态到内核态再返回到用户态的传递过程, 一定程度降低了服务性能。所以就会认为这种方式会有一定的性能损耗。
默认情况下,用户空间模式下的 kube-proxy 通过轮转算法选择后端。
iptables
首先来简单了解下 iptables:
iptables 是 Linux 中最常用的一种防火墙工具,除了防火墙它还可以用作 IP 转发和简单的负载均衡功能。基于 Linux 中的 netfilter 内核模块实现。 Netfilter 在协议中添加了一些钩子,它允许内核模块通过这些钩子注册回调函数,这样经过钩子的所有数据都会被注册在响应钩子上的函数处理,包括修改数据包内容、给数据包打标记或者丢掉数据包等。iptables 是运行在用户态的一个程序,通过 netlink 和内核的 netfilter 框架打交道,具有足够的灵活性来处理各种常见的数据包操作和过滤需求。它允许将灵活的规则序列附加到内核的数据包处理管道中的各种钩子上。
Netfilter 是 Linux 2.4.x 引入的一个子系统,它作为一个通用的、抽象的框架,提供一整套的 hook 函数的管理机制,使得诸如数据包过滤、网络地址转换(NAT)和基于协议类型的连接跟踪成为了可能。
在 kubernetes v1.2 之后 iptables 成为默认代理模式,这种模式下,kube-proxy 会监视 Kubernetes master 对 Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会安装 iptables 规则,从而捕获到达该 Service 的 clusterIP(虚拟 IP)和端口的请求,进而将请求重定向到 Service 的一组 backend 中的某个上面。因为流量转发都是在内核进行的,所以性能更高更加可靠。

可以看到该模式下 iptables 来做用户态的入口,kube-proxy 只是持续监听 Service 以及 Endpoints 对象的变化, iptables 通过设置的转发策略,直接将对 VIP 的请求转发给后端 Pod,iptables 使用 DNAT 来完成转发,其采用了随机数实现负载均衡。
如果 kube-proxy 在 iptables 模式下运行,并且所选的第一个 Pod 没有响应,则连接失败。 这与用户空间模式不同:在这种情况下,kube-proxy 将检测到与第一个 Pod 的连接已失败, 并会自动使用其他后端 Pod 重试。
该模式相比 userspace 模式,克服了请求在用户态-内核态反复传递的问题,性能上有所提升,但使用 iptables NAT 来完成转发,存在不可忽视的性能损耗,iptables 模式最主要的问题是在 service 数量大的时候会产生太多的 iptables 规则,使用非增量式更新会引入一定的时延,大规模情况下有明显的性能问题。
ipvs
当集群的规模比较大时,iptables 规则刷新就会很慢,难以支撑大规模的集群。因为 iptables 的底层实现是链表,对路由规则的增删查改都需要遍历一次链表。
在 kubernetes v1.2 之后 ipvs 成为kube-proxy的默认代理模式。ipvs 正是解决这一问题的,ipvs 是 LVS 的负载均衡模块,与 iptables 比较像的是,ipvs 的实现虽然也基于 netfilter 的钩子函数,但是它却使用哈希表作为底层的数据结构并且工作在内核态,也就是说 ipvs 在重定向流量和同步代理规则有着更好的性能,几乎允许无限的规模扩张。

ipvs 支持三种负载均衡模式:
1、DR模式(Direct Routing);
2、NAT 模式(Network Address Translation);
3、Tunneling(也称 ipip 模式)。
三种模式中只有 NAT 支持端口映射,所以 ipvs 使用 NAT 模式。linux 内核原生的 ipvs 只支持 DNAT,当在数据包过滤,SNAT 和支持 NodePort 类型的服务这几个场景中ipvs 还是会使用 iptables。
ipvs 也支持更多的负载均衡算法:
rr:round-robin/轮询;
lc:least connection/最少连接;
dh:destination hashing/目标哈希;
sh:source hashing/源哈希;
sed:shortest expected delay/预计延迟时间最短;
nq:never queue/从不排队
kernelspace
kernelspace 模式是 windows 上的代理模式,这里不展开讨论了
服务发现
service 的 endpoints 解决了容器发现问题,但是不提前知道 service 的 Cluster IP,就无法知道 service 服务了。Kubernetes 支持两种基本的服务发现模式 —— 环境变量和 DNS。
环境变量
当一个 pod 创建完成之后,kubelet 会在该 pod 中注册该集群已经创建的所有 service 相关的环境变量,但是需要注意的是,在 service 创建之前的所有 pod 是不会注册该环境变量的,所以在平时使用时,建议通过 DNS 的方式进行 service 之间的服务发现。
举个例子,一个名称为 redis-primary 的 Service 暴露了 TCP 端口 6379, 同时给它分配了 Cluster IP 地址 10.0.0.11,这个 Service 生成了如下环境变量:
REDIS_PRIMARY_SERVICE_HOST=10.0.0.11
REDIS_PRIMARY_SERVICE_PORT=6379
REDIS_PRIMARY_PORT=tcp://10.0.0.11:6379
REDIS_PRIMARY_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_PRIMARY_PORT_6379_TCP_PROTO=tcp
REDIS_PRIMARY_PORT_6379_TCP_PORT=6379
REDIS_PRIMARY_PORT_6379_TCP_ADDR=10.0.0.11
DNS
可以在集群中部署 CoreDNS 服务(旧版本的 kubernetes 群使用的是 kubeDNS), 来达到集群内部的 pod 通过DNS 的方式进行集群内部各个服务之间的通讯。
当前 kubernetes 集群默认使用 CoreDNS 作为默认的 DNS 服务,主要原因是 CoreDNS 是基于 Plugin 的方式进行扩展的,简单,灵活,并且不完全被Kubernetes所捆绑。
同时 k8s 中也建议使用 DNS 来做服务发现。
Kubernetes DNS 服务器是唯一的一种能够访问 ExternalName 类型的 Service 的方式。
总结
k8s 中一般使用 Service 为 Pod 对象提供一个固定、统一的访问接口及负载均衡的能力;
k8s 中的负载均衡主要借助于 endpoint 和 kube-proxy 来实现;
endpoint 是 k8s 集群中的一个资源对象,存储在 etcd 中,用来记录一个 service 对应的所有 pod 的访问地址,当一个 service 关联的 pod 被删除,更新,新增,对应的 endpoint 资源都会更新;
kube-proxy 是 Kubernetes 的核心组件,部署在每个 Node 节点上,它是实现 Kubernetes Service 的通信与负载均衡机制的重要组件; kube-proxy 负责为 Pod 创建代理服务,从 apiserver 获取所有 server 信息,并根据 server 信息创建代理服务,实现server到Pod的请求路由和转发,从而实现K8s层级的虚拟转发网络;
kube-proxy 的路由转发规则是通过其后端的代理模块实现的,其中 kube-proxy 的代理模块目前有四种实现方案,userspace、iptables、ipvs、kernelspace ;
service 的 endpoints 和 kube-proxy 解决了容器的发现和负载均衡的问题,但是 service 服务如何被内部的服务找到呢,Kubernetes 支持两种基本的服务发现模式 —— 环境变量和 DNS;
其中 k8s 中推荐使用 DNS 来做 service 的服务发现,当前 kubernetes 集群默认使用 CoreDNS 作为默认的 DNS 服务,主要原因是 CoreDNS 是基于 Plugin 的方式进行扩展的,简单,灵活,并且不完全被Kubernetes所捆绑。
参考
【kubernetes service 原理解析】https://zhuanlan.zhihu.com/p/111244353
【service selector】https://blog.csdn.net/luanpeng825485697/article/details/84296765
【一文看懂 Kube-proxy】https://zhuanlan.zhihu.com/p/337806843
【Kubernetes 【网络组件】kube-proxy使用详解】https://blog.csdn.net/xixihahalelehehe/article/details/115370095
【Service】https://jimmysong.io/kubernetes-handbook/concepts/service.html
【Service】https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/
【k8s 中的 service 如何找到绑定的 Pod 以及如何实现 Pod 负载均衡】https://boilingfrog.github.io/2022/10/16/k8s中的service如何找到绑定的Pod以及如何实现Pod负载均衡/
k8s 中的 service 如何找到绑定的 Pod 以及如何实现 Pod 负载均衡的更多相关文章
- 【Kubernetes】在K8s中创建StatefulSet
在K8s中创建StatefulSet 遇到的问题: 使用Deployment创建的Pod是无状态的,当挂在Volume之后,如果该Pod挂了,Replication Controller会再run一个 ...
- 在K8s中创建StatefulSet
在K8s中创建StatefulSet 遇到的问题: 使用Deployment创建的Pod是无状态的,当挂在Volume之后,如果该Pod挂了,Replication Controller会再run一个 ...
- k8s 中的 ingress 使用细节
k8s中的ingress 什么是ingress Ingress 如何使用 ingress 使用细节 参考 k8s中的ingress 什么是ingress k8s 中使用 Service 为相同业务的 ...
- Spring Cloud Ribbon 中的 7 种负载均衡策略
负载均衡通器常有两种实现手段,一种是服务端负载均衡器,另一种是客户端负载均衡器,而我们今天的主角 Ribbon 就属于后者--客户端负载均衡器. 服务端负载均衡器的问题是,它提供了更强的流量控制权,但 ...
- K8S中Service
Service 的概念Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务. 这一组 Pod 能够被 Serv ...
- k8s中几个基本概念的理解,pod,service,deployment,ingress的使用场景
k8s 总体概览 前言 Pod 副本控制器(Replication Controller,RC) 副本集(Replica Set,RS) 部署(Deployment) 服务(Service) ingr ...
- k8s中ingress,service,depoyment,pod如何关联
k8s中pod通过label标签名称来识别关联,它们的label name一定是一样的.ingress,service,depoyment通过selector 中app:name来关联 1.查询发布 ...
- [转帖]k8s 中的服务如何沟通
k8s 中的服务如何沟通 https://www.jianshu.com/p/9fae09876eb7 本文将介绍 k8s 中的服务如何相互访问,例如后端服务访问数据库,不同类型的服务间的相互访问.并 ...
- 深入理解k8s中的访问控制(认证、鉴权、审计)流程
Kubernetes自身并没有用户管理能力,无法像操作Pod一样,通过API的方式创建/删除一个用户实例,也无法在etcd中找到用户对应的存储对象. 在Kubernetes的访问控制流程中,用户模型是 ...
随机推荐
- AI目标分割能力,无需绿幕即可实现快速视频抠图
绿幕抠图是影视制作过程中常见的技术手段,常用于视频中抠除并替换背景,通过后期加工实现视频剪辑制作的更多可能性.然而,绿幕抠图技术制作成本费时费力,无法应用于日常生活. 华为视频编辑服务近期上线目标分割 ...
- Mqtt开发笔记:windows下C++ ActiveMQ客户端介绍、编译和使用
前话 项目需求,需要使用到mqtt协议,之前编译QtMqtt库,不支持队列模式queue(点对点),只支持订阅/发布者模式.,所以使用C++ ActiveMQ实现. MQTT协议 简介 M ...
- Nginx 平滑升级、Nginx的一些基础配置
# Nginx 平滑升级 # 方案一:使用Nginx服务信号进行升级 # 1.将就版本的sbin目录下可执行nginx进行备份(mv nginx nginxold) # 2.将新版本 configur ...
- 【Harmony OS】【ArkUI】ets开发 简易视频播放器
前言:这一次我们来使用ets的Swiper组件.List组件和Video组件制作一个简易的视频播放器.本篇是以HarmonyOS官网的codelab简易视频播放器(eTS)为基础进行编写.本篇最主要 ...
- electron 应用开发优秀实践
vivo 互联网前端团队-Yang Kun 一.背景 在团队中,我们因业务发展,需要用到桌面端技术,如离线可用.调用桌面系统能力.什么是桌面端开发?一句话概括就是:以 Windows .macOS 和 ...
- vue 将markdown字符串转html、修改主题、生成目录
前言 将 markdown 字符串转成 html 显示出来,同时把目录也提取出来一起显示.可以使用 marked 来读取 markdown 字符串解析成 html marked官网:https://m ...
- kubernetes网络模型
Overview 本文将探讨Kubernetes中的网络模型,以及对各种网络模型进行分析. Underlay Network Model 什么是Underlay Network 底层网络 Underl ...
- ENSP NE40E 报错(NE1启动操作超时,请检查与服务器链接后重试!)
前言:某网友淘宝找我咨询NE40E启动失败的问题,事后我整理的处理过程,供各位同行参考. 系统版本:windows 10 软件版本: ENSP:V100R003C00 virtual BOX:5.2. ...
- Excelize 发布 2.6.1 版本,支持工作簿加密
Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库,基于 ECMA-376,ISO/IEC 29500 国际标准.可以使用它来读取.写入由 Microsoft Exc ...
- 座位安排(欧拉回路,高斯消元,bitset)
题面 由于旋转大师 F r e n c h \rm French French 的离去, A r e x t r e \rm Arextre Arextre 光荣地承担了给全班换座位的重任. 由于这是 ...