ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

K8S svc原理

K8S svc原理 Service(svc)通过标签选择的方式匹配一组Pod对外访问服务的一种机制,每一个svc可以理解为一个微服务。微服务对这一组Pod进行轮循访问工作原理1k8s在创建service时候会根据标签选择器selector(Lable selector)来查找pod,据此创建与service同名的endpoint对象当pod地址发生变化时,endpoint也会随之发生变化service接收到前端client请求的时候就会通过endpoint,找到要转发到哪个Pod进行访问网站的地址。(至于要转发到哪个节点的Pod,由负载均衡kube-proxy起初就决定好了的)endpoint解释1231.endpoint是k8s集群中的一个资源对象存储在etcd中用来记录一个service对应的所有pod的访问地址。2.只有当service配置selector(选择器) ,endpoint controller才会自动创建对应的endpoint对象否则不会生成endpoint对象。3.例:k8s集群中创建一个名为hello的service就会生成一个同名的endpoint对象endpoint就是service关联的pod的ip地址和端口。userspace模式工作原理图(按个人理解画的)此图为node1服务器节点clusterIP 主要在每个 node 节点使用 iptables将发向 clusterIP port的数据转发到 kube-proxy 中。然后 kube-proxy 自己内部实现有负载均衡的方法并查询到这个 service 下的 endPoints,找到对应的 pod 的地址和对应端口进而把数据转发给对应的 pod 的地址和端口1234567891011121314151617181920212223访问Service的请求不论是Cluster IP TargetPort的方式还是用Node节点的IPNodePort的方式都被Node节点的Iptables规则重定向到Kube-proxy监听Service服务代理端口。kube-proxy接收到Service的访问请求后根据负载策略转发到后端的Pod。1.Service在很多情况下只是一个概念而真正将Service的作用实现的是kube-proxy服务进程。2.每个Node节点上都会运行一个kube-proxy服务进程。3.对每一个TCP类型的Kubernetes Service,kube-proxy都会在本地Node节点上建立一个SocketServer来负责接收请求然后均匀发送到后端某个Pod的端口上。这个过程默认采用Round Robin负载均衡算法。4.kube-proxy在运行过程中动态创建与Service相关的Iptables规则这些规则实现了ClusterIp及NodePort的请求流量重定向到kube-proxy进程上对应服务的代理端口功能。5.kube-proxy通过查询和监听API Server 中Service与Endpoints的变化为每个Service都建立一个“服务代理对象”并自动同步。服务代理对象是kube-proxy程序内部的一种数据结构它包括一个用于监听此服务请求的SockerServer,SocketServer的端口是随机选择一个本地空闲端口。此外kube-proxy内部创建了一个负载均衡器-LoadBalancer.6.针对发生变化的Service列表kube-proxy会逐个处理a. 如果没有设置集群IP则不做任何处理否则取该Service的所有端口定义列表。b.为Service端口分配服务代理对象并为该Service创建相关的Iptables规则。c.更新负载均衡器组件中对应Service的转发地址列表7.kube-proxy在启动时和监听到Service或Endpoint的变化后会在本机Iptables的NAT表中添加4条规则链。a.KUBE-PORTALS-CONTAINER: 从容器中通过Cluster IP 和端口号访问service.b.KUBE-PORTALS-HOST: 从主机中通过Cluster IP 和端口号访问service.c.KUBE-NODEPORT-CONTAINER:从容器中通过NODE IP 和端口号访问service.d. KUBE-NODEPORT-HOST:从主机中通过Node IP 和端口号访问service.Service提供常用的类型有ClusterIP也是默认方式。Service会分配一个集群内部的固定虚拟IP实现集群内通过该IP来对POD进行访问。这个又有两类上面说到的最普通的ServiceClusterIP还有一种是Headless Service这种形式不会分配IP也不会通过kube-proxy做反向代理或者负载均衡而是通过DNS提供稳定的网络ID来访问DNS会将headless service的后端直接解析为POD的IP列表这种主要是共StatefulSet类型使用。NodePort这种类型的Service是除了使用ClusterIP的功能外还会映射一个宿主机随机端口到service上这样集群外部可以通过宿主机IP随机端口来访问。LoadBalancer和nodePort类似不过除了使用ClusterIP和NodePort之外还会向使用的公有云申请一个负载均衡器从而实现集群外部通过LB来访问服务 公有云负载 要花钱)ExternalName是Service的一种特例此模式主要面对运行在集群外部的服务通过它可以将外部服务映射到k8s集群具备k8s内服务的一些特性来为集群内部提供服务。123456简单概括1.ClusterIP默认类型自动为每个Pod分配一个仅cluster内部可以访问的虚拟IP2.NodePort在ClusterIp的基础上为每台机器绑定一个端口。这样就可以通过NodeIP:NodePort(节点ip:端口)来访问该服务3.loadBalaner,在NodePort的基础上借助cloud provider创建一个外部负载均衡器并将请求转发到NodePort 需要独立收费外部设备4.Externalname,把集群外部的服务引入到集群内部来在集群内部直接 使用没有任何类型代理被创建只有kubernetes1.7以上版本才支持要说一下ClusterIP这个东西这是通过yaml安装的一个coredns插件它就的配置清单中就定义了service。1kubectl get svc这个servic ip地址段是在部署API server的时候, API server服务 配置文件中定义的地址段。而且在Flannel中都没有这个地址段。相比之下POD的IP其实是实实在在配置在容器中的。最重要的是集群中任何节点上都没有关于这个网段的路由信息那么集群内部是如何通过这个完全虚拟的IP来访问的呢这就要说到kube-proxy了你看在集群的任何机器上都可以PING通这个地址。我们来看看这个svc的详情1kubectl describe svc myapp-nodeport12这个10.101.188.44 serviceIP关联了Endpoints那么现在就有了一个大致的认识就是你访问10.101.188.44就是访问10.244.1.93:80,10.244.1.94:80,10.244.2.96:80其中一个而这个IP就是POD的真实IP这个IP段是在Flannel上配置过的。下面再来看一张图1234567在IPVS规则中定义了访问10.101.188.44就会转发到(10.244.1.93:80,10.244.1.94:80,10.244.2.96:80)轮循所以通过上面我们就知道它其实是通过IPVS规则来转发的根本不是通过路由来实现的。可是你想过没有这个规则是谁生成的呢其实就是kube-proxy来生成的而且这样的规则会同步到集群其他机器上哪怕这个POD没有运行在自己的机器上也要有这样的规则只有这样才能保证集群任何一台主机都可以通过这个serviceIP来访问到POD当面临跨主机的时候才会用到路由规则由Flannel的隧道来进行转发到真实POD所在主机然后由该主机的kube-proxy来转发到具体的POD上。这时候我们就明白了kube-proxy的大致作用当service有了IP和端口,以及POD的IP和端口对应关系,以及宿主机随机端口到service的映射就可以完成对内、外请求的转发而转发就是本地转发或是用IPVS规则而远程则用了路由信息。集群中每个NODE都运行一个kube-proxy进程,这个就是service的载体。它负责建立、删除和更新IPVS规则、通知API SERVER自己的更新或者从API service那里获取其他kube-proxy的IPVS规则变化来更新自己的。但是userspace模式每次请求都要走一遍kube-proxy,那么kube-proxy的频繁任务太重。并且效率不高怎么办于是诞生了iptables模式iptables在这种模式下kube-proxy监控kubernetes对svc和endpoints对象进行增删改查。并且这种模式使用iptables来做用户态的入口。而真正提供服务的是内核的NetilterNetfilter采用模块化设计具有良好的可扩充性。其重要工具模块IPTables从用户态的iptables连接到内核态的Netfilter的架构中Netfilter与IP协议栈是无缝契合的并允许使用者对数据报进行过滤、地址转换、处理等操作。这种情况下proxy只作为Controller。Kube-Proxy 监听 Kubernetes Master 增加和删除 Service 以及 Endpoint 的消息。对于每一个 ServiceKube Proxy 创建相应的 IPtables 规则并将发送到 Service Cluster IP 的流量转发到 Service 后端提供服务的 Pod 的相应端口上。并且流量的转发都是在内核态进行的所以性能更高更加可靠。此图片来源于网络懒不想画了。1在这种模式下缺点就是在大规模的集群中iptables添加规则会有很大的延迟。因为使用iptables每增加一个svc都会增加一条iptables的chain。并且iptables修改了规则后必须得全部刷新才可以生效。IPVSIPVS相对于iptables来说效率会更加高使用ipvs模式需要在允许proxy的节点上安装ipvsadmipset工具包加载ipvs的内核模块。并且ipvs可以轻松处理每秒 10 万次以上的转发请求。当proxy启动的时候proxy将验证节点上是否安装了ipvs模块。如果未安装的话将回退到iptables模式。这种模式kube-proxy 会监视 Kubernetes Service 对象和 Endpoints 调用 netlink 接口以相应地创建 ipvs 规则并定期与 Kubernetes Service 对象和 Endpoints 对象同步 ipvs 规则以确保 ipvs 状态与期望一 致。访问服务时流量将被重定向到其中一个后端 Podipvs模式也是基于netfilter对比iptables模式在大规模Kubernetes集群有更好的扩展性和性能支持更加复杂的负载均衡算法(如最小负载、最少连接、加权等)支持Server的健康检查和连接重试等功能。ipvs依赖于iptables使用iptables进行包过滤、SNAT、masquared。ipvs将使用ipset需要被DROP或MASQUARED的源地址或目标地址这样就能保证iptables规则数量的固定我们不需要关心集群中有多少个Service了本文固定链接: http://www.yoyoask.com/?p2163转载请注明: shooter 2020年03月02日 于 SHOOTER 发表ServiceK8s 服务一句话Service 是一组Pod的统一访问入口提供稳定的网络地址解决Pod飘忽不定的问题。为什么需要 ServicePod特点Pod会销毁重建Pod IP每次重建都会变Deployment扩缩容Pod数量会变化一批PodIP动态增减如果直接访问PodIPPod重启IP就失效不能直接拿来业务调用。Service 屏蔽Pod的动态变化给这一组Pod提供一个固定IPClusterIP后端通过label selector匹配Pod。客户端 → Service固定IP → 负载均衡 → 后端一组PodService不代理存储数据只是四层网络负载均衡。依靠label selector挑选后端Pod。Service 工作原理简要Service定义selector匹配Pod标签例如app:nginxk8s控制器endpoint-controller自动维护Endpoints对象保存所有匹配成功Pod的IP端口列表kube‑proxy 在每个节点上把Service的IP规则写到iptables/ipvs实现流量转发到后端Pod。你改Pod标签、Pod新建删除Endpoints自动更新kube‑proxy同步转发规则。Service 四种type类型重点1. ClusterIP默认类型分配一个集群内部虚拟IP仅集群内部Pod可以访问外部机器访问不了。最常用微服务之间互相调用。yaml示例apiVersion: v1 kind: Service metadata: name: nginx-svc namespace: dev spec: type: ClusterIP # 默认可以省略 selector: app: nginx # 选择labelapp:nginx的pod ports: - port: 80 # Service自身端口 targetPort: 80 # 后端Pod容器端口portservice端口targetPortpod容器端口集群内部访问nginx-svc:80k8s自带DNS同namespace直接写service名字就可以解析ClusterIP。 跨namespace访问格式服务名.命名空间.svc.cluster.local例nginx-svc.dev.svc.cluster.local2. NodePort在每一个集群节点上打开一个物理端口30000‑32767外部机器访问节点IP:NodePort端口流量进入集群转发到后端Pod。缺点端口范围有限不适合生产大规模对外暴露。spec: type: NodePort selector: app: nginx ports: - port: 80 targetPort:80 nodePort: 30080 # 可选不写自动分配访问任意节点IP:300803. LoadBalancer云厂商专用在NodePort基础之上调用云厂商API创建外部负载均衡器SLB分配公网IP。公网用户访问这个公网SLB IP流量进到集群。阿里云、腾讯云k8s支持裸金属自建k8s没有这个能力。spec: type: LoadBalancer4. ExternalName不做负载均衡只是DNS别名把service映射到外部域名数据库、外部中间件。 集群内部访问service名字解析为外部域名。Endpoints看不见的配套对象Service的selector匹配pod生成Endpoints资源保存后端Pod列表。kubectl get endpoints nginx-svc如果endpoints为空selector没有匹配到任何Pod标签这是高频故障点。Service不会直接操作Pod完全靠label selector。如果你Pod label写错endpoints为空访问service会连接失败。Service 不做什么❌Service是四层TCP/UDP负载均衡不能处理http域名、https证书。七层http/https要交给 Ingress。❌Service不会主动探测业务应用是否正常只看Pod是否ready就绪业务死了但是pod状态readyservice依然转发流量。需要liveness/readiness探针Service vs Ingress简单区分Service四层给集群内部访问或者NodePort/LoadBalancer对外提供IP。Ingress七层HTTP域名、路径路由统一证书接收外部http流量转发给后端Service。外网 → Ingress(7层) → Service(4层) → Pod常用命令kubectl get svc -n dev kubectl describe svc nginx-svc kubectl get endpoints nginx-svc高频踩坑总结selector的label和Pod的label不一致 → endpoints为空访问服务不通。port和targetPort搞混。ClusterIP只能集群内部访问本机电脑不能直接访问ClusterIP。LoadBalancer依赖云厂商CSI/CCM组件自建k8s typeLoadBalancer不会生成公网IP。快速记忆Service 一组Pod的固定门面地址。 通过标签选PodEndpoints存后端PodIPkube‑proxy实现转发 ClusterIP集群内用NodePort节点端口LoadBalancer云厂商公网负载。前面我们已经学完 Pod、ReplicaSet、Deployment、PV/PVC/StorageClass、Namespace、Service。 如果你需要我可以把这些全部串成一张完整业务调用链路。
返回列表