大家好,欢迎来到IT知识分享网。
1 概述
在Kubernetes(K8s)中,Endpoint是一个关键的核心对象,它承担着连接Service和后端Pod的重要角色。Endpoint提供了对服务后端的抽象,允许用户在集群中动态地管理服务的网络终端。本文将深入研究K8s中Endpoint的概念、作用以及使用方法,并通过详细的示例来帮助读者更好地理解。
1.1 什么是Kubernetes Endpoint?
Endpoint代表了Service后端的一组IP地址和端口号,用于将流量从Service引导到实际运行应用程序的Pod。每个Service都关联着一个对应的Endpoint,这个Endpoint动态地维护了所有Service所选择的Pod的网络终端信息。
简而言之,Endpoint是Service的一种实现,是Service背后真实运行的Pod的地址和端口的集合。通过Endpoint,K8s可以实现服务的动态发现和负载均衡。
+----------+ / +----> Pod1 | +--------+ / / +----------+ | Client +-----+------+ Pod2 | +--------+ \ \ +----------+ \ +----> Pod3 | +----------+
1.2 Endpoint的结构
Endpoint主要由以下几个部分组成:
- IP地址: 指定Pod的IP地址,用于标识网络上的唯一位置。
- 端口号: 指定Pod中运行应用程序的端口,用于标识应用程序的通信端口。
一个Endpoint可以包含多个IP地址和端口号的组合,这取决于与Service相关联的Pod的数量。Endpoint的结构使得它能够适应不同Service的需求,实现对多个Pod的动态管理。
1.3 Endpoint与Service的关系
在K8s中,每个Service都有一个相应的Endpoint。当Service被创建时,K8s会自动创建对应的Endpoint,并将Service选择的Pod的IP地址和端口号添加到Endpoint中。这种关系保证了Service与Pod之间的正确通信。
在Service和Endpoint之间的关系中,Service充当了一种抽象,为应用程序提供了一个稳定的入口点,而Endpoint则提供了Service后端的真实网络终端。这种分离使得用户能够更加灵活地管理和维护后端Pod的变化,而不需要改变Service的定义。
+----------+ +--------+ | Client +-----> | Service | +----------+ +--------+ | v +-----------+ | Endpoint | +-----------+
1.4 Endpoint的使用
为了更好地理解Endpoint的使用,让我们通过一个具体的示例来演示。
假设我们有一个简单的Web应用,由多个前端(frontend)和后端(backend)Pod组成。前端提供Web页面,后端处理业务逻辑。我们已经创建了一个名为web-service
的Service,现在让我们看看与之关联的Endpoint。
首先,我们查看web-service
的定义:
apiVersion: v1 kind: Service metadata: name: web-service spec: selector: app: frontend ports: - protocol: TCP port: 80 targetPort: 8080
这个Service选择了标签为app=frontend
的所有Pod,并将流量引导到它们的80端口。现在,我们来查看与之关联的Endpoint:
kubectl get endpoints web-service
上述命令的输出可能如下所示:
NAME ENDPOINTS AGE web-service 192.168.1.2:8080,192.168.1.3:8080,192.168.1.4:8080 1h
在这个示例中,web-service
的Endpoint列举了所有与该Service相关联的Pod的IP地址和端口号。这样,K8s就能够动态地将流量引导到这些具体的Pod,实现负载均衡和服务发现。
1.5 动态管理Endpoint
在K8s中,Endpoint的管理是动态的。当Service的相关Pod发生变化时,Endpoint会相应地更新。例如,当我们扩展了前端Pod的数量时,Endpoint会自动添加新的IP地址和端口号。
让我们通过一个扩展Pod数量的例子来演示:
kubectl scale deployment frontend --replicas=5
然后,我们再次查看web-service
的Endpoint:
shell kubectl get endpoints web-service
输出如下所示:
NAME ENDPOINTS AGE web-service 192.168.1.2:8080,192.168.1.3:8080,192.168.1.4:8080,192.168.1.5:8080,192.168.1.6:8080 5m
在这个例子中,我们扩展了前端Pod的数量,Endpoint相应地添加了新的IP地址和端口号,确保了与Service相关联的所有Pod都能够被正确地服务。
2 Endpoint增删改查
2.1 创建Endpoint
apiVersion: v1 kind: Endpoints metadata: name: my-endpoint subsets: - addresses: - ip: 192.168.1.1 - ip: 192.168.1.2 ports: - name: port1 port: 80 protocol: TCP - addresses: - ip: 192.168.1.3 ports: - name: port2 port: 8080 protocol: TCP
在 Kubernetes 中,Endpoint 的定义会随着 Service 的创建自动生成。例如,创建一个 Service,如下所示:
apiVersion: v1 kind: Service metadata: name: backend-service spec: selector: app: my-app ports: - name: http port: 80 targetPort: http
该 Service 定义了一个名叫 backend-service 的虚拟服务,它包含了一个名叫 http 的端口,映射到后端的 http 服务端口。
Kubernetes 会自动为该 Service 创建一个 Endpoint,并将其关联起来。如果需要手动修改 Endpoint,可以使用以下命令:
kubectl edit endpoints backend-service
2.2 Endpoint 更新
在 Kubernetes 中,当 Endpoint 中的某些 Pod 不可用时,Kubernetes 会自动地从 Endpoint 中删除这些 Pod,并将 Endpoint 更新为不可用状态。新的 Endpoint 会在缺失 Pod 的同一端口上生成一个新的地址,并将服务转发到可用的 Pod。
为了避免 Endpoint 的数据丢失,Kubernetes 具有自动和手动两种更新 Endpoint 的方式。
2.2.1 自动更新 Endpoint
当 Pod 恢复正常时,Kubernetes 会自动更新 Endpoint 并将该 Pod 重新添加到 Endpoint 中,从而使该 Service 再次可用。这种自动更新是 Kubernetes Endpoint 更改监控机制的一部分。
2.2.2 手动更新 Endpoint。
在某些情况下,特别是在进行操作系统多次启动后,Kubernetes 可能无法监视 Endpoint 中的所有更改。此时,可以手动更新 Endpoint。
我们可以使用以下命令手动更新 Endpoint:
kubectl get endpoints my-endpoint -n my-namespace -o yaml | kubectl apply -f -
在执行上述命令之后,Kubernetes 将自动更新 Endpoint 并重新加载流量。
2.3 Endpoint 的删除
Endpoint 可以通过以下命令进行删除:
kubectl delete endpoints my-endpoint -n my-namespace
执行上述命令后,Endpoint 会被删除,但 Service 仍然存在。如果需要同时删除 Service,请执行以下命令:
kubectl delete service backend-service -n my-namespace
3 Endpoint controlor
endpoint controlor是k8s集群的其中一个组件,主要是维护endpoint,保证endpoint内ip:port 能够提供正常服务,其功能如下:
- endpoint controller 建立 service 与 pod 的list-watch
- 轮询service队列,查询属于对应该service的pods
- 判断pods状态以及port情况,生成endpoint对象
- 过滤掉状态为not ready 的pods
- 过滤掉不满足service.spec.targetPort 的pods
- 获取pods 的ip 以及service.spec.ports ,生成endpoint对象
- 比较该endpoint对象与当前endpoint ,若当前endpoint不存在,则发送给apiserver创建请求,若与当前endpoint不一致,则发送给apiserver更新请求
4 Endpoint参数解释
apiVersion: v1 kind: Endpoint metadata: # 对象元数据 name: namespace: subsets: # 端点对象的列表 - addresses: # 处于“就绪”状态的端点地址对象列表 - hostname <string> # 端点主机名 ip <string> # 端点的IP地址,必选字段 nodeName <string> # 节点主机名 targetRef: # 提供了该端点的对象引用 apiVersion <string> # 被引用对象所属的API群组及版本 kind <string> # 被引用对象的资源类型,多为Pod name <string> # 对象名称 namespace <string> # 对象所属的名称究竟 fieldPath <string> # 被引用的对象的字段,在未引用整个对象时使用,常用于仅引用 # 指定Pod对象中的单容器,例如spec.containers[1] uid <string> # 对象的标识符; notReadyAddresses: # 处于“未就绪”状态的端点地址对象列表,格式与address相同 ports: # 端口对象列表 - name <string> # 端口名称; port <integer> # 端口号,必选字段; protocol <string> # 协议类型,仅支持UDP、TCP和SCTP,默认为TCP; appProtocol <string> # 应用层协议;
- endpoint.metadata.name : 代表着service name
- endpoint.subsets[].addresses[].ip 代表 状态为ready pod 的ip
- endpoint.subsets[].targetRef: 代表来自该ip的pod详情
- endpoint. subsets[].ports[]: 数据来源于service.spec.ports,当pods内的port 并不满足targetPort ,则会在endpoint.subsets[].addresses[]中剔除该pod ip
- endpoint. subsets[].notReadyAddresses:未就绪pod列表
5 Endpoint实战
5.1 利用readiness测试endpoint
目的:
- 测试是否创建service就会自动创建endpoint资源
- 利用readiness(就绪探针)模拟后端pod宕机,查看endpoint资源是否会将宕机的pod下线
5.1.1 编写services-readiness.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: demoapp namespace: dev spec: replicas: 3 selector: matchLabels: app: demoapp-with-readiness template: metadata: creationTimestamp: null labels: app: demoapp-with-readiness spec: containers: - image: ikubernetes/demoapp:v1.0 name: demoapp imagePullPolicy: IfNotPresent readinessProbe: httpGet: path: '/readyz' port: 80 initialDelaySeconds: 15 periodSeconds: 10 --- apiVersion: v1 kind: Service metadata: name: services-readiness-demo namespace: dev spec: selector: app: demoapp-with-readiness ports: - name: http protocol: TCP port: 80 targetPort: 80
5.1.2 查看部署状态
[root@master01 yaml]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE demoapp-677db795b4-9zf5t 1/1 Running 0 63s demoapp-677db795b4-wdf7g 1/1 Running 0 63s demoapp-677db795b4-wn76j 1/1 Running 0 63s [root@master01 yaml]# kubectl get svc -n dev NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE services-readiness-demo ClusterIP 10.109.208.211 <none> 80/TCP 66s #这里看到确实有一个endpoint的资源而且和svc重名,因为endpoint资源和svc资源就是以名字来进行关联的 [root@master01 yaml]# kubectl get endpoints -n dev NAME ENDPOINTS AGE services-readiness-demo 10.244.1.15:80,10.244.2.23:80,10.244.2.24:80 68s #可以看到以下A [root@master01 yaml]# kubectl describe endpoints services-readiness-demo -n dev Name: services-readiness-demo Namespace: dev Labels: <none> Annotations: endpoints.kubernetes.io/last-change-trigger-time: 2022-06-17T07:02:49Z Subsets: Addresses: 10.244.1.15,10.244.2.23,10.244.2.24 NotReadyAddresses: <none> Ports: Name Port Protocol ---- ---- -------- http 80 TCP Events: <none>
5.1.3 访问测试
正常是可以访问200的,并且现在endpoint资源里后端pod还是三个
[root@master01 yaml]# curl 10.109.208.211:80/readyz
OK
[root@master01 yaml]# curl -I 10.109.208.211:80/readyz
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 2
Server: Werkzeug/1.0.0 Python/3.8.2
Date: Fri, 17 Jun 2022 07:25:57 GMT
修改某一个pod的readyz参数,就会导致访问出现5xx,之后readiness探针就会检测到pod宕机,endpoint就会下线宕机的pod
curl -X POST -d "readyz=fail" 10.244.2.23/readyz
[root@master01 yaml]# curl 10.244.2.23/readyz
fail
[root@master01 yaml]# curl -I 10.244.2.23/readyz
HTTP/1.0 507 INSUFFICIENT STORAGE
Content-Type: text/html; charset=utf-8
Content-Length: 4
Server: Werkzeug/1.0.0 Python/3.8.2
Date: Fri, 17 Jun 2022 07:32:23 GMT
查看endpoint详细信息,会看到NotReadAddresses字段中已经有刚刚宕机pod了
[root@master01 yaml]# kubectl describe endpoints services-readiness-demo -n dev
Name: services-readiness-demo
Namespace: dev
Labels: <none>
Annotations: endpoints.kubernetes.io/last-change-trigger-time: 2022-06-17T07:32:28Z
Subsets:
Addresses: 10.244.1.15,10.244.2.24
NotReadyAddresses: 10.244.2.23
Ports:
Name Port Protocol
---- ---- --------
http 80 TCP
Events: <none>
可以看到READY字段中有一个pod的状态已经是0了
[root@master01 yaml]# kubectl get pod -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
demoapp-677db795b4-9zf5t 1/1 Running 0 32m 10.244.2.24 node02 <none> <none>
demoapp-677db795b4-wdf7g 1/1 Running 0 32m 10.244.1.15 node01 <none> <none>
demoapp-677db795b4-wn76j 0/1 Running 0 32m 10.244.2.23 node02 <none> <none>
5.2 利用endpoint代理外部mysql(externalName的示例)
5.2.1 编写mysql-endpoints-demo.yaml
这里Endpoints和Service不需要通过labels来进行关联,只需要通过metadata.name字段关联即可(保持一致)
$ vim mysql-endpoints-demo.yaml apiVersion: v1 kind: Endpoints metadata: name: mysql-external namespace: default subsets: - addresses: - ip: 172.29.9.51 #这里的地址可以是外部mysql的读写分离器的IP这样就能保证数据一致性了 - ip: 172.29.9.52 ports: - name: mysql port: 3306 protocol: TCP --- apiVersion: v1 kind: Service metadata: name: mysql-external namespace: default spec: type: ClusterIP ports: - name: mysql port: 3306 targetPort: 3306 protocol: TCP
5.2.2 部署验证
部署之后,任何pod都可以通过service来访问数据库了。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/152290.html