K8s-深入理解Service
K8s-深入理解Service
基于K8s v1.31
Overview
Service是K8s实现微服务的核心,通过创建Srvice,可以实现具有相同的功能都容器提供一个统一的入口
Service的概念和原理
负载均衡机制
当一个Service对象被定义出来,客户端都可以通过ServiceIP访问Pod容器,到每个Node山上交与kube-porxy实现
kube-porxy的代理模式
iptables模式 (v1.28中实现)
通过基于Linux 的 Linux Kernel的iptables规则实现,实现了从Service到后端Endpoints列表的负载均衡规则
每次创建Service和Endpoints发生变化,kube-proxy都会刷新本Node得全部iptables,在大规模集群(service和endpoints数量达到数百万),刷新时间过长,系统性能下降,可以通过调整kube-proxy的资源对象KubeProxyConguration中的同步行为;
iptables:
# 设置同步最短时间,默认1s
minSyncPeriod: 1s
# 同步时间间隔
syncPeriod: 30sipvs模式(仅适用于Linux 操作系统)
在ipvs模式下,kube-proxy通过Linux Kernel的netlink接口来设置iptables模式。
ipvs模式基于Linux操作系统的netfilter钩子函数,类似与iptables,但是使用更加散列表作为底层数据结构,并且工作在内核空间,这使得ipvs模式比iptables模式的转发性能更高,同步Service和Endpoints规则的效率也更高,还有支持更高的网络吞吐量
ipvs要求Linux Kernel启用IPVS内核模块,如果kube-proxy未检测开启,自动切换到iptables
ipvs支持许多负载均衡策略:
- rr:轮询
- wrr:加权轮询
- lc:最小连接数
- wlc:加权最小连接数
- lblc:基于地域的最小连接数
- lblcr:带有副本的基于地域的最小连接数
- sh:源地址散列
- dh:目的地址散列
- sed:最短期望延迟
- nq:用不排队
kernelspace模式
这是Windows操作系统内核的数据包转发代理模式,使用Hyper-V vSwitch的拓展(VFP),仅仅用于windows
K8s 从v1.14开始提供网络应答的DSR模式,该模式处于Alpha阶段,通过kube-proxy命令行参数–enable-dsr和开启WinDSR特性进行启用,允许Svc的后端Pod直接返回网络响应给调用Service的客户端,而不是通过节点的VFR代理实现
回话保持机制
Service支持设置sessionAffinity来实现基于客户端IP的会话保持机制,即首次将某个客户端来源IP发起的请求转发到后端Pod之后,之后从相同的源客户端,都转发到相同的Pod,配置参数为service.spec.sessionAffinity
apiVersion: v1 |
流量策略
K8s 从v1.21开始,引入
apiVersion: v1 |
在K8s 1.22引入ProxyTerminatingEndpoints字段,在1.2 Stable阶段,管理如何处理正在停止的Endpoints流量
Service多端口设计
K8s Service支持多端口,区分协议和端口号
ports: |
外部服务定义为Service
Service多应用场景:
- 已经部署的集群外部服务,比如数据库服务、缓存服务等
- 其他K8s集群的某个服务
- 迁移过程中对某个服务进行K8s服务名访问机制
Service的类型
- ClusterIP:K8s默认自动设置Service虚拟IP地址,仅可被集群内客户端应用访问
- NodePort:将Service的端口号映射到每个Node对一个端口号上,这样集群中规定任意Node都可以作为Service的访问入口地址,即NodeIP:NodePort
- LoadBalancer:将Service映射到一个已经存在的负载均衡的IP地址上
- ExternalName:将Service映射为一个外部域名地址,通过externalName设置
ClusterIP
这是K8s默认设置IP地址类型,kube-apiserver启动参数--service-cluster-ip-range
设置Service的IP地址范围,也可以手动分配IP
- 在K8s v1.24中引入新特性ServiceIPStaticSubrange用于允许管理静态分配的ClusterIP范围,降低与系统分配IP产生的冲突改了,在V1.26中进入Stable
ServiceIPStaticSubrange的工作机制:
- 分为高地位:高位动态分配范围,低位静态分配范围
- 划分算法:min(max(16,cidrSize/16),256)
在K8s v1.27中引入MultiCIDRServiceAllocator特性和API资源IPAddress,使用MulitCIDRServiceAllocator特性门控才能开启,对于动态控制,目前处于Alpha
NodePort
NodePort可以应用Service暴露到Node
- NodePort端口范围,可以通过
--service-node-port-range
指定可以分配到端口范围(默认30000-32767)
在K8s v1.27开始提供了ServiceNodePortStaticSubrange特性门控,控制端口冲突,在v1.29进入stable
- 工作原理也是划分前后部分,前面作为静态范围, 后面大的作为动态范围
- 划分计算公式:min(max(16,nodePortSize)/32,128)
- 另外kube-proxy默认给所有网卡绑定上Nodeport,实际上可以通过制定特定网卡实现不同网卡的效果
LoadBalancer
通常使用外部负载均衡器多云平台,可以设置Service多类型为LB
ExternalName
定义集群外的ServiceK8s集群的访问地址
Headless Service
Headless Service(无头服务),无ClusterIP,kube-proxy不会创建负载均衡转发规则,而是服务名的解析机制
设置了标签选择器
当客户端访问的时候,获取到的Endpoints列表
apiVersion: v1 |
没有设置标签选择器
K8s不会自动创建对应的Endpoints列表,DNS系统会尝试下面的条件对服务名设置DNS记录
- 如果Service的类型为ExternalName,则尝试将服务名的DNS记录设置为外部名称(externalName,DNS域名格式)对应的CNAME记录
- 对于其他类型的Service,系统将对Service后端处于Ready的Endpoint(以及EndpointSlice)创建DNS记录,针对IPv4创建A记录,针对IPv6创建AAAA记录
为服务设置外部IP地址
apiVersion: v1 |
Service支持的网络协议
- UDP
- TCP
- SCTP:在K8s v1.12中引入,其到v1.20 处于stable,LB取决厂商支持
- HTTP:取决厂商是否支持HTTP
- PROXY:取决厂商
- TLS:取决厂商
服务发现机制
服务发现机制是K8s集群客户端应用如何获取后端服务的访问地址
环境变量
在Pod启动之后,系统会自动为其容器允许环境注入集群中有效的Service的信息
格式:{SVCNAME}_SERVICE_HOST和{SVCNAME}_SERVICE_PORT格式进行设置
DNS方式
Service在K8s遵守DNS命名,Service在NDS的表示方法为:
- servicename:服务名称
- namespace:命名空间
- clusterdomain:集群设置的域名后缀
如果在SVC中设置了Name,也会有一个SRV记录的格式:_
端点分片
K8s 从1.16引入了EndpointSlice机制,包含一个新的EndpointSlice和EndpointSlice Controller,在v1.21进入Stable
通过Endpoint点分片管理减少Master和各个Node之间的网络传输和提高整体性能,
- v1.17默认开启
EndpointSlice的关键信息:
管理的服务名称,将EndpointSlice与Service关联信息设置一个标签
地址类型AddressType,包含三类取值类型
- IPv4
- IPv6
- FQDN:全球限定域名
在Endpoints列表每个Endpoints信息
Address:Endpoint IP地址
Conditions:状况信息,用于系统判断Endpoint是否可等
Hostname:在Endpoints设置主机名hostname
TargeRef:Endpoint对应的Pod名称,用于外部服务可能没有该信息
有俩个EndpointSlice Controller自动设置的信息
- nodeName:Endpoint所在Node名称
- zone:Endpoint所在Zone信息
EndpointSlice Controller通过endpointslice.kubernetes.io/managed_by标签进行管理
EndpointSlice的状况类型说明
包含三种状态:Ready、Serving和Terminating
- Ready:取自Pod的Ready。Pod为正常运行服务就绪时,EndpointSlice的Ready为true;当Pod处于停止中,EndpointSlice的Ready=false,但是如果设置了字段pushlichNotReadyAddress=true,永远为true
- Serving:这是K8s 从v1.20开始提供的新类型,在v1.26处于Stable。处于停止依旧可以接受请求
- Terminating:v1.20引入。v1.22进入到Beta,表示Endpoint是否处于停止
EndpointSlice的镜像复制功能
为了避免创建了Endpoint资源再去创建EndpointSlice,自动完成Endpoint到EndpointSlice的操作,K8s从1.19默认支持
下面的情况不会自动复制:
- Endpoint设置了标签:endpointslice.kubernetes.io/skip-mirror=true
- Endpoint设置了注解:control-plane.aplha.kubernetes.io/leader
- Endpoint对应的Service不存在
- Endpoint对应的Service设置了非空的选择器
一个Endpoint资源同时存在IPv4和IPv6,会被复制为多个EndpointSlice资源,每种地址最多被复制为1000个EndpointSlice
EndpointSlice的数据分布管理机制
如何自动平衡replace
- 便利所有EndpointSlice,删除不需要的Endpoint,更新匹配的Endoint
拓扑感知路由机制
v1.21引入的,v1.27通过拓扑感知提示进行标注,v1.28被称为拓扑感知路由机制
DNS服务搭建和配置指南
基于CoreDNS得搭建
修改每个Node上kubelet的启动参数
添加kubelet参数
--cluster-dns=169.169.0.100
:是DNS服务的ClusterIP--cluster-domain=cluster.local
:在DNS设置的域名
部署CoreDNS
…
服务名的DNS解析
…
CoreDNS配置说明
CoreDNS功能是通过插件链式调用生成
常见插件如下:
- Loadbalance:提供基于DNS的负载均衡功能
- loop:检测DNS解析过程中出现的简单循环问题
- cache:提供前段缓存功能
- health:对Endpoint进行监控检查
- Kubernetes:从K8s读取Zone数据
- etcd:从etcd中读取Zone数据,可用于自定义域名记录
- file:从RFC1035格式中读取Zone数据
- hosts:使用/etc/hosts文件或者其他文件读取Zone数据,可用于域名记录
- auto:从磁盘中自动加载区域文件
- reload:定时自动重载Configfile配置文件中的内容
- prometheus:为Prometheus提供采集性能指标的URL
- pprof:在URL的/debug/pprof下提供运行时的性能数据
- log:对DNS查询进行日志记录
- errors:对错误信息进行日志记录
Node本地DNS缓存服务搭建和配置指南
…
Service和Pod的DNS域名相关性
为了使用域名访问,会根据SVCName,NS来在/etc/resolv.conf自动后缀
Service的DNS域名
对于Service来说,K8s会设置一个如下格式的DNS域名
. .svc.
K8s也会为Service的每个命名端口色设置一个SRV记录
. . . .svc.
Pod的DNS域名
对于Pod来说,K8s会设置一个如下格式的域名
. .pod.
Pod自定义hostname和subdomain
通过设置.spec.hostname和.spec.subdomain实现
Pod的DNS策略
在pod的dnsPolicy字段可以设置不同的DNS策略
- Default:继承Pod所在Node的域名解析设置
- ClusterFirst:优先使用K8s环境的DNS
- ClusterFirstWithHostNet:专用于hostNetwork运行的Pod
- Node:忽略K8s集群的DNS,运行用户手动通过dnsConfig设置,在1.14进入stable
Pod自定义DNS
dnsConfig …
Window NodeDNS解析说明
- 不支持DNS策略dnsPolicy=ClusterFirstWithHostNet
- Linux支持多个searches搜索域名后缀,windows只支持一个