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 地址列表。

相关推荐
竹木一54012 分钟前
Docker拉取镜像代理配置实践与经验分享
经验分享·docker·容器
破 风2 小时前
Docker启动mysql容器时找不到 mysqlx.sock 和 mysqld.sock
mysql·docker·容器
阿里云云原生2 小时前
SAE 实现应用发布全过程可观测
云原生
鱼饼6号3 小时前
Jenkins Pipeline 构建 CI/CD 流程
linux·运维·服务器·ci/cd·容器·jenkins
Ares-Wang4 小时前
kubernetes》》k8s》》Heml
云原生·容器·kubernetes
阿里云大数据AI技术4 小时前
千万级数据秒级响应!碧桂园基于 EMR Serverless StarRocks 升级存算分离架构实践
大数据·云原生·serverless
容器魔方4 小时前
Bilibili、中电信人工智能科技、商汤科技、联通云等正式加入Volcano社区用户组
云原生·容器·云计算
努力的IT小胖子5 小时前
Docker 镜像下载太慢?手把手教你修改镜像源,速度起飞!
后端·docker·容器
阿里云云原生6 小时前
MCP云托管最优解,揭秘国内最大MCP中文社区背后的运行时
云原生
有谁看见我的剑了?6 小时前
docker 运行时权限和 Linux 能力了解
linux·docker·容器