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.local
,redis-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