十分钟了解k8s service到pod转发机制
什么是serviceservice只是一个抽象概念,在逻辑上将一组pod(功能相同)给抽象出来一个统一入口。可以将他简单理解为做了一个服务的负载均衡。我们知道pod在重新部署之后ip会改变,所以一般会通过service来访问pod。core-dns会给service分配一个内部的虚拟ip(节点上根本查询不到这个ip,ping是不通的,具体是怎么访问到的继续往下看),因此内部服务可以通过这个ip或者
什么是service
service只是一个抽象概念,在逻辑上将一组pod(功能相同)给抽象出来一个统一入口。可以将他简单理解为做了一个服务的负载均衡。我们知道pod在重新部署之后ip会改变,所以一般会通过service来访问pod。core-dns会给service分配一个内部的虚拟ip(节点上根本查询不到这个ip,ping是不通的,具体是怎么访问到的继续往下看),因此内部服务可以通过这个ip或者是serviceName来访问到pod的服务。
service提供的常用type:
- ClusterIP,也是默认方式。Service会分配一个集群内部的固定虚拟IP,实现集群内通过该IP来对POD进行访问。这个又有两类,上面说到的最普通的Service,ClusterIP还有一种是Headless Service,这种形式不会分配IP也不会通过kube-proxy做反向代理或者负载均衡,而是通过DNS提供稳定的网络ID来访问,DNS会将headless service的后端直接解析为POD的IP列表,这种主要是共StatefulSet类型使用。
- NodePort,这种类型的Service是除了使用ClusterIP的功能外还会映射一个宿主机随机端口到service上,这样集群外部可以通过宿主机IP+随机端口来访问。这样得保证每一个node节点的该端口都可用才行,直接使用任意node节点的ip+端口就能直接访问pod。
- HostPort,他这个和nodeport的区别是,只在某一个node节点打开端口。
- LoadBalancer:和nodePort类似,不过除了使用ClusterIP和NodePort之外还会向使用的公有云申请一个负载均衡器,从而实现集群外部通过LB来访问服务。这个主要是依托云lb。
- ExternalName:是Service的一种特例,此模式主要面对运行在集群外部的服务,通过它可以将外部服务映射到k8s集群,具备k8s内服务的一些特性,来为集群内部提供服务
apiVersion: v1
kind: Service
metadata:
namespace: app
name: eureka-server
labels:
name: eureka-server
spec:
type: NodePort ##这个位置来指定service的类型
selector:
app: eureka-server
ports:
- port: 80
targetPort: 9101
nodePort: 31101
什么是endpoints
endpoints也是k8s的一个资源,我们在创建service的时候如果我们设置了selector选中了需要关联的pod,那么就会创建一个与service同名的endpoints。他是用来记录service对应pod的访问地址。
可以看上图,我的baoming
服务启动了两个pod,因此endpoints中会有两个ip存储。
enpoints的维护是通过endpoint_controller
endpoint controller
endpoint controller是k8s集群控制器的其中一个组件,下面简单列举,详细的我建议大家去看下源码,go写的,我看的似懂非懂能理解一部分逻辑,简单了解干啥活就行。其功能如下:
- 负责生成和维护所有endpoint对象的控制器
- 负责监听service和对应pod的变化
- 监听到service被删除,则删除和该service同名的endpoint对象
- 监听到新的service被创建,则根据新建service信息获取相关pod列表,然后创建对应endpoint对象
- 监听到service被更新,则根据更新后的service信息获取相关pod列表,然后更新对应endpoint对象
- 监听到pod事件,则更新对应的service的endpoint对象,将podIp记录到endpoint中
重点来了 kube-proxy
英语过关的直接点这学霸专用通道,不行的装个有道翻译再进。
kube-proxy是对service的实现,也就是service只是用来抽象定义,真正具体化干活的是kube-proxy.它运行在每一个node节点上,负责该节点的网络代理。它是一个pod。
下面是kube-proxy三种模式:
-
Userspace模式,这种模式时最早的,不过已经不推荐使用了,效率低,因为需要在内核态和用户态多次转换,就不多做说明了。大家看图只需要看client的那条线。
当一个进程在执行用户自己的代码时处于用户运行态(用户态),此时特权级最低,为3级,是普通的用户进程运行的特权级,大部分用户直接面对的程序都是运行在用户态。Ring3状态不能访问Ring0的地址空间,包括代码和数据;当一个进程因为系统调用陷入内核代码中执行时处于内核运行态(内核态),此时特权级最高,为0级。执行的内核代码会使用当前进程的内核栈,每个进程都有自己的内核栈.
-
Iptables模式(默认)。当service或者endpoints、pod发生变化时,kube-proxy会创建对应的iptables规则。那开始的时候说的service的ip就出来了,它是iptables规则中的ip,并不对应到网络设备。这种模式下kube-proxy只用来维护iptables规则,iptables作为用户态的入口,直接调用内核态Netilter,中间省去了kube-proxy的内部转换。
在这种模式下,kube-proxy监视Kubernetes控制平面以添加和删除Service和Endpoint对象。对于每个服务,它都安装iptables规则,该规则捕获到服务clusterIP和的port流量,并将该流量重定向到服务的后端集之一。对于每个Endpoint对象,它将安装iptables规则,该规则选择一个后端Pod。
默认情况下,iptables模式下的kube-proxy会随机选择一个后端。
使用iptables处理流量具有较低的系统开销,因为流量由Linux netfilter处理,而无需在用户空间和内核空间之间切换。这种方法也可能更可靠。
如果kube-proxy在iptables模式下运行,并且所选的第一个Pod没有响应,则连接失败。这与用户空间模式不同:在这种情况下,kube-proxy将检测到与第一个Pod的连接已失败,并会自动使用其他后端Pod重试。
您可以使用Pod 准备就绪状况探针 来验证后端Pod 正常运行,以便iptables模式下的kube-proxy仅将经过测试的后端视为正常。这样做意味着您避免将流量通过kube-proxy发送到已知已失败的Pod。
- IPVS代理模式,没有仔细研究,网上查着看当service有成千上万个的时候速度上会更占优势。而且有更多的lb策略。
在ipvs模式下,kube-proxy监视Kubernetes服务和端点,调用netlink接口以相应地创建IPVS规则,并定期将IPVS规则与Kubernetes服务和端点同步。该控制循环可确保IPVS状态与所需状态匹配。访问服务时,IPVS将流量定向到后端Pod之一。
IPVS代理模式基于类似于iptables模式的netfilter挂钩函数,但是使用哈希表作为基础数据结构,并且在内核空间中工作。这意味着,与iptables模式下的kube-proxy相比,IPVS模式下的kube-proxy可以以更低的延迟来重定向流量,从而在同步代理规则时具有更好的性能。与其他代理模式相比,IPVS模式还支持更高的网络流量吞吐量。
IPVS提供了更多选项来平衡后端Pod的流量。这些是:
rr:轮循
lc:连接最少(打开的连接最少)
dh:目标哈希
sh:源哈希
sed:最短的预期延迟
nq:永不排队
更多推荐
所有评论(0)