【Kubernetes知识点】 解读 Service 和 EndpointSlice 之间的关系

【Kubernetes知识点】 解读 Service 和 EndpointSlice 之间的关系

目录

  • [1 概念](#1 概念)
    • [1.1 Service的概念](#1.1 Service的概念)
    • [1.2 Endpoint 的概念](#1.2 Endpoint 的概念)
    • [1.3 EndpointSlice 的引入](#1.3 EndpointSlice 的引入)
      • [1.3.1 EndpointSlice支持的地址](#1.3.1 EndpointSlice支持的地址)
      • [1.3.2 EndpointSlice的状态](#1.3.2 EndpointSlice的状态)
      • [1.3.3 EndpointSlice的拓扑信息](#1.3.3 EndpointSlice的拓扑信息)
    • [1.4 Service 、Endpoint和 EndpointSlice 的关系](#1.4 Service 、Endpoint和 EndpointSlice 的关系)
    • [1.5 Endpoint 和 EndpointSlice 的对比](#1.5 Endpoint 和 EndpointSlice 的对比)
    • [1.6 无选择器 Service 的场景](#1.6 无选择器 Service 的场景)
    • [1.7 自定义EndpointSlice 要求](#1.7 自定义EndpointSlice 要求)
  • [2 实验设计:验证Service 和 EndpointSlice关联](#2 实验设计:验证Service 和 EndpointSlice关联)
    • [2.1 创建测试应用:](#2.1 创建测试应用:)
    • [2.2 观察Service和EndpointSlice](#2.2 观察Service和EndpointSlice)
    • [2.3 模拟 Pod 变化: 扩容和缩容Pod](#2.3 模拟 Pod 变化: 扩容和缩容Pod)
    • [2.4 无选择器 Service 实验:](#2.4 无选择器 Service 实验:)
  • [3 结论](#3 结论)
  • [4 参考文献](#4 参考文献)

❤️ 摘要:在 Kubernetes 中,Service 和 EndpointSlice 是实现负载均衡和服务发现的重要组件。 EndpointSlice让Service更好地处理大量后端,并允许集群有效地更新其健康后端列表。本文将深入探讨它们之间的关系,并设计实验来验证这一关系。


💯 本文关联好文:


1 概念

1.1 Service的概念

❔说明:想深入了解Service,请提前看前文《一文读懂Service以及实践攻略》

Kubernetes 中的 Service 是一种网络抽象层,旨在为一组 Pod 提供稳定的访问入口。通过 Service,用户可以不必关心 Pod 的变化,而是通过统一的 IP 地址和端口来访问这些 Pod。

1.2 Endpoint 的概念

Endpoints 是 Kubernetes 中用于跟踪服务网络端点的原始 API。每个 Service 都有一个对应的 Endpoints 对象,存储该服务的所有网络端点。然而,随着 Kubernetes 集群和服务的扩展,原有的 Endpoints API 逐渐暴露出其局限性,特别是在处理大量网络端点的时候。

Kubernetes 限制单个 Endpoints 对象中可以容纳的端点数量。当服务有超过 1000 个支持端点时,Kubernetes 会截断 Endpoints 对象中的数据, 并在 Endpoints 上设置注释: endpoints.kubernetes.io/over-capacity: truncated

1.3 EndpointSlice 的引入

❔ 说明: Kubernetes v1.21之后, EndpointSlice特性是stable

为了更有效地管理服务的端点,Kubernetes 引入了 EndpointSlice。与传统的 Endpoints 资源相比,EndpointSlice 提供了更好的扩展性,尤其是在处理大规模集群时。它将多个端点组织成切片,减少 API 调用次数,提高效率。

如果某个服务的端点数量达到阈值,那么 Kubernetes 将添加另一个空的 EndpointSlice 并在其中存储新的端点信息。默认情况下,一旦现有 EndpointSlice 全部包含至少 100 个端点,Kubernetes 就会创建一个新的 EndpointSlice。

1.3.1 EndpointSlice支持的地址

EndpointSlices 支持三种地址类型,设置addressType字段:

  • IPv4
  • IPv6
  • FQDN (Fully Qualified Domain Name)

❔ 说明: 每个 EndpointSlice 对象代表一个特定的IP地址类型。如果您有一项可通过 IPv4 和 IPv6 使用的服务,则至少有两个 EndpointSlice 对象。

1.3.2 EndpointSlice的状态

EndpointSlice API有三个状态条件, 说明以下:

条件 说明
ready 正在运行的Pod将Ready 条件设置为 True 时,同时将 EndpointSlice 条件也设置为 true。
serving serving 条件几乎与 ready 条件相同。不同之处在于,如果用户在 pod 终止时关心 pod是否还运行,则应检查 serving 条件。
Terminating Terminating 是指示端点是否正在终止的条件。对于 Pod,这是设置了删除时间戳的任何 Pod。

1.3.3 EndpointSlice的拓扑信息

EndpointSlice 中的每个端点都可以包含相关的拓扑信息。拓扑信息包括端点的位置以及对应的Node和Zone的信息。字段说明以下:

  • nodeName - 此端点所在节点的名称。
  • zone - 此端点所在的区域。

1.4 Service 、Endpoint和 EndpointSlice 的关系

打个比喻 :在一个大型活动中,K8s中的Service 作为活动入口的前台人员,他为所有来宾提供入口进入指示。每个来宾Endpoint在活动中有自己的身份标识,比如知道他们的座位号。

现在这个活动区,划分了多个小区域,EndpointSlice就像是一个拿着分区名单的组长,名单记录了一组来宾的身份信息和他们的座位分布。通过EndpointSlice,你可以更高效地管理和查找来宾的位置信息,尤其是在活动人数众多时。这种分片的方式让协调工作变得更加灵活和高效。

Kubernetes中,Service与EndpointSlice实现以下机制:

  1. 选择器机制:Service 使用标签选择器来确定哪些 Pod 作为其后端。EndpointSlice 则维护与这些 Pod 相关联的网络端点信息。
  2. 动态更新:当 Pod 的状态变化时,Service 控制器会自动更新 EndpointSlice,确保服务始终指向活跃的 Pod。
  3. 负载均衡:EndpointSlice 的分组机制使得负载均衡变得更加高效,能够快速响应 Pod 的变化。

1.5 Endpoint 和 EndpointSlice 的对比

作为新的替代方案,EndpointSlice与Endpoint有以下不同点:

资源对象 Endpoints EndpointSlice
数据结构 所有网络端点信息存储在一个单一的 Endpoints 对象中。随着后端 Pod 数量的增加,这些对象可能会变得非常庞大。 将网络端点组织为多个切片,使得每个切片只包含一部分端点信息,从而减小单个对象的大小。
性能 在更新过程中,Endpoints 的每次变更都会引发大量的流量,这在高频更新的场景下尤其明显。 EndpointSlices 的设计使得添加或删除单个 Pod 只需触发相同数量的更新,但更新消息的大小要小得多,从而降低了 CPU 使用率和网络流量。
新特性支持 N/A EndpointSlices 支持新的网络功能,如双栈网络和拓扑感知路由,使得 Kubernetes 在网络管理上更加灵活和高效。

1.6 无选择器 Service 的场景

在某些情况下,用户可能希望定义一个没有选择器的 Service。这种情况通常用于以下场景:

  • 外部数据库:在生产环境中使用外部数据库集群,而在测试环境中使用内部数据库。
  • 跨命名空间或集群访问:需要将 Service 指向不同命名空间或其他集群中的 Service。
  • 迁移工作负载:在评估迁移至 Kubernetes 的过程中,可能只在 Kubernetes 中运行部分后端。

在这些场景中,可以定义一个不带选择器的 Service。由于没有选择器,Kubernetes 不会自动创建对应的 EndpointSlice(和旧版的 Endpoints)对象。用户可以手动添加 EndpointSlice 对象,将 Service 映射到实际运行的网络地址和端口。

1.7 自定义EndpointSlice 要求

对于用户手动创建的 EndpointSlice,建议选择合适的标签值,例如 endpointslice.kubernetes.io/managed-by。对于直接使用 kubectl 管理 EndpointSlices 的用户,建议使用描述此手动管理的名称,例如 "staff" 或 "cluster-admins",应避免使用保留值 "controller",因为它表示由 Kubernetes 自身控制平面管理的 EndpointSlices。

⚠️ 注意: Kubernetes API 服务器不允许代理未映射到 Pods 的端点。由于这一限制,诸如 kubectl port-forward service/<service-name> 的操作在 Service 没有选择器时会失败。

2 实验设计:验证Service 和 EndpointSlice关联

为验证 Service 和 EndpointSlice 之间的关系,我们可以进行以下实验:

2.1 创建测试应用:

沿用《一文读懂Service以及实践攻略》案例,创建一个简单的 Web 应用,定义一个 Deployment 和对应的 Service。

Deployment 示例

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
# 定义Deployment的名字
  name: nginx-deployment
  labels:
    app: nginx
spec:
  # 定义副本数
  replicas: 1
  # 选择器指定label与pod模板的label匹配
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
    # 与选择器指定label匹配
      labels:
        app: nginx
    spec:
      containers:
      # pod名字,可自定义
      - name: nginx
      # 镜像源, 这里设置私有镜像源
        image: harbor.zx/hcie/nginx:1.26.1
      # pod暴露端口号
        ports:
        - containerPort: 80
          name: http
          protocol: TCP

Service 示例

yaml 复制代码
---
apiVersion: v1
kind: Service
metadata:
  name: my-clusterip-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

部署Service和Deployment

bash 复制代码
kubectl apply -f nginx-deployment.yaml
kubectl apply -f clusterip-service.yaml

2.2 观察Service和EndpointSlice

查看service详细信息

bash 复制代码
kubectl describe svc my-clusterip-service

输出如下:

bash 复制代码
Name:              my-clusterip-service
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.245.81.75
IPs:               10.245.81.75
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         172.16.194.102:80
Session Affinity:  None
Events:            <none>

查看endpointslice

bash 复制代码
kubectl describe endpointslices.discovery.k8s.io my-clusterip-service-xvl7k

输出如下:

bash 复制代码
Name:         my-clusterip-service-xvl7k
Namespace:    default
Labels:       endpointslice.kubernetes.io/managed-by=endpointslice-controller.k8s.io
# 通过label,自动关联my-clusterip-service
              kubernetes.io/service-name=my-clusterip-service
Annotations:  endpoints.kubernetes.io/last-change-trigger-time: 2024-09-28T09:43:42Z
AddressType:  IPv4
Ports:
  Name     Port  Protocol
  ----     ----  --------
  <unset>  80    TCP
# 自动关联Endpoint,对应pod
Endpoints:
  - Addresses:  172.16.194.102
  # pod状态是Ready时, EndpointSlice状态自动设置为Ready
    Conditions:
      Ready:    true
    Hostname:   <unset>
    # 关联某个Deployment下pod
    TargetRef:  Pod/nginx-deployment-64db67d8bc-zblx6
    # 描述pod在当前的节点
    NodeName:   k8s-worker1
    # 描述pod在当前的域
    Zone:       <unset>
Events:         <none>

❔ 说明:

  • 通过创建上述 Deployment 和 Service,Kubernetes 会自动生成 EndpointSlice。

2.3 模拟 Pod 变化: 扩容和缩容Pod

扩容Deployment的副本数到3,观察EndpointSlice的变化:

bash 复制代码
kubectl scale deployment/nginx-deployment --replicas=3

观察Endpointslice,执行以下命令

bash 复制代码
kubectl describe endpointslices.discovery.k8s.io my-clusterip-service-xvl7k

输出如下:

bash 复制代码
erip-service-xvl7k
Name:         my-clusterip-service-xvl7k
Namespace:    default
Labels:       endpointslice.kubernetes.io/managed-by=endpointslice-controller.k8s.io
              kubernetes.io/service-name=my-clusterip-service
Annotations:  endpoints.kubernetes.io/last-change-trigger-time: 2024-09-28T09:57:26Z
AddressType:  IPv4
Ports:
  Name     Port  Protocol
  ----     ----  --------
  <unset>  80    TCP
# 新增两个Endpoint,并分配到不同的节点
Endpoints:
  - Addresses:  172.16.194.102
    Conditions:
      Ready:    true
    Hostname:   <unset>
    TargetRef:  Pod/nginx-deployment-64db67d8bc-zblx6
    NodeName:   k8s-worker1
    Zone:       <unset>
  - Addresses:  172.16.135.200
    Conditions:
      Ready:    true
    Hostname:   <unset>
    TargetRef:  Pod/nginx-deployment-64db67d8bc-qbmvd
    NodeName:   k8s-master3
    Zone:       <unset>
  - Addresses:  172.16.126.43
    Conditions:
      Ready:    true
    Hostname:   <unset>
    TargetRef:  Pod/nginx-deployment-64db67d8bc-p7xqj
    NodeName:   k8s-worker2
    Zone:       <unset>
Events:         <none>

手动删除一个 Pod,并观察 EndpointSlice 的变化:

bash 复制代码
kubectl delete pod nginx-deployment-64db67d8bc-zblx6 

观察Endpointslice,执行以下命令

bash 复制代码
kubectl describe endpointslices.discovery.k8s.io my-clusterip-service-xvl7k

输出如下:

bash 复制代码
# Endpoint列表会剔除被删除的pod
Endpoints:
  - Addresses:  172.16.135.200
    Conditions:
      Ready:    true
    Hostname:   <unset>
    TargetRef:  Pod/nginx-deployment-64db67d8bc-qbmvd
    NodeName:   k8s-master3
    Zone:       <unset>
  - Addresses:  172.16.126.43
    Conditions:
      Ready:    true
    Hostname:   <unset>
    TargetRef:  Pod/nginx-deployment-64db67d8bc-p7xqj
    NodeName:   k8s-worker2
    Zone:       <unset>
Events:         <none>
---
Endpoints:
  - Addresses:  172.16.135.200
    Conditions:
      Ready:    true
    Hostname:   <unset>
    TargetRef:  Pod/nginx-deployment-64db67d8bc-qbmvd
    NodeName:   k8s-master3
    Zone:       <unset>
  - Addresses:  172.16.126.43
    Conditions:
      Ready:    true
    Hostname:   <unset>
    TargetRef:  Pod/nginx-deployment-64db67d8bc-p7xqj
    NodeName:   k8s-worker2
    Zone:       <unset>
  - Addresses:  172.16.194.101
    Conditions:
      Ready:    false                                   -> Ready状态从false转为true 
    Hostname:   <unset>
    TargetRef:  Pod/nginx-deployment-64db67d8bc-v86vr   -> 添加新的pod 
    NodeName:   k8s-worker1
    Zone:       <unset>
Events:         <none>

❔步骤说明:

  1. EndpointSlice监听到Pod被删除的事件;
  2. 更新Endpoint列表,剔除被删除的Pod;
  3. EndpointSlice监听到新的Pod被创建;
  4. 更新Endpoint列表,新增新创建的Pod;
  5. 监听Pod的状态,如果Pod状态转为Ready, 则设置Endpoint的状态为Ready。

❔ 总结:

  1. 动态更新:当 Pod 的状态变化时,Service 控制器会自动更新 EndpointSlice,确保服务始终指向活跃的 Pod。
  2. 负载均衡:EndpointSlice 的分组机制使得负载均衡变得更加高效,能够快速响应 Pod 的变化。

2.4 无选择器 Service 实验:

如果是Service需要代理外部的应用,或者应用的部署在Service之后的, 可能会采用无选择器的Service这种方式部署Service资源。

创建一个不带选择器的 Service:

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  ports:
    - port: 8080
      targetPort: 8080

然后手动创建 EndpointSlice:

yaml 复制代码
apiVersion: discovery.k8s.io/v1
addressType: IPv4
endpoints:
# 外部应用的IP地址
  - addresses:
      - 192.168.1.100
    conditions:
      ready: true
kind: EndpointSlice
metadata:
  labels:
    endpointslice.kubernetes.io/managed-by: endpointslice-controller.k8s.io
    # 关联没有选择器的service
    kubernetes.io/service-name: external-service
  name: external-service-endpoints
  namespace: default
# 指定映射的端口
ports:
- name: ""
  port: 8080
  protocol: TCP

创建service和endpointslice

bash 复制代码
kubectl apply -f external-service.yaml
kubectl apply -f external-service-endpoints.yaml

观察service状态

bash 复制代码
[root@k8s-master1 hcie]# kubectl describe svc external-service
Name:              external-service
Namespace:         default
Labels:            <none>
Annotations:       <none>
# 确实没有selector
Selector:          <none>
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.245.23.244
IPs:               10.245.23.244
Port:              <unset>  8080/TCP
TargetPort:        8080/TCP
# 没有Endpoint
Endpoints:         <none>
Session Affinity:  None
Events:            <none>

观察Endpointslice状态

bash 复制代码
[root@k8s-master1 hcie]# kubectl describe endpointslices.discovery.k8s.io external-service-endpoints
Name:         external-service-endpoints
Namespace:    default
Labels:       endpointslice.kubernetes.io/managed-by=endpointslice-controller.k8s.io
              kubernetes.io/service-name=external-service
Annotations:  <none>
AddressType:  IPv4
Ports:
  Name     Port  Protocol
  ----     ----  --------
  <unset>  8080  TCP
Endpoints:
  - Addresses:  192.168.1.100
    Conditions:
      Ready:   true
    Hostname:  <unset>
    NodeName:  <unset>
    Zone:      <unset>
Events:        <none>

成功创建并关联。

3 结论

通过以上实验,我们可以验证 Service 和 EndpointSlice 之间的密切关系。EndpointSlices 的引入解决了原有 Endpoints 的性能瓶颈,使 Kubernetes 在网络管理上更加高效和灵活。在实验中,验证了Service 通过标签选择器关联 Pod,而 EndpointSlice 则负责维护这些 Pod 的网络信息。无选择器的 Service 也能够与外部后端进行整合,提供更大的灵活性。希望本文可以帮助你更深入了解它们间的关系。

4 参考文献

[1]Kubernetes 官方文档-service

[2]EndpointSlices

相关推荐
大筒木老辈子17 分钟前
Linux笔记---进程:进程切换与O(1)调度算法
linux·服务器·笔记
小七de尾巴27 分钟前
Linux下X11协议理解
linux·运维·计算机外设
大风吹PP凉1 小时前
45系统调用与内核API
java·linux·服务器
ZHOU_WUYI1 小时前
windows 中docker desktop 安装
运维·docker·容器
gma9991 小时前
【shell编程】函数、正则表达式、文本处理工具
linux·c++·正则表达式·bash
liuyunluoxiao1 小时前
Linux基本指令【Linux系统】
linux
Python私教1 小时前
Python 使用 Token 认证方案连接 Kubernetes (k8s) 的详细过程
开发语言·python·kubernetes
我是唐青枫2 小时前
Linux ss 命令详解
linux·运维·服务器
legend_jz2 小时前
【Linux】线程的互斥和同步
linux·运维·服务器·开发语言·笔记·学习·学习方法
桃园码工2 小时前
2-测试bigcache做进程内缓存 --开源项目obtain_data测试
vscode·mysql·go·postman