Service 和 Headless Servic 的区别

  • 普通的 Service,只能通过解析 service 的 DNS 返回 service 的 Cluster IP。
  • headless service作为service的一种类型,顾名思义无头服务,无头 Service 不会获得集群 IP,kube-proxy 不会处理这类 Service, 而且平台也不会为它们提供负载均衡或路由支持。
  • 无头 Service 允许客户端直接连接到它所偏好的任一 Pod。 无头 Service 不使用虚拟 IP 地址和代理配置路由和数据包转发;相反,无头 Service 通过内部 DNS 记录报告各个 Pod 的端点 IP 地址,这些 DNS 记录是由集群的 DNS 服务所提供的。
  • Cluster IP 类型的 Service 用于有状态的服务,而 Headless Service 则用于有状态的服务,比如有时候 client 想自己决定使用哪个 Real Server,可以通过查询 DNS 来获取 Real Server 的信息。又或者 headless service关联的每个 endpoint(也就是 Pod),都会有对应的 DNS 域名;这样 Pod 之间就可以互相访问。
  • 无状态的服务,其中一个代表就是 Deployment,而有状态的服务,代表则是 StatefulSet。 其中,Headless Service 主要是为了 StatefulSet 的网络拓扑状态而服务的。

普通 service 解析 DNS

Service的ClusterIP工作原理:一个 Service 可能对应一组 endpoints(所有 pod 的地址+端口),client 访问 ClusterIP,通过 iptables 或者 ipvs 转发到 Real Server(Pod)

# kubectl get pods -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP              NODE   NOMINATED NODE   READINESS GATES
busybox                  1/1     Running   0          18s   10.104.157.68   k8s    <none>           <none>
nginx-6b85df66b4-gnbwg   1/1     Running   0          18s   10.104.157.70   k8s    <none>           <none>
nginx-6b85df66b4-rjf6g   1/1     Running   0          18s   10.104.157.71   k8s    <none>           <none>
#
# kubectl get service -l service=nginx
NAME             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
nginx-service    ClusterIP   172.16.100.1   <none>        80/TCP    21s
#
# kubectl get endpoints nginx-service
NAME            ENDPOINTS                           AGE
nginx-service   10.104.157.70:80,10.104.157.71:80   45s
#
# kubectl exec -t busybox -- nslookup nginx-service.default.svc.cluster.local
Server:    172.16.0.10
Address 1: 172.16.0.10 kube-dns.kube-system.svc.cluster.local

Name:      nginx-service.default.svc.cluster.local
Address 1: 172.16.100.1 nginx-service.default.svc.cluster.local

从上面的结果能看到,虽然 Service 有 2 个 endpoint(10.104.157.70:80,10.104.157.71:80),但是 DNS 查询时只会返回 Service 的 ClusterIP 地址(172.16.100.1),具体 Client 访问的是哪个 real server,由 iptables 或者 ipvs 决定。

headless Service的解析service的DNS结果

# kubectl get statefulsets
NAME    READY   AGE
redis   2/2     38s
#
# kubectl get pods -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP              NODE   NOMINATED NODE   READINESS GATES
busybox   1/1     Running   0          59s   10.104.157.77   k8s    <none>           <none>
redis-0   1/1     Running   0          49s   10.104.157.80   k8s    <none>           <none>
redis-1   1/1     Running   0          48s   10.104.157.81   k8s    <none>           <none>
#
# kubectl get service -l service=redis
NAME             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
redis-headless   ClusterIP   None           <none>        6379/TCP   17s
redis-service    ClusterIP   172.16.200.1   <none>        6379/TCP   23s
#
# kubectl get endpoints  redis-service 
NAME            ENDPOINTS                               AGE
redis-service   10.104.157.80:6379,10.104.157.81:6379   25s
#
# kubectl exec -t busybox -- nslookup redis-headless.default.svc.cluster.local
Server:    172.16.0.10
Address 1: 172.16.0.10 kube-dns.kube-system.svc.cluster.local

Name:      redis-headless.default.svc.cluster.local
Address 1: 10.104.157.80 redis-0.redis-headless.default.svc.cluster.local
Address 2: 10.104.157.81 redis-0.redis-headless.default.svc.cluster.local

根据结果看到,dns查询会返回 2 个 endpoint(10.104.157.75:6379,10.104.157.76:6379),也就是 2 个 pod 地址和 DNS( redis-1.redis-headless.default.svc.cluster.localredis-0.redis-headless.default.svc.cluster.local),通过解析 pod 的 DNS 也能返回 Pod 的 IP。

# kubectl exec -t busybox -- nslookup redis-0.redis-headless.default.svc.cluster.local
Server:    172.16.0.10
Address 1: 172.16.0.10 kube-dns.kube-system.svc.cluster.local

Name:      redis-0.redis-headless.default.svc.cluster.local
Address 1: 10.104.157.80 redis-0.redis-headless.default.svc.cluster.local

总结:

Headless Service 的作用在于是让 <pod name> 加入了域名中,这样才能完成网络拓扑的关系确定。如果这个 StatefulSet 需要被当做一个整体进行访问那么使用 <svc name>.<namespace>.svc.cluster.local 的域名格式也可以完成,因为 StatefulSet 对应的集群千变万化,有的可能只是一个读写分离集群;有的可能是一主多从集群。那么它的访问入口也需要根据实际情况进行变化,而 VIP 的模式只是将多个 IP 进行平等的负载,所以不需要用 VIP 的模式来实现一个负载均衡,这种情况下将负载交由客户端来决定是一个非常聪明的思路。

概括就是:

  • 无头服务不需要指定集群地址
  • 无头服务适用有状态应用例如数据库
  • 无头服务dns查询会返回pod列表,开发人员可以自定义负载均衡策略
  • 普通Service可以通过负载均衡路由到不同的容器应用

参考:
https://www.cnblogs.com/chadiandianwenrou/p/11937041.html
https://blog.csdn.net/qq_33326449/article/details/117401847
https://fuzhibo.site/kubernetes,headless/service/2019/12/30/why-kubernetes-has-headless-service.html