Service介绍-Service常用类型-Endpoints服务代理

简介

K8s 中的Service是一种抽象,用于定义一组Pod的逻辑集合,并为它们提供统一的网络入口。Service充当了Pod的负载平衡器和服务发现器,为应用程序提供了稳定的网络地址,使得应用程序可以访问与之关联的Pod而无需了解其具体的IP地址或端口。

Service特点和功能:

  • 稳定的网络地址:Service为一组Pod提供了一个虚拟IP地址(ClusterIP),这个地址是稳定的,不受后端Pod的变化影响。应用程序可以通过Service的虚拟IP地址来访问与之关联的Pod。

  • 负载平衡:Service可以将传入的请求分发到与之关联的多个Pod中,实现负载平衡,从而提高应用程序的可用性和性能。

  • 服务发现:Service充当了服务发现器的角色,使得其他应用程序或服务可以通过Service名称来发现和访问它所代表的后端Pod。

  • 多种类型:Kubernetes支持多种类型的Service,包括ClusterIP、NodePort、LoadBalancer和ExternalName等,每种类型适用于不同的场景和需求。

  • 选择器匹配:Service通过标签选择器(Selectors)来确定与之关联的Pod集合。只有具有特定标签的Pod才会被Service选中。

  • 会话关联:可选的会话关联(Session Affinity)功能可以确保将来自同一客户端的请求路由到相同的后端Pod,以维护会话状态。

总之,Service 是 Kubernetes 中一种非常重要的资源,它提供了一种抽象和统一的方式来公开应用程序,并实现负载均衡和服务发现,从而简化了微服务架构中的网络管理和通信。

创建 Service

例如,假定有一组 Pod,每个 Pod 都在侦听 TCP 端口 9376,并且它们还被打上 app.kubernetes.io/name=MyApp 标签。你可以定义一个 Service 来发布该 TCP 侦听器。

yaml 复制代码
apiVersion: v1
kind: Service     # 指定了资源的类型,这里是Service。
metadata:         # 指定了Service的元数据,包括标签和名称。
  labels:         # 指定了一组标签,这里有一个标签run: redis
    run: redis
  name: my-service                # 指定了Service的名称,这里是 my-service
spec:						      # 指定了Service的规格,包括端口、选择器、会话关联等。
  internalTrafficPolicy: Cluster  # 指定了内部流量策略,这里设置为Cluster,表示只使用集群内部的流量。
  ipFamilies:					  # 指定了IP族,这里设置为IPv4,表示只使用IPv4地址。
  - IPv4
  ipFamilyPolicy: SingleStack     # 指定了IP族策略,这里设置为SingleStack,表示只使用单一的IP族。
  ports:						  # 指定了Service监听的端口和转发的目标端口。
  - port: 80					  # 指定了Service监听的端口,这里是80。
    protocol: TCP				  # 指定了协议,这里是TCP。
    targetPort: 6379			  # 指定了转发的目标端口,也就是后端pod 端口,这里也是80。
  selector:					      # 指定了Service所选择的Pod的标签,这里选择了带有run: redis 标签的 Pod。
    run: redis
  sessionAffinity: None			  # 指定了会话关联的策略,这里设置为None,表示不启用会话关联
  type: ClusterIP				  # 指定了Service的类型,这里是ClusterIP,表示Service只在集群内部可访问。

这个Service将流量从集群内部的80端口转发到具有run: redis 标签的Pod,并且只使用IPv4地址。Service 能够将任意入站 port 映射到某个 targetPort。 默认情况下,出于方便考虑,targetPort 会被设置为与 port 字段相同的值。

端口定义

Pod 中的端口定义是有名字的,你可以在 Service 的 targetPort 属性中引用这些名字。 例如,我们可以通过以下方式将 Service 的 targetPort 绑定到 Pod 端口:

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app.kubernetes.io/name: proxy
spec:
  containers:
  - name: nginx
    image: nginx:stable
    ports:
      - containerPort: 80
        name: http-web-svc

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app.kubernetes.io/name: proxy
  ports:
  - name: name-of-service-port
    protocol: TCP
    port: 8080
    targetPort: http-web-svc  # 后端 pod 端口的名字 也可以写80端口

Service 的默认协议是 TCP;除此之外还有 UDP SCTP两种协议。

EndpointSlices

  • EndpointSlice 是 Kubernetes 1.16 引入的新概念,用于解决 Endpoints 对象过大的问题。
  • EndpointSlice 将一个服务的终端信息分成多个小的片段(Slice),每个片段包含一部分后端 Pod 的信息。
  • 每个 EndpointSlice 对象都包含了一部分服务终端的 IP 地址和端口信息,以及与之相关联的标签和条件信息。
  • EndpointSlice 可以更有效地管理大规模服务,减少对 Kubernetes API Server 的压力,并提高服务发现的性能。

使用EndpointSlice的建议

  • 对于普通的服务发现和负载均衡需求,通常只需关注 Endpoints 即可。
  • 当处理大型服务或大规模集群时,EndpointSlice 可以提供更好的性能和可伸缩性。
  • 大多数情况下,不需要直接操作 EndpointSlice,因为 Kubernetes 会自动管理它们
  • 默认情况下,控制面创建和管理的 EndpointSlice 将包含不超过 100 个端点。 你可以使用 kube-controller-manager 的 --max-endpoints-per-slice 标志设置此值,最大值为 1000。

总的来说,Endpoints 和 EndpointSlice 都是 Kubernetes 中用于表示服务终端的重要资源,它们提供了服务发现和负载均衡的功能,但 EndpointSlice 更适用于处理大规模服务和大型集群。

查看 EndpointSlice:

bash 复制代码
# 查看 endpointslice 资源
kubectl get endpointslice

# 查看 endpointslice 自动生成的yaml文件
kubectl get endpointslice -oyaml

endpointslice的yaml文件介绍

yaml 复制代码
addressType: IPv4							# 指定了终端的地址类型,这里是IPv4
apiVersion: discovery.k8s.io/v1				# 指定了资源的API版本
endpoints:									# 包含了服务终端的详细信息,每个元素表示一个终端
- addresses:								# 指定了后端 Pod 的IP地址
  - 172.21.231.188
  conditions:								# 包含了终端的状态条件,例如是否就绪、正在服务、是否终止等
    ready: true
    serving: true
    terminating: false
  nodeName: node02							# 指定了运行该终端的节点名称
  targetRef:								# 指定了与终端相关联的目标资源,例如Pod
    kind: Pod								# 资源类型为Pod
    name: php-apache-7d4456444b-8t2bz		# 代理的后端Pod名字
kind: EndpointSlice							# 指定了资源的类型为EndpointSlice
metadata:									# 包含了资源的元数据信息
  generateName: php-apache-					# 指定了资源的生成名称
  generation: 13							# 指定了资源的生成数
  labels:									# 资源的标签信息,用于标识和分类资源
    endpointslice.kubernetes.io/managed-by: endpointslice-controller.k8s.io
    kubernetes.io/service-name: php-apache
    run: php-apache
  name: php-apache-6mzj5					# 指定了资源的名称
  ownerReferences:							# 指定了资源的所有者引用,例如与之关联的Service
  - apiVersion: v1
    blockOwnerDeletion: true
    controller: true
    kind: Service
    name: php-apache
ports:										# 指定了服务终端监听的端口信息
- name: ""
  port: 80
  protocol: TCP

Endpoints

在 K8S 中,Endpoints 是一种 API 资源,用于表示一个服务的终端,即该服务所关联的后端 Pod 的网络地址信息。当创建一个 Service 对象时,K8S 会自动创建相应的 Endpoints 对象,用于存储该服务的后端 Pod 的 IP 地址和端口信息。

Endpoints 主要用于以下几个方面:

  • 服务发现:Endpoints 提供了一种机制,使得其他应用程序或服务可以发现和访问与之关联的后端 Pod。通过查询 Endpoints,应用程序可以获取到与之关联的所有后端 Pod 的 IP 地址和端口信息,并与其进行通信。
  • 负载均衡:当一个服务与多个 Pod 关联时,K8S 会自动在 Endpoints 中存储这些 Pod 的地址信息。Service 对象会将请求转发到与之关联的所有 Pod 中,从而实现负载均衡的效果。
  • 服务代理:可以使用Endpoints yaml文件手动修改代理除K8S自己以外的服务。

Endpoints yaml文件介绍

查看方法

bash 复制代码
kubectl get endpoints php-apache -oyaml
yaml 复制代码
apiVersion: v1  							# 指定了 Kubernetes API 的版本
kind: Endpoints								# 指定了资源类型为 Endpoints
metadata:									# 包含了资源的元数据信息,包括标签和名称
  labels:
    run: php-apache
  name: php-apache							# 资源名字
subsets:									# 包含了终端的子集信息,每个子集表示一组后端 Pod
- addresses:								
  - ip: 172.21.231.188						# 后端Pod地址
    nodeName: node02						# Pod 运行在在那个节点上
    targetRef:
      kind: Pod                             # 后端代理的资源类型
      name: php-apache-7d4456444b-8t2bz		# 代理的Pod名字
  ports:
  - port: 80								# 指定代理后端 Pod 的端口号
    protocol: TCP							# 指定协议

使用Endpoints 代理K8S外部服务

例如使用 Endpoints 外部nginx服务,具体配置如下:

yaml 复制代码
---
apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: web-nginx        # 标签必须和下面的Endpoints标签一致
  name: web-nginx             # Service 名字必须和下面Endpoints 名字一直
spec:
  ports:
  - name: http				  # ports 名字必须和下面一致
    port: 8080			      # Service 自己的端口按需修改
    protocol: TCP             # 协议按需修改
    targetPort: 80            # 代理外部服务端口必须和Endpoints的端口一致
  sessionAffinity: None		  # 是否建立回话关联
  type: ClusterIP			  # 服务类型
---
apiVersion: v1
kind: Endpoints
metadata:
  labels:
    k8s-app: web-nginx        # 标签和上面一致
  name: web-nginx			  # 名字和上面一致
subsets:
- addresses:				  # 需要代理外部的服务地址   有几个就写几个
  - ip: 192.168.1.161
#  - ip: 192.168.1.207
#  - ip: 192.168.1.251
  ports:
  - name: http                # post 名字和上面一致
    port: 80                  # 端口和外部服务的端口一致和上面的端口一致
    protocol: TCP			  # 和上面一致

修改好以后创建

按照我这个配置正常情况下肯定是可以代理外部服务了,这样代理外部服务主要是为了统一所有环境的配置文件。

bash 复制代码
kubectl create -f web-nginx.yaml

使用 Service 代理外部域名

使用 Service 代理百度域名 ,肯定能代理成功,但是百度不允许跨域访问。

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  labels:
    app: web-nginx
  name: web-nginx
spec:
  type: ExternalName
  externalName: www.baidu.com

Service 常用类型

ClusterIP

通过集群的内部 IP 公开 Service,选择该值时 Service 只能够在集群内部访问。 这也是你没有为服务显式指定 type 时使用的默认值。

示例:

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  labels:
    run: php-apache
  name: php-apache
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: php-apache
  type: ClusterIP    # 不指定类型默认是 ClusterIP

NodePort

通过每个节点上的 IP 和静态端口(NodePort)公开 Service。 为了让 Service 可通过节点端口访问,Kubernetes 会为 Service 配置集群 IP 地址, 相当于你请求了 type: ClusterIP 的服务。

示例:

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    # 默认情况下,为了方便起见,`targetPort` 被设置为与 `port` 字段相同的值。
    - port: 80
      targetPort: 80
      # 可选字段
      # 默认情况下,为了方便起见,Kubernetes 控制平面会从某个范围内分配一个端口号
      #(默认:30000-32767)
      nodePort: 30007  # NodePort 可以自己指定端口,不指定的话就是随机端口

K8S 默认的端口范围是(30000-32767)可以自己修改:

二进制方式部署的修改apiserver启动文件即可

--service-node-port-range=30000-32767

bash 复制代码
vim /usr/lib/systemd/system/kube-apiserver.service

kubeadm 方式部署的修改这个文件夹下面 /etc/kubernetes/ 找到kube-apiserver.yaml 有关的文件修改即可 ,参数都是一样的。

LoadBalancer

用于将外部流量均衡地分发到集群中的后端 Pod。LoadBalancer 在云提供商(如AWS、阿里云,腾讯云等)上创建一个负载均衡器,并将该负载均衡器配置为将流量路由到 Kubernetes 集群中的 Service。这使得应用程序可以通过公共 IP 地址或 DNS 名称访问 Kubernetes 集群中的服务。

示例:

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  clusterIP: 10.0.171.239
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 192.0.2.127

如要设置内部负载均衡器,请根据你所使用的云平台,为 Service 添加以下注解之一:

阿里云:

yaml 复制代码
metadata:
  annotations:
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type: "intranet"

百度云:

yaml 复制代码
metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/cce-load-balancer-internal-vpc: "true"

腾讯云:

yaml 复制代码
metadata:
  annotations:
    service.kubernetes.io/qcloud-loadbalancer-internal-subnetid: subnet-xxxxx

AWS:

yaml 复制代码
metadata:
    name: my-service
    annotations:
        service.beta.kubernetes.io/aws-load-balancer-internal: "true"

ExternalName

将服务映射到 externalName 字段的内容(例如,映射到主机名 api.foo.bar.example)。 该映射将集群的 DNS 服务器配置为返回具有该外部主机名值的 CNAME 记录。

示例:

yaml 复制代码
## 代理外部域名就是用的这个类型
apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

无头Service(Headless Services)

无头服务K8S中一种特殊类型的服务,与普通的服务类型(如ClusterIP、NodePort、LoadBalancer)不同,它并不分配 ClusterIP,也不会代理流量到任何后端 Pod。相反,它的主要目的是为了服务发现,通过 DNS 记录提供了服务的所有 Pod 的 IP 地址列表。这样,应用程序可以直接通过 Pod 的 IP 地址来访问服务,而不需要经过 Kubernetes 的服务代理。

由于无头服务提供了每个 Pod 的直接 IP 地址,因此它通常用于运行有状态应用程序,如数据库、缓存

示例:

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: mysql
  labels:
    app: mysql
    app.kubernetes.io/name: mysql
spec:
  ports:
  - name: mysql
    port: 3306
  clusterIP: None   # 类型设置为none
  selector:
    app: mysql

查询 DNS 记录: 使用 Pod 内置的 DNS 解析功能,可以通过无头服务的 DNS 名称来获取所有后端 Pod 的 IP 地址列表。例如,通过查询 my-headless-service.namespace.svc.cluster.local 可以获取到所有与 my-headless-service 服务关联的 Pod 的 IP 地址列表。

相关推荐
年薪丰厚1 小时前
如何在K8S集群中查看和操作Pod内的文件?
docker·云原生·容器·kubernetes·k8s·container
zhangj11251 小时前
K8S Ingress 服务配置步骤说明
云原生·容器·kubernetes
岁月变迁呀1 小时前
kubeadm搭建k8s集群
云原生·容器·kubernetes
墨水\\1 小时前
二进制部署k8s
云原生·容器·kubernetes
Source、1 小时前
k8s-metrics-server
云原生·容器·kubernetes
上海运维Q先生1 小时前
面试题整理15----K8s常见的网络插件有哪些
运维·网络·kubernetes
颜淡慕潇1 小时前
【K8S问题系列 |19 】如何解决 Pod 无法挂载 PVC问题
后端·云原生·容器·kubernetes
ProtonBase1 小时前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
大熊程序猿4 小时前
K8s证书过期
云原生·容器·kubernetes
摸鱼也很难7 小时前
Docker 镜像加速和配置的分享 && 云服务器搭建beef-xss
运维·docker·容器