26. Service——深入学习
本章讲解知识点
- Service 会话保持机制
- Service 的多端口设置
- Service 支持的网络协议
- Kubernetes 的服务发现机制
- Headless Service
- Endpoint Slices
<br>
这一节我们来讲讲 Service 更多细节
1. Service 会话保持机制
Service 支持通过设置 sessionAffinity 实现基于客户端 IP 的会话保持机制,即首次将某个客户端来源 IP 发起的请求转发到后端的某个 Pod 上,之后从相同的客户端 IP 发起的请求都将被转发到相同的后端 Pod 上。配置参数为 service.spec.sessionAffinity。在 Kubernetes 中,Service 默认使用的是 sessionAffinity 策略是 None,即不做会话保持,将请求随机分配给后端的 Pod。相反可以配置为 ClientIP 策略,例如:
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: my-first-deploy sessionAffinity: ClientIP ports: - name: http protocol: TCP port: 8080 targetPort: 8080
同时,用户可用设置会话保持的最长时间,在此时间之后重置客户端来源 IP 的保持规则,配置参数为 service.spec.sessionAffinityConfig.clientIP.timeoutSeconds。
例如下面设置会话保持时间为5分钟:
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: my-first-deploy sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 300 ports: - name: http protocol: TCP port: 8080 targetPort: 8080
<br>
2. Service 的多端口设置
一个容器应用可以提供多个端口的服务,在 Service 的定义中也可以相应地设置多个端口号。
如下:
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: my-app ports: - name: http port: 80 targetPort: 8080 - name: https port: 443 targetPort: 8443
在上面的例子中,Service 定义了两个端口,分别对应的是 HTTP 和 HTTPS 协议。其中,name 字段指定了端口的名称,port 字段指定了 Service 对外提供的端口号,targetPort 字段指定了后端 Pod 真实使用的端口号。
在使用多端口的 Service 时,需要注意端口的选择和定义,以确保后端 Pod 能够正常处理来自 Service 不同端口的请求。
<br>
3. Service 支持的网络协议
TCP、UDP、HTTP、HTTPS、PROXY、SCTP
<br>
4. Kubernetes 的服务发现机制
服务发现机制指客户端应用在一个 Kubernetes 集群中如何获取后端服务的访问地址。Kubernetes 提供了两种机制供客户端应用以固定的方式获取后端服务的访问地址:环境变量方式和 DNS 方式。
4.1 环境变量方式
当创建一个 Service 对象时,Kubernetes 会自动在集群中的所有 Pod 中注入相应的环境变量。其中,环境变量名的格式为 $(SERVICE_NAME)_SERVICE_HOST
和 $(SERVICE_NAME)_SERVICE_PORT
,其中 SERVICE_NAME 是 Service 的名称,这两个环境变量可以用于访问 Service 对应的 Pod。其中,SERVICE_NAME 的命名规则为:将Service 的 name 字符串转换为全大写字母,将中横线 -
替换为下划线 _
。
如果 Service 对象有多个端口,那么端口号会追加在环境变量名后面,如 $(SERVICE_NAME)_SERVICE_PORT_<PORT>_TCP
。
举个例子,假设有一个名为 my-service 的 Service 对象,它有两个端口:80 和 8080。那么,在 Pod 中就会注入以下环境变量,我们可以进入 Pod 中通过命令 printenv 来查看:
[root@master mtuser]# kubectl get pod NAME READY STATUS RESTARTS AGE my-first-deploy-785c6c79d9-t5qgw 1/1 Running 0 3h38m my-first-deploy-785c6c79d9-zw8zl 1/1 Running 0 3h38m [root@master mtuser]# [root@master mtuser]# kubectl exec -it my-first-deploy-785c6c79d9-t5qgw -- bash root@my-first-deploy-785c6c79d9-t5qgw:/usr/local/tomcat# printenv ... MY_FIRST_DEPLOY_PORT_8080_TCP_ADDR=10.97.139.74 MY_FIRST_DEPLOY_PORT=tcp://10.97.139.74:8080 MY_FIRST_DEPLOY_SERVICE_HOST=10.97.139.74 MY_FIRST_DEPLOY_PORT_8080_TCP=tcp://10.97.139.74:8080 MY_FIRST_DEPLOY_SERVICE_PORT=8080 MY_FIRST_DEPLOY_PORT_8080_TCP_PROTO=tcp MY_FIRST_DEPLOY_PORT_8080_TCP_PORT=8080 ...
可以在 Pod 中使用这些环境变量来访问 Service 对应的 Pod。比如,在 Python 应用程序中,可以使用以下代码来获取 Service 对应的地址和端口:
import os service_host = os.environ.get('MY_SERVICE_SERVICE_HOST') service_port = os.environ.get('MY_SERVICE_SERVICE_PORT') url = f"http://{service_host}:{service_port}"
4.2 DNS 方式
在 Kubernetes 集群中,Service 对象会自动注册到集群的内置 DNS 服务器中。每个 Service 对象会有一个 DNS 名称,格式为 $(SERVICE_NAME).$(NAMESPACE).svc.cluster.local
,其中 SERVICE_NAME 是 Service 的名称,NAMESPACE 是 Service 所在的命名空间。通过这个 DNS 名称,可以直接访问 Service 对应的 Pod。
举个例子,假设有一个名为 my-service 的 Service 对象,它所在的命名空间为 my-namespace。那么,可以通过以下方式来访问 Service 对应的 Pod:
http://my-service.my-namespace.svc.cluster.local
对于客户端来说,DNS 域名格式的 Service 名称提供的是稳定、不变的访问地址,可以大大简化客户端应用的设置,是 Kubernetes 集群中推荐的使用方式。Service 的域名解析是供 Kubernetes 集群内部应用之间进行访问的。
<br>
5. Headless Service
5.1 基本概念
Headless Service 是 Kubernetes Service 的一种类型,它与标准 Service 不同,它不会创建 ClusterIP,而是直接将请求转发给 Service 关联的所有 Pod。通常情况下,Service 会将请求负载均衡到一组 Pod 上,但是 Headless Service 会将请求发送到所有 Pod,不进行负载均衡。Headless Service 通常用于 StatefulSet,以便每个 Pod 都有一个唯一的稳定的 DNS 名称。
因此,对于某些应用场景中,客户端应用不需要 Service 内置的负载均衡能力,而是想自己实现负载均衡功能,或者自己实现服务发现机制,就可以使用 Headless Service。
所以 Headless Service 没有 ClusterIP,kube-proxy 也不会为它创建负载转发规则。
5.2 小实验
我们做个小实验演示一下 Headless Service 如何将请求发送到后端 Pod:
我们给出一个 Headless Service 定义文件:
apiVersion: v1 kind: Service metadata: name: my-first-deploy namespace: default spec: clusterIP: None ports: - port: 8080 protocol: TCP targetPort: 8080 selector: app: my-first-deploy
注意这里我们要设置 Label Selector,这样才能关联到后端 Pod。
创建该应用后,我们查看一下 Headless Service:
[root@master mtuser]# kubectl create -f my-first-svc.yaml service/my-first-deploy created [root@master mtuser]# [root@master mtuser]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-first-deploy ClusterIP None <none> 8080/TCP 9s [root@master mtuser]# [root@master mtuser]# kubectl describe svc my-first-deploy Name: my-first-deploy Namespace: defaul
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
本专刊适合于立志转行云计算的小白,有一定的编程、操作系统、计算机网络、数据结构、算法基础。 本专刊同时也适合于面向云计算(Docker + Kubernetes)求职的从业者。 本专刊囊括了云计算、VMWare、Docker、Kubernetes、Containerd等一系列知识点的讲解,并且最后总