Tim Wang Tech Blog

Kubernetes headless Service介绍

本文由 headless-services-in-kubernetes的中文翻译版本,内容有删减

Kubernetes headless Service是一个没有专用负载均衡器的service。这种类型的Service 通常用于有状态的应用程序。例如数据库,这些应用要求必须为每个实例维护一致的网络标识。如果客户端需要连接所有 Pod,则无法使用常规 Kubernetes的 ClusterIP Service来完成此操作。Service将无法将每个连接转发到随机选择的容器。

常规的Service是如何工作的?(How does Regular Service Object Works?)

接下来我们通过下面的yaml配置文件来创建一个常规的Kubernetes ClusterIP Service。

cat <<EOF | kubectl apply -f -
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: normal-nginx
  labels:
    app: normal-nginx # Deployment labels to match with replicaset labels and pods labels
spec:
  replicas: 3
  selector:
    matchLabels:
      app: normal-nginx # Replicaset to manage pods with labels
  template:
    metadata:
      labels:
        app: normal-nginx # Pods labels
    spec:
      containers:
        - name: nginx
          image: nginx
---
apiVersion: v1 # v1 is the default API version. It is the latest version of the Core API.
kind: Service # Service is a collection of Pods that are running on a host.
metadata:
  name: normal-nginx # name of the service
  labels:
    app: normal-nginx # label for the service
spec:
  selector:
    app: normal-nginx # label for the service
  ports:
  - port: 80 # port to expose
    targetPort: 80 # container port
    protocol: TCP # protocol to use for the port mapping ( example TCP, UDP, or SCTP)
  type: ClusterIP # type of service to create, ClusterIP is the default. Others are NodePort, LoadBalancer, and ExternalName.
EOF

Output:

deployment.apps/normal-nginx created
service/normal-nginx created
``
接下来我们通过下面的命令来验证我们的Service是否创建成功。

```Shell 
kubectl get svc -o wide | grep normal-nginx

Output:

normal-nginx   ClusterIP  10.96.141.251  <none>    80/TCP  48s   app=normal-nginx

然后是 normal-nginx pods的验证。

kubectl get pods -o wide | grep normal-nginx

Output:

normal-nginx-d98bff4-jk65q    1/1   Running  0     74s   10.244.2.20  kind-worker2  <none>      <none>
normal-nginx-d98bff4-sbzf9    1/1   Running  0     74s   10.244.1.19  kind-worker  <none>      <none>
normal-nginx-d98bff4-wbj7q    1/1   Running  0     74s   10.244.2.19  kind-worker2  <none>      <none>

Now if you run nslookup to normal-nginx service object you will see following output:
现在,如果您运行 nslookupnormal-nginx 服务对象,您将看到以下输出:

kubectl run -it --rm debug --image=tutum/dnsutils --restart=Never nslookup normal-nginx

Output:

Server:     10.96.0.10
Address:    10.96.0.10#53

Name:   normal-nginx.default.svc.cluster.local
Address: 10.96.141.251
pod "debug" deleted

nslookup normal-nginx 的结果是 ClusterIP 地址。

Headless Service是如何工作的(How does Headless Service Object Works?

对于客户端来说,要连接到所有的pod,它需要知道每个pod的IP地址。一种选择是让客户端调用Kubernetes API server,并通过API调用获取pod和IP地址的列表。但是,使用APIserver并不理想,因为您应该始终努力减少API调用以提高性能。另一种选择是使用Headless Service,它将为您提供一个静态IP地址列表,您可以使用该列表连接到pod。

Kubernetes 允许客户端查找服务中pod的IP地址。通常,当您查找服务地址时,您会得到一个单独的IP地址:负载均衡器或ClusterIP的地址。如果您使用Headless Service时,那么Kubernetes将为您提供所有pod的IP地址列表。客户端可以通过执行DNS A记录查找来查找服务的所有pod的IPs。然后,客户端可以使用该信息连接到一个、多个或所有pod。

Headless service在进行单个pod的健康检查时也很有用。使用常规Service时,健康检查是在负载均衡器上执行的,该负载均衡器仅将流量转发到pod。这意味着pod可能不健康,但负载均衡器永远不会知道,因为它只是转发流量。使用headless service时,健康检查是在单个pod上执行的,因此您可以确保流量路由到健康的pod。

接下来,我们来运行相同的测试。首先,创建部署对象和headless service。在服务规范中将clusterIP字段设置为None意味着Kubernetes将不会为服务分配集群IP地址,您可以按照以下方式执行:

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: headless-nginx
  labels:
    app: headless-nginx # Deployment labels to match with replicaset labels and pods labels
spec:
  replicas: 3
  selector:
    matchLabels:
      app: headless-nginx # Replicaset to manage pods with labels
  template:
    metadata:
      labels:
        app: headless-nginx # Pods labels
    spec:
      containers:
        - name: nginx
          image: nginx
---
apiVersion: v1 # v1 is the default API version. It is the latest version of the Core API.
kind: Service # Service is a collection of Pods that are running on a host.
metadata:
  name: headless-nginx # name of the service
  labels:
    app: headless-nginx # label for the service
spec:
  selector:
    app: headless-nginx # label for the service
  clusterIP: None # this is will point directly to pods, nslookup will rerun pod ips
  ports:
  - port: 80 # port to expose
    targetPort: 80 # container port
    protocol: TCP # protocol to use for the port mapping ( example TCP, UDP, or SCTP)
  type: ClusterIP # type of service to create, ClusterIP is the default. Others are NodePort, LoadBalancer, and ExternalName.
EOF

你会得到下面的输出

deployment.apps/headless-nginx created
service/headless-nginx created

继续验证

kubectl get svc -o wide

Output:

NAME       TYPE    CLUSTER-IP  EXTERNAL-IP  PORT(S)  AGE   SELECTOR
headless-nginx  ClusterIP  None     <none>    80/TCP  43s   app=headless-nginx
kubectl get pods -o wide

Output:

NAME               READY  STATUS  RESTARTS  AGE  IP      NODE      NOMINATED NODE  READINESS GATES
headless-nginx-5795b5d5db-9sv8k  1/1   Running  0     71s  10.244.2.18  kind-worker2  <none>      <none>
headless-nginx-5795b5d5db-d5xmn  1/1   Running  0     71s  10.244.1.18  kind-worker  <none>      <none>
headless-nginx-5795b5d5db-dgwzq  1/1   Running  0     71s  10.244.1.17  kind-worker  <none>      <none>

接下来运行nslookup测试,如下所示

kubectl run -it --rm debug --image=tutum/dnsutils --restart=Never nslookup headless-nginx

Output:

Server:     10.96.0.10
Address:    10.96.0.10#53

Name:   headless-nginx.default.svc.cluster.local
Address: 10.244.1.18
Name:   headless-nginx.default.svc.cluster.local
Address: 10.244.1.17
Name:   headless-nginx.default.svc.cluster.local
Address: 10.244.2.18

pod "debug" deleted

可以看到,nslookup命令为headless service返回了三个IP地址。

headless servicey应用场景(Some of the use cases of headless service)

  • 数据库复制和集群:数据库中的数据在两个或多个数据库之间同步。MongoDB,Couchbase等服务使用headless服务来集群和同步数据库之间的数据。
  • 创建有状态服务:StatefulSet是用于管理有状态应用程序的工作负载API对象。它管理一组Pod的部署和缩放,并提供有关这些Pod的顺序和唯一性的保证。Headless服务使用稳定的主机名和IP地址暴露StatefulSet的Pod。RabbitMQ或Kafka(或任何其他消息代理服务)可以使用有状态集来部署到Kubernetes。
  • 容器编排:不建议将容器编排工具(如marathon,kube-scheduler等)直接暴露给互联网,但headless服务可以帮助您在内部暴露这些工具,并使它们从外部世界保持安全。
  • TLS终止:使用headless服务,我们可以在任何节点上终止TLS,然后可以在未加密的连接上进行通信。
  • 服务发现:正如我们在示例中看到的,headless服务可以用于执行nslookup命令并获取Pod的IP地址。

headless service的缺点(Drawbacks of headless service)

Headless service也存在一些缺点。主要的一个是它可能更难调试,因为您必须查看单个pod,而不是单个负载均衡器。这通常不是一个大问题,因为大多数服务都有某种日志记录,可以帮助您调试问题。