1

k8s权威指南笔记:Service

 2 years ago
source link: https://keys961.github.io/2022/04/03/k8s%E6%9D%83%E5%A8%81%E6%8C%87%E5%8D%97%E7%AC%94%E8%AE%B0(4)/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

1. Service定义

Service定义文档:

  • https://kubernetes.io/zh/docs/concepts/services-networking/service/

  • https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#service-v1-core

2. Service概念与原理

2.1. Service概念

Service用途:

  1. 给一组Pod提供一个抽象、稳定的网络地址

  2. 实现负载均衡/路由,透明化后端Pod地址(Endpoint)

例如,有2个Tomcat的Pod组成的Deployment,包含2个Pod的地址,需要直接和它们通信,负载均衡需要自己做。

之后抽象出1个Service,抽象出一个稳定地址,访问该地址,自动负载均衡且不需要知道Pod的地址。

2.2. 负载均衡机制

a. kube-proxy代理

通过每个Node等kube-proxy进程代理。

提供三种模式:

  • user-space:代理在用户空间实现,效率最低

  • iptables:基于内核的iptables规则进行转发路由,需要通过readiness probe更新规则

  • ipvs:基于内核netlink接口的IPVS规则,效率最高,需启动IPVS模块,否则退回iptables模式

路由规则支持:round-robin, least connection, dst hashing, src hashing, shortest expected delay等

b. 会话保持机制

一段时间内(会话内),将某个源IP的请求路由到同个Pod上。

Pod定义中,使用sessionAffinity设置(为ClientIP),并设置会话过期时间。

2.3. 端口设置

Service可以指定多个端口,以暴露在外。端口的通信协议可不同。

端口列表中每个端口的3个不同字段:

  • port:服务暴露给集群内部访问的端口,配合ClusterIP:port使用

  • targetPort:映射到Pod上的端口,默认和port相同

    • 如:Service的port80,Pod服务的端口是8080,则targetPort8080
  • nodePort:绑定在Node IP上的端口,以便外部访问,配合NodeIP:nodePort使用

2.4. 路由到外部服务

一般情况下,Service将一组Pod合起来,将请求直接转发到Pod上。

也可直接路由到外部服务,即Service -> Service,不需配置Label Selector(selector)。

  1. 定义外部Service的Endpoints对象,即指名外部Service的IP和端口列表

  2. 本服务引用步骤1的Endpoints对象

2.5. 发布服务

通过设置spec.type,将Service暴露给外部使用。共4种方法:

  • ClusterIP:默认,集群内部IP暴露,仅内部访问

  • NodePort:通过物理节点Node的IP暴露,即通过nodeIP:nodePort访问

  • LoadBalancer:通过云服务商的负载均衡器,向外部暴露服务。服务上云后,负载均衡器会自动将外网IP请求路由到ClusterIPNodePort服务上

  • ExternalName:通过DNS到CNAME机制,将Service的内部域名转换为externalName外部域名来访问

也可以用Ingress暴露,见后文。

2.6. 支持的网络协议

  • TCP:默认,任意可用

  • UDP:大多可用,若spec.typeLoadBalancer(见2.5节),取决于云服务商

  • SCTP:需要插件,若spec.typeLoadBalancer,取决于云服务商

  • HTTP:取决于云服务商,也可以用Ingress直接暴露

  • PROXY:取决于云服务商

2.7. 服务发现

实现机制有2类:

  1. 环境变量:创建Pod后,自动设置Service的地址、端口等环境变量

    • 格式类似<servicename>_SERVICE_HOST<servicename>_SERVICE_PORT
  2. DNS(推荐):使用CoreDNS服务器提供域名解析

    • A/AAAA记录:

      • 格式为<servicename>.<namespace>.svc.<clusterdomain>

      • “普通”服务返回一个IP地址,“无头”服务返回1组Pod的IP地址列表

    • SRV记录:

      • 设置命名端口后,每个端口都有一条SRV记录,解析为端口号和域名

      • 格式为_<portname>._<protocol>.<servicename>.<namespace>.svc.<clusterdomain>

      • “普通”服务返回1个结果,“无头”服务返回1组Pod的结果

2.8. Headless Service

不提供ClusterIP,需要设置clusterIP: None

外部应用从DNS获取一组Pod的Endpoint列表,需要自行实现负载均衡。

若指定了Label Selector,则扫描符合条件的Pod,加入Endpoint列表中。

若没指定Label Selector,则不会创建Endpoint列表,而是:

  • spec.typeExternalName,则直接转换为externalName外部域名

  • 若Service定义中有同名的Endpoint定义,则转换为该Endpoint定义中的列表

2.9. Endpoint Slices

将一组完整Pod的Endpoint列表分成若干个分片,解决大集群扩展问题。

为某个Service所有,类似于将网络分成若干子网分开管理:Service -> Endpoint Slice -> Endpoint。

原始情况:

  • Service要存储每个Pod的Endpoint,这些存储于etcd中,成本高、apiserver压力大且有容量限制

  • kube-proxy需要维护的iptables或ipv的规则增多

  • Pod的Endpoint更改时,都要传输到每个kube-proxy上,带宽浪费

Endpoint Slices下:

  • Pod的Endpoint更改时,只需更新一个分片,开销急剧变小

  • 为基于Node拓扑的服务路由提供支持

Endpoint Slice分片:基于nodeNamezone

Endpoint Slice分片平衡:

  1. 移除和修改已有Endpoint Slice的Endpoint

  2. 对1中已修改的Endpoint Slice,用新Endpoint填满

  3. 剩余的,添加到未修改的Endpoint Slice,或创建新的,优先考虑创建新的

3. DNS服务

3.1. CoreDNS服务器

目前使用CoreDNS实现,为一个Pod,里面为1个coredns容器。架构图如下:

图片.png

部署可参考:[使用 CoreDNS 进行服务发现 Kubernetes](https://kubernetes.io/zh/docs/tasks/administer-cluster/coredns/)

3.2. Node本地DNS缓存

Node节点本地拥有NodeLocal DNSCache,优先使用本地,然后使用CoreDNS查询。可缓解CoreDNS服务器压力,降低查询延迟、网络竞争,提升性能。

部署可参考:[在 Kubernetes 集群中使用 NodeLocal DNSCache Kubernetes](https://kubernetes.io/zh/docs/tasks/administer-cluster/nodelocaldns/)

3.3. Pod DNS

a. 域名规则

规则为:<pod-ip>.<servicename>.<namespace>.pod.<clusterdomain>

若Pod没有由Service暴露出来,则<servicename>省略。

b. 自定义hostname和subdomain

Pod的定义文件中,可设置hostname,替换掉规则中的pod-ip

也可设置subdomain,替换掉<servicename>。若需要将其暴露在外,需要创建Headless Service,其name要设置为对应的subdomain

c. DNS策略

配置dnsPolicy设置,有4种:

  • Default:继承宿主机

  • ClusterFirst:优先使用k8s集群的DNS服务(如CoreDNS)

  • ClusterFirstWithHostNet:若Pod开启hostNetwork直接使用宿主机网卡通信,开启它可使用k8s集群的DNS服务

  • None:忽略,需要手动配置DNS,见下d

d. 自定义DNS配置

dnsPolicyNone时,在dnsConfig设置,包含下面3个参数:

  • nameservers:DNS服务器列表

  • searches:用于搜索的域名后缀

  • options:其它可选参数,如ndot,timeout

4. Ingress

Ingress将集群内服务暴露到集群外,并进行服务到流量路由,规则由Ingress对象控制。

其包含了:

  • Ingress Controller:进行服务暴露和流量路由

  • Ingress:定义路由规则

外部访问Ingress Controller暴露的端口即可。

图片.png

4.1. Ingress Controller

  • 进行服务暴露和流量路由

  • 自动监听apiserver并更新路由规则

可选nginx、HAProxy、云服务提供等方案。

部署:选择一个方案,如nginx-ingress,构建Deployment或DaemonSet

  • nginx-ingress: https://kubernetes.github.io/ingress-nginx/deploy/

4.2. Ingress

用于定义路由规则。

包含2种设置:

  1. 路由规则(spec.rules):包括host域名、http.paths服务路径,每个路径还需要设置backend,即对应的服务名和端口号

    • 路径需要设置路径类型(pathType),可选精确、前缀,或由哪个IngressClass控制,通配符也可匹配
  2. 默认后端设置(defaultBackend):在不匹配任何服务时,路由到此,也可在Ingress Controller中设置

4.3. IngressClass

k8s可部署多个Ingress Controller,而Ingress归哪个Ingress Controller管,需要IngressClass。

IngressClass指定了Ingress Controller的名字,Ingress应用它即可归对应的Ingress Controller管。

系统有一个默认的IngressClass,当Ingress没指定IngressClass时使用。


0 comments

Be the first person to leave a comment!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK