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 用于无状态的服务。 无状态的服务,其中一个代表就是 Deployment。Deployment 的 Pod数量 和 IP 地址是可变化的,通过 Service 和 Pod 建立连接。比如某些 client 不需要关心访问的是哪个 Pod,这样 client 就可以通过访问这个 Service 来访问 Pod,从而无需关系 Pod 的 IP 是多少。
- 而 Headless Service 则用于有状态的服务。而有状态的服务,代表则是 StatefulSet。Headless Service 主要是为了 StatefulSet 的网络拓扑状态而服务的。比如有时候 client 想自己决定使用哪个 Real Server,可以通过查询 DNS 来获取 Real Server 的信息。又或者 headless service关联的每个 endpoint(也就是 Pod),都会有对应的 DNS 域名;这样 Pod 之间就可以互相访问。
普通 service 解析 DNS
Service的ClusterIP工作原理:一个 Service 可能对应一组 endpoints(所有 pod 的地址+端口),client 访问 ClusterIP,通过 iptables 或者 ipvs 转发到 Real Server(Pod)
定义一个简单的 Deployment资源,包含两个 nginx。并定义一个普通 Service 来进行测试,yaml 如下:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:1.24.0
name: nginx
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
service: nginx
spec:
selector:
app: nginx
type: ClusterIP
clusterIP: 172.16.100.1
ports:
- port: 80
protocol: TCP
targetPort: 80
创建资源后:
# 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结果
定义一个简单的 Statefulsets 资源,包含两个 redis。并定义一个 headless Service 来进行测试,yaml 如下:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
spec:
replicas: 2
serviceName: redis-headless
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7.0
ports:
- containerPort: 6379
name: redis
---
apiVersion: v1
kind: Service
metadata:
name: redis-headless
labels:
service: redis
spec:
selector:
app: redis
type: ClusterIP
clusterIP: None
ports:
- port: 6379
protocol: TCP
targetPort: 6379
资源创建后:
# 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
#
# kubectl get endpoints redis-headless
NAME ENDPOINTS AGE
redis-headless 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-1.redis-headless.default.svc.cluster.local
根据结果看到,dns 查询会返回 2 个域名( redis-0.redis-headless.default.svc.cluster.local
,redis-1.redis-headless.default.svc.cluster.local
),这两个域名的 IP 正好对应两个 endpoint 地址(10.104.157.80、10.104.157.81)。通过解析 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