第56节 service


❤️💕💕新时代拥抱云原生,云原生具有环境统一、按需付费、即开即用、稳定性强特点。Myblog:http://nsddd.topopen in new window


[TOC]

Service 对象

Service Selector

Kubernetes 允许将 Pod 对象通过标签(Label)进行标记,并通过 Service Selector 定义基于 Pod 标签的过滤规则,以便选择服务的上游应用实例

Service Selector 对象是 Kubernetes 中的一个资源对象,用于定义服务的选择器。选择器是一组用于选择后端 Pod 的标签。当一个 Service 对象被创建时,可以指定相关联的 Selector 对象。这个 Selector 可以是一个简单的标签选择器,也可以是一个更复杂的表达式,如 matchExpressions

Service Selector 对象的定义可以在创建 Service 对象时直接指定,也可以使用 kubectl label 命令进行设置。例如,可以使用以下命令创建一个 Service Selector 对象:

kubectl label pods <pod-name> app=my-app

这个命令会将 Pod 对象的标签设置为 app=my-app。然后,可以使用以下命令创建一个 Service 对象,并将其关联到这个 Pod:

kubectl expose pod <pod-name> --port=<port> --target-port=<target-port> --selector=app=my-app

在这个命令中,--selector 参数指定了一个标签选择器,用于选择与之关联的 Pod。在这个例子中,选择器是 app=my-app

要查看 Service Selector 对象的详细信息,可以使用以下命令:

kubectl describe service <service-name> --namespace=<namespace>

这个命令会显示与 Service 对象相关联的 Endpoint 和 Selector 对象。其中,Selector 对象列出了与 Service 相关联的 Pod 的标签选择器。

Ports

Ports 属性中定义了服务的端口、协议目标端口等信息

Service 对象是 Kubernetes 中的一个资源对象,用于定义一个服务。服务是一组 Pod 的抽象,这些 Pod 可以被其他容器或外部用户访问。Service 对象可以定义一个稳定的 DNS 名称和 IP 地址,以及一个负载均衡器,用于将请求分发给后端 Pod。

Service 对象中的 Ports 对象用于定义服务的端口信息。一个 Service 对象可以包含多个 Ports 对象,每个 Ports 对象定义了一个服务端口和其对应的目标端口。例如,下面的 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 对象定义了两个端口:httphttpshttp 端口映射到后端 Pod 的 8080 端口,https 端口映射到后端 Pod 的 8443 端口。

要创建一个 Service 对象,可以使用以下命令:

kubectl expose deployment <deployment-name> --type=ClusterIP --name=<service-name> --port=<port> --target-port=<target-port>

其中,<deployment-name> 为部署的名称,<service-name> 为服务的名称,<port> 为服务的端口,<target-port> 为后端 Pod 的端口。

要查看 ServicePorts 对象的详细信息,可以使用以下命令:

kubectl describe service <service-name> --namespace=<namespace>

这个命令会显示与 Service 对象相关联的 Ports 对象和 Endpoint 对象。其中,Ports 对象列出了服务的端口信息,Endpoint 对象列出了与服务相关联的后端 Pod 的网络地址和端口信息。

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  #如果设置了PublishNotReadyAdddress为 true,则无论Pod是否就绪都会被加入endpoint readyAddress list 中
  #publishNotReadyAddresses: true
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: nginx

Endpoint 对象

Endpoint 对象是 Kubernetes 中的一个资源对象,用于存储一个服务的网络地址和端口信息。这个对象可以通过 kubectl 命令行工具或 Kubernetes API 进行创建和管理。

Endpoint 对象可以与 Service 对象关联,表示服务的后端地址和端口信息。Endpoint 对象中的地址和端口信息可以手动配置,也可以通过 EndpointSlices 对象自动管理。

在创建 Service 对象时,Kubernetes 会自动创建相应的 Endpoint 对象,并将其与 Service 对象关联。如果需要手动配置 Endpoint 对象,可以使用以下命令:

kubectl create endpoint <endpoint-name> --namespace=<namespace> --addresses=<ip1>,<ip2>,... --ports=<port1>,<port2>,...

其中,<endpoint-name>Endpoint 对象的名称,<namespace> 为命名空间名称,<ip1>,<ip2>,... 为后端服务的 IP 地址,<port1>,<port2>,... 为后端服务的端口号。

要查看 Endpoint 对象的详细信息,可以使用以下命令:

kubectl describe endpoints <endpoint-name> --namespace=<namespace>

当 Service 的 selector 不为空时,Kubernetes Endpoint Controller 会侦听服务创建事件,创建与 Service 同名的 Endpoint 对象

selector 能够选取的所有 PodIP 都会被配置到 addresses 属性中

  • 如果此时 selector 所对应的 filter 查询不到对应的 Pod,则 addresses 列表为空
  • 默认配置下,如果此时对应的 Pod 为 not ready 状态,则对应的 PodIP 只会出现在 subsets 的notReadyAddresses 属性中,这意味着对应的 Pod 还没准备好提供服务,不能作为流量转发的目标。
  • 如果设置了 PublishNotReadyAdddress 为 true,则无论 Pod 是否就绪都会被加入 readyAddress list 中
apiVersion: v1
kind: Endpoints
metadata:
  name: service-without-selector
subsets:
  - addresses:
      - ip: 220.181.38.148
    ports:
      - name: http
        port: 80
        protocol: TCP

如果 service 对象过多的话, Endpoint 对象不好管理,社区提出了 EndpointSlice 对象。

EndpointSlice 对象

EndpointSlice 对象用于管理服务的端点。它们提供了一种比传统的 Endpoint 对象更可扩展和高效的管理端点信息的方式。在 Kubernetes 中,EndpointSlice 对象表示与服务关联的端点的子集。这个子集是由一组选择器定义的,这些选择器根据特定的标签或 IP 地址等标准过滤端点。这允许更细粒度地控制哪些端点包含在 EndpointSlice 中。

Endpoint slices 由 Kubernetes 自动创建和管理,因此无需手动创建它们。可以使用 kubectl 命令行工具或 Kubernetes API 查询 Endpoint slices,就像其他 Kubernetes 资源一样。Endpoint slices 被设计为比传统的 Endpoint 资源更可扩展,因为它们可以处理更多的端点而不影响性能。它们也更高效,因为它们只存储与服务相关的端点信息。

  • 当某个 Service 对应的 backend Pod 较多时,Endpoint 对象就会因保存的地址信息过多而变得异常庞大
  • Pod 状态的变更会引起 Endpoint 的变更,Endpoint 的变更会被推送至所有节点,从而导致持续占用大量网络带宽
  • EndpointSlice 对象,用于对 Pod 较多的 Endpoint 进行切片,切片大小可以自定义

不定义 selector 的 service

Service 可以定义 selector,也可以不定义 selector。这个命令会显示与 Service 对象相关联的 Ports 对象和 Endpoint 对象。在 headless 服务中,Endpoint 对象列出了与之关联的 Pod 的网络地址和端口信息,而不是 IP 地址。

apiVersion: v1
kind: Service
metadata:
  name: my-headless-service
spec:
  clusterIP: None
  ports:
    - name: http
      port: 80
      targetPort: 8080
    - name: https
      port: 443
      targetPort: 8443


在这个 Service 对象中,clusterIP 属性被设置为 None,表示这个服务没有任何 IP 地址。然后,可以使用这个服务的 DNS 名称来访问与之关联的 Pod。

用户创建了 Service 但不定义 Selector

  • Endpoint Controller 不会为该 Service 自动创建 Endpoint
  • 用户可以手动创建 Endpoint 对象,并设置任意 IP 地址到 Address 属性
  • 访问该服务的请求会被转发至目标地址

通过该类型服务,可以为集群外的一组 Endpoint 创建服务

Service Endpoint Pod 的关系

img

📜 对上面的解释:

可以看到 Endpoint 链接了 Service 和 Pod

ServiceEndpointPod 是 Kubernetes 中三个重要的概念。Service 定义了一个服务,可以将请求负载均衡到多个 Pod 上。Endpoint 定义了 Service 的后端 Pod 的地址和端口信息。Pod 是 Kubernetes 中最基本的部署单元,是一个或多个容器的集合。在 Kubernetes 中,ServiceEndpoint 对象通常是通过 Pod 对象来定义的。ServiceEndpoint 对象是通过 selector 属性与 Pod 对象关联的,selector 属性定义了一组标签,这些标签用于选择与 ServiceEndpoint 相关联的 Pod

一个 Service 对象可以与多个 Endpoint 对象关联,每个 Endpoint 对象定义了一个后端 Pod 的地址和端口信息。当一个 Service 对象收到请求时,它会将请求负载均衡到与之关联的 Endpoint 对象上。Endpoint 对象中的地址和端口信息可以手动配置,也可以由 Kubernetes 自动管理。

ServiceEndpointPod 之间的关系如下:

  • Service 对象定义了一个服务,包括服务的 IP 地址和端口信息。
  • Endpoint 对象定义了一个服务的后端 Pod 的地址和端口信息。
  • Pod 对象是 Kubernetes 中最基本的部署单元,是一个或多个容器的集合。
  • ServiceEndpoint 对象通常是通过 selector 属性与 Pod 对象关联的,selector 属性定义了一组标签,这些标签用于选择与 ServiceEndpoint 相关联的 Pod
  • 当一个 Service 对象收到请求时,它会将请求负载均衡到与之关联的 Endpoint 对象上。
  • Endpoint 对象中的地址和端口信息可以手动配置,也可以由 Kubernetes 自动管理。

Service 的类型

类型描述
ClusterIP在集群内部的 IP 地址上暴露服务。这个地址只能在集群内部访问。
NodePort在每个节点的 IP 地址上暴露服务。这个地址可以从集群外部访问。
LoadBalancer在外部负载均衡器的 IP 地址上暴露服务。这个地址可以从集群外部访问。
ExternalName通过 CNAME 记录暴露服务。这个地址可以从集群内部和外部访问。
  • clusterIP
    • Service 的默认类型, 服务被发布至仅集群内部可见的虚拟 IP 地址上。
    • 在 API Server 启动时,需要通过 service-cluster-ip-range 参数配置虚拟 IP 地址段,API Server 中有用于分配 IP 地址和端口的组件,当该组件捕获 Service 对象并创建事件时,会从配置的虚拟 IP 地址段中取一个有效的 IP 地址,分配给该 Service 对象。
  • nodePort
    • 在 API Server 启动时,需要通过 node-port-range 参数配置 nodePort 的范围, 同样的,API Server 组件会捕获 Service 对象并创建事件,即从配置好的 nodePort 范围取一个有效端口,分配给该 Service。
    • 每个节点的 kube-proxy 会尝试在服务分配的 nodePort 上建立侦听器接收请求,并转发给服务对应的后端 Pod 实例。
  • LoadBalancer
    • 企业数据中心一 般会采购一些负载均衡器,作为外网请求进入数据中心内部的统一流量入口。
    • 针对不同的基础架构云平台,Kubernertes Cloud Manager 提供支持不同供应商 API 的 Service Controller。如果需要在 Openstack 云平台上搭建 Kubernetes 集群,那么只需提供一份 openstack.rc, Openstack Service Controller 即可通过调用 LBaaS API 完成负载均衡配置。
  • Headless Service
    • Headless 服务是用户将 clusterIP 显示定义为 None 的服务。
    • 无头的服务意味着 Kubernetes 不会为该服务分配统一入口,包括 clusterIP, nodePort 等
    • ExternalName:为一个服务创建别名

ExternalName demo:

访问该 service 的情况会被转发到指定域名。

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: tencent.com

包含关系:

在 Kubernetes 中,ClusterIP 是一种服务类型,用于在集群内部的 IP 地址上暴露服务。这个地址只能在集群内部访问。NodePortLoadBalancer 是 Kubernetes 中的另外两种服务类型,它们都可以在集群外部访问服务。NodePort 在每个节点的 IP 地址上暴露服务,而 LoadBalancer 在外部负载均衡器的 IP 地址上暴露服务。

因此,ClusterIPNodePortLoadBalancer 的子集。也就是说,如果你创建了一个 ClusterIP 服务,那么你可以通过 NodePortLoadBalancer 访问这个服务。但是,如果你创建了一个 NodePortLoadBalancer 服务,那么你不能通过 ClusterIP 访问这个服务,因为 ClusterIP 只在集群内部暴露服务。

Service Topology

Service Topology 是 Kubernetes 中的一个资源对象,用于定义服务的拓扑结构。拓扑结构是一组用于选择后端 Pod 的拓扑域。当一个 Service 对象被创建时,可以指定相关联的 Service Topology 对象。这个 Service Topology 可以是一个简单的标签选择器,也可以是一个更复杂的表达式,如 matchExpressionsService Topology 对象定义了服务的拓扑结构,可以实现更高效的负载均衡和故障转移。要使用 Service Topology,需要将 Kubernetes 版本升级到 1.16 或更高版本。

要创建一个 Service Topology 对象,可以使用以下命令:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app
  topologyKeys:
    - "kubernetes.io/hostname"
  ports:
    - name: http
      port: 80
      targetPort: 8080

在这个 Service 对象中,topologyKeys 属性被设置为 kubernetes.io/hostname,表示使用 hostname 作为拓扑域。然后,在 Endpoint 对象中,每个 Podhostname 属性会被用作拓扑域。

要查看 Service Topology 对象的详细信息,可以使用以下命令:

kubectl describe service <service-name> --namespace=<namespace>

这个命令会显示与 Service 对象相关联的 Service Topology 对象和 Endpoint 对象。其中,Service Topology 对象列出了服务的拓扑信息。

细节部分:

  • 一个网络调用的延迟受客户端和服务器所处位置的影响,两者是否在同一节点、同一机架、同一可用区、同一数据中心,都会影响参与数据传输的设备数量
  • 在分布式系统中,为保证系统的高可用,往往需要控制应用的错误域(Failure Domain),比如通过反亲和性配置,将一个应用的多个副本部署在不同机架,甚至不同的数据中心
  • Kubernetes 提供通用标签来标记节点所处的物理位置,如:
    • topology.kubernetes.io/ zone: us-west2-a
    • failure-domain. beta.kubernetes.io/ region: us-west
    • failure-domain.tess.io/ network-device: us-west05-ra053
    • failure-domain.tess.io/rack: us_westO2_02-314_19_12
    • kubernetes.io/hostname: node-1
  • Service 引入了 topologyKeys 属性,可以通过如下设置来控制流量
    • topologyKeys 设置为["kubernetes.io/hostname"]时,调用服务的客户端所在节点上如 果有服务实例正在运行,则该实例处理请求,否则,调用失败。
    • topologyKeys设置为["kubernetes.io/hostname" , "topology.kubernetes.io/zone", "topology. kubernetes.io/region"]时,若同一节点有对应的服务实例,则请求会优先转发至该实例。否则,顺序查找当前 zone 及当前 region 是否有服务实例,并将请求按顺序转发。
    • topologyKeys 设置为["topology.kubernetes.io/ zone", "*"] 时,请求会被优先转发至当前 zone 的服务实例。如果当前 zone 不存在服务实例,则请求会被转发至任意服务实例。

该 Service 的访问只会转发到 client 所在 node 上的 Pod:

apiVersion: v1
kind: Service
metadata:
  name: nodelocal
spec:
  ports:
    - port: 80
      protocol: TCP
      name: http
  selector:
    app: nginx
  topologyKeys:
    - "kubernetes.io/hostname"

该 Service 的访问会按照优先级转发:

apiVersion: v1
kind: Service
metadata:
  name: prefer-nodelocal
spec:
  ports:
    - port: 80
      protocol: TCP
      name: http
  selector:
    app: nginx
  topologyKeys:
    - "kubernetes.io/hostname"
    - "topology.kubernetes.io/zone"
    - "topology.kubernetes.io/region"
    - "*"

END 链接