其他分享
首页 > 其他分享> > kubernetes: headless service

kubernetes: headless service

作者:互联网

 

背景:
有时候我们创建的服务不想走 负载均衡,想直接通过 pod-ip 链接后端, 怎么办呢, 使用headless service接可以解决。
1.什么是headless service
headless service 是将service的发布文件中的clusterip=none ,不让其获取clusterip , DNS解析的时候直接走pod
2.实验
部署pod

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

部署常规service

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  labels:
    app: nginx
spec:
  ports:
  - port: 88
    targetPort: 80
  selector:
    app: nginx
  type: NodePort

 

查看 部署的service
10.97.134.133是 clusterip
在这里插入图片描述
部署headlessservice

apiVersion: v1
kind: Service
metadata:
  name: headless-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  clusterIP: None

 

查看详情
在这里插入图片描述
测试服务解析
service 的 FQDN: nginx-service.default.svc.cluster.local
headless service的FQDN: headless-service.default.svc.cluster.local
我们在容器里面ping FQDN , service解析出的地址是clusterip
在这里插入图片描述
headless service 解析出来的地址是 pod ip
在这里插入图片描述
所以在微服务相关场景 如果需要直通pod的时候 我们就可以使用headless service 绕过 k8s的转发机制,直接访问pod了。

参考资料
https://kubernetes.io/docs/concepts/services-networking/service/#headless-services

 

如果您使用 gRPC 并在 Kubernetes 上部署了许多后端,那么本文档适合您。

为什么要负载均衡?

大规模部署有许多相同的后端实例和许多客户端。每个后端服务器都有一定的容量。负载均衡用于在可用服务器之间分配来自客户端的负载。

在开始详细了解Kubernetes中的gRPC负载平衡之前,让我们先了解一下负载平衡的好处。

负载平衡有很多好处,其中一些是:

负载平衡还有许多其他好处。你可以在这里阅读更多关于负载均衡器的内容。

https://www.appviewx.com/education-center/load-balancer/

gRPC的负载均衡选项

gRPC中有两种类型的负载平衡选项——代理和客户端。

代理负载平衡

在代理负载均衡中,客户端将rpc发送给LB (load Balancer)代理。LBRPC调用分发到一个可用的后端服务器,该后端服务器实现为调用提供服务的实际逻辑。LB跟踪每个后端的负载,并实现公平分配负载的算法。客户端本身并不知道后台服务器。客户端是不可信的。这种体系结构通常用于面向用户的服务,其中来自开放互联网的客户端可以连接到服务器

客户端负载均衡

在客户端负载平衡中,客户端知道许多后端服务器,并为每个RPC选择一个后端服务器。如果客户端希望实现基于服务器负载报告的负载均衡算法。对于简单的部署,客户机可以在可用的服务器之间轮询请求。

有关gRPC负载均衡选项的更多信息,可以查看文章gRPC负载均衡。

https://grpc.io/blog/grpc-load-balancing/

与gRPC负载均衡相关的挑战

gRPCHTTP/2上工作。http/2上的TCP连接是长期存在的。一个连接可以使多个请求多路复用。这减少了与连接管理相关的开销。但这也意味着连接级负载平衡不是很有用。Kubernetes中的默认负载均衡是基于连接级负载均衡的。由于这个原因,Kubernetes的默认负载平衡不能与gRPC一起工作。

为了确认这个假设,让我们创建一个Kubernetes应用程序。这个应用程序由-组成

图片

创建服务端部署

要创建部署,请将以下代码保存在 YAML 文件中,例如 deployment-server.yaml,然后运行命令kubectl apply -f deployment-server.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: grpc-server
  labels:
    app: grpc-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: grpc-server
  template:
    metadata:
      labels:
        app: grpc-server
    spec:
      containers:
        - name: grpc-server
          image: techdozo/grpc-lb-server:1.0.0

这将创建一个具有三个副本的 gRPC 服务端。该GRPC服务端在端口上运行8001。要验证 pod是否成功创建,请运行命令kubectl get pods

NAME                           READY   STATUS    RESTARTS   AGE
grpc-server-6c9cd849-5pdbr     1/1     Running   0          1m
grpc-server-6c9cd849-86z7m     1/1     Running   0          1m
grpc-server-6c9cd849-mw9sb     1/1     Running   0          1m

您可以运行命令kubectl logs --follow grpc-server-<>查看日志。

创建服务

要创建服务,请将以下代码保存在 YAML 文件中,例如service.yaml,然后运行命令kubectl apply -f service.yaml

apiVersion: v1
kind: Service
metadata:
  name: grpc-server-service
spec:
  type: ClusterIP
  selector:
    app: grpc-server
  ports:
    - port: 80
      targetPort: 8001

ClusterIP服务提供负载平衡的 IP 地址。它在通过标签选择器匹配的pod 端点之间负载平衡流量。

Name:              grpc-server-service
Namespace:         default      
Selector:          app=grpc-server
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.96.28.234
IPs:               10.96.28.234
Port:              <unset>  80/TCP
TargetPort:        8001/TCP
Endpoints:         10.244.0.11:8001,10.244.0.12:8001,10.244.0.13:8001
Session Affinity:  None

如上所示,Pod 的 IP 地址是 - 10.244.0.11:8001,10.244.0.12:8001,10.244.0.13:8001。如果客户端调用端口 80上的服务,那么它将跨端点(Pod 的 IP 地址)对调用进行负载平衡。但对于gRPC 而言,情况并非如此,您很快就会看到。

创建客户端部署

要创建客户端部署,请将以下代码保存在 YAML 文件中,例如 deployment-client.yaml,然后运行命令 kubectl apply -f deployment-client.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: grpc-client
  labels:
    app: grpc-client
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grpc-client
  template:
    metadata:
      labels:
        app: grpc-client
    spec:
      containers:
        - name: grpc-client
          image: techdozo/grpc-lb-client:1.0.0
          env:
            - name: SERVER_HOST
              value: grpc-server-service:80

gRPC 客户端应用程序在启动时使用一个通道在 10 个并发线程中对服务器进行 1,000,000 次调用。该SERVER_HOST环境变量指向DNS服务的grpc-server-service。在 gRPC 客户端上,通过将SERVER_HOST(serverHost)传递为:

ManagedChannelBuilder.forTarget(serverHost) .defaultLoadBalancingPolicy("round_robin") .usePlaintext() .build();

如果您检查服务器日志,您会注意到所有客户端调用仅由一个服务器 pod 提供服务。

使用无头服务的客户端负载平衡

您可以使用Kubernetes headless service进行客户端循环负载平衡。这种简单的负载平衡与 gRPC一起开箱即用。缺点是它没有考虑服务器上的负载。

什么是无头服务?

幸运的是,Kubernetes 允许客户端通过DNS查找来发现 pod IP。通常,当您对服务执行DNS 查找时,DNS 服务器会返回一个 IP — 服务的集群 IP。但是,如果您告诉 Kubernetes您的服务不需要集群 IP(您可以通过将服务规范中的 clusterIP 字段设置为 None 来实现),DNS 服务器将返回 pod IP 而不是单个服务 IPDNS 服务器将返回服务的多个 A 记录,而不是返回单个 DNS A记录,每个记录都指向当时支持该服务的单个 podIP。因此,客户端可以进行简单的 DNS A 记录查找并获取属于服务的所有pod的 IP。然后,客户端可以使用该信息连接到其中一个、多个或全部。

将服务规范中的 clusterIP字段设置为None 会使服务无头,因为 Kubernetes 不会为其分配集群IP,客户端可以通过该IP连接到支持它的pod

将无头服务定义为:

apiVersion: v1
kind: Service
metadata:
  name: grpc-server-service
spec:
  clusterIP: None
  selector:
    app: grpc-server
  ports:
    - port: 80
      targetPort: 8001

要使服务成为无头服务,您唯一需要更改的.spec.clusterIP字段是将字段设置为None

验证 DNS

要确认无头服务的 DNS,请创建一个镜像为tutum/dnsutils的 pod :

kubectl run dnsutils --image=tutum/dnsutils --command -- sleep infinity

然后运行命令

kubectl exec dnsutils -- nslookup grpc-server-service

这将无头服务的 FQDN 返回为:

Server:         10.96.0.10
Address:        10.96.0.10#53
Name:   grpc-server-service.default.svc.cluster.local
Address: 10.244.0.22
Name:   grpc-server-service.default.svc.cluster.local
Address: 10.244.0.20
Name:   grpc-server-service.default.svc.cluster.local
Address: 10.244.0.21

如您所见,无头服务解析为所有通过 service 连接的 pod的 IP 地址。将此与非无头服务返回的输出进行对比。

Server: 10.96.0.10 Address: 10.96.0.10#53 Name: grpc-server-service.default.svc.cluster.local Address: 10.96.158.232

配置客户端 客户端应用程序剩下的唯一变化是指向带有服务器 pods 端口的无头服务,如下所示:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: grpc-client
  labels:
    app: grpc-client
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grpc-client
  template:
    metadata:
      labels:
        app: grpc-client
    spec:
      containers:
        - name: grpc-client
          image: techdozo/grpc-lb-client:1.0.0
          env:
            - name: SERVER_HOST
              value: grpc-server-service:8001

请注意,SERVER_HOST现在指向无头服务 grpc-server-service和服务器端口 8001。您还可以使用 SERVER_HOST 作为 FQDN

name: SERVER_HOST 
value: "grpc-server-service.default.svc.cluster.local:8001"

如果您通过首先删除客户端部署来再次部署客户端:

kubectl delete deployment.apps/grpc-client

然后再次部署客户端:

kubectl apply -f deployment-client.yaml

您可以看到 pod打印的日志。

图片

代码示例

本文的工作代码示例列在GitHub 上 。您可以使用kind在本地 Kubernetes 集群上运行代码。

https://github.com/techdozo/grpc-lb

https://techdozo.dev/2021/getting-started-with-kind-quick-start-a-multi-node-local-kubernetes-cluster/

概括

gRPC 中有两种可用的负载平衡选项——代理和客户端。由于 gRPC 连接是长期存在的,Kubernetes的默认连接级负载平衡不适用于 gRPCKubernetes Headless服务是一种可以实现负载均衡的机制。Kubernetes 无头服务 DNS 解析为支持 PodIP

标签:service,kubernetes,grpc,server,headless,gRPC,pod,客户端
来源: https://www.cnblogs.com/cheyunhua/p/16212246.html