K8s-深入理解Service

基于K8s v1.31

Overview

Service是K8s实现微服务的核心,通过创建Srvice,可以实现具有相同的功能都容器提供一个统一的入口

Service的概念和原理

负载均衡机制

当一个Service对象被定义出来,客户端都可以通过ServiceIP访问Pod容器,到每个Node山上交与kube-porxy实现

kube-porxy的代理模式

  1. 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: 30s
  2. ipvs模式(仅适用于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:用不排队
  3. 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
kind: Service
metadata:
name: svc
spec:
# 设置会话
sessionAffinity: ClientIP
# 配置会话保持时间
sessionAffinityConfig:
clientIP:
# 3h
timeoutSeconds: 10800
selector:
app: svc
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: NodePort

流量策略

K8s 从v1.21开始,引入

apiVersion: v1
kind: Service
metadata:
name: svc
spec:
# 设置流量策略 v1.21引入, v1.26进入到stable
internalTrafficPolicy: Cluster
externalTrafficPolicy: Local

在K8s 1.22引入ProxyTerminatingEndpoints字段,在1.2 Stable阶段,管理如何处理正在停止的Endpoints流量

Service多端口设计

K8s Service支持多端口,区分协议和端口号

ports:
- protocol: TCP
port: 80
name: web
targetPort: 8080
- protocol: UDP
port: 53
name: dns
targetPort: 5353

外部服务定义为Service

Service多应用场景:

  1. 已经部署的集群外部服务,比如数据库服务、缓存服务等
  2. 其他K8s集群的某个服务
  3. 迁移过程中对某个服务进行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不会创建负载均衡转发规则,而是服务名的解析机制

  1. 设置了标签选择器

    当客户端访问的时候,获取到的Endpoints列表

apiVersion: v1
kind: Service
metadata:
name: svc
spec:
selector:
app: svc
  1. 没有设置标签选择器

    K8s不会自动创建对应的Endpoints列表,DNS系统会尝试下面的条件对服务名设置DNS记录

    • 如果Service的类型为ExternalName,则尝试将服务名的DNS记录设置为外部名称(externalName,DNS域名格式)对应的CNAME记录
    • 对于其他类型的Service,系统将对Service后端处于Ready的Endpoint(以及EndpointSlice)创建DNS记录,针对IPv4创建A记录,针对IPv6创建AAAA记录

为服务设置外部IP地址

apiVersion: v1
kind: Service
metadata:
name: svc
spec:
externalIPs:
- 192.168.1.2

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的表示方法为:..svc.

  • servicename:服务名称
  • namespace:命名空间
  • clusterdomain:集群设置的域名后缀

如果在SVC中设置了Name,也会有一个SRV记录的格式:_._...svc.

端点分片

K8s 从1.16引入了EndpointSlice机制,包含一个新的EndpointSlice和EndpointSlice Controller,在v1.21进入Stable

通过Endpoint点分片管理减少Master和各个Node之间的网络传输和提高整体性能,

  • v1.17默认开启

EndpointSlice的关键信息:

  1. 管理的服务名称,将EndpointSlice与Service关联信息设置一个标签

  2. 地址类型AddressType,包含三类取值类型

    • IPv4
    • IPv6
    • FQDN:全球限定域名
  3. 在Endpoints列表每个Endpoints信息

    • Address:Endpoint IP地址

    • Conditions:状况信息,用于系统判断Endpoint是否可等

    • Hostname:在Endpoints设置主机名hostname

    • TargeRef:Endpoint对应的Pod名称,用于外部服务可能没有该信息

      有俩个EndpointSlice Controller自动设置的信息

      • nodeName:Endpoint所在Node名称
      • zone:Endpoint所在Zone信息
  4. 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只支持一个