K8S之Headless返回IP浅析
简介
- 有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 “None” 来创建 Headless Service。(
这个service是没有IP
)。因为没有ClusterIP,kube-proxy 并不处理此类服务,因为没有load balancing或 proxy 代理设置,在访问服务的时候回返回后端的全部的Pods IP地址,主要用于开发者自己根据pods进行负载均衡器的开发(设置了selector) 或 StatefulSet
- 这个选项允许开发人员自由寻找他们自己的方式,从而降低与 Kubernetes 系统的耦合性。 应用仍然可以使用一种自注册的模式和适配器,对其它需要发现机制的系统能够很容易地基于这个 API 来构建。
对这类 Service 并不会分配 Cluster IP,kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由
。 DNS如何实现自动配置,依赖于Service是否定义了 selector
不同的pod通过域名进行通信
ClusterIP=None
[root@k8s-master-1 headless]apiVersion: v1kind: Servicemetadata: name: nginxspec: type: ClusterIP clusterIP: None selector: app: nginx ports: - port: 88 targetPort: 80---apiVersion: apps/v1kind: Deploymentmetadata: name: nginxspec: replicas: 2 selector: matchLabels: app: nginx template: metadata: name: nginx labels: app: nginx spec: restartPolicy: Always containers: - name: nginx image: nginx:latest imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80
[root@k8s-master-1 headless]NAME READY STATUS RESTARTS AGEnginx-d89c7cdcb-ql9fz 1/1 Running 0 2m57snginx-d89c7cdcb-vlmlp 1/1 Running 0 2m57s[root@k8s-master-1 headless]NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes ClusterIP 10.0.0.1 <none> 443/TCP 159dnginx ClusterIP None <none> 88/TCP 73s[root@k8s-master-1 headless]Name:nginxNamespace: defaultLabels: <none>Annotations:<none>Selector: app=nginxType:ClusterIPIP Families:<none>IP: NoneIPs: NonePort:<unset> 88/TCPTargetPort: 80/TCPEndpoints: 10.70.2.58:80,10.70.2.61:80Session Affinity: NoneEvents: <none>[root@k8s-master-1 headless]If you don't see a command prompt, try pressing enter./ # nslookup nginx.default.svc.cluster.localServer: 10.0.0.10Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.localName: nginx.default.svc.cluster.localAddress 1: 10.70.2.58 10-70-2-58.nginx.default.svc.cluster.localAddress 2: 10.70.2.61 10-70-2-61.nginx.default.svc.cluster.local## 由于nginx.default.svc.cluster.local 返回的是svc后面的POD IP,而后端pod的88端口并没有通/ # telnet nginx.default.svc.cluster.local 88 telnet: can't connect to remote host (10.70.2.58): Connection refused/ ^CConsole escape. Commands are:
ClusterIP!=None
[root@k8s-master-1 headless]apiVersion: v1kind: Servicemetadata: name: nginxspec: type: ClusterIP selector: app: nginx ports: - port: 88 targetPort: 80---apiVersion: apps/v1kind: Deploymentmetadata: name: nginxspec: replicas: 2 selector: matchLabels: app: nginx template: metadata: name: nginx labels: app: nginx spec: restartPolicy: Always containers: - name: nginx image: nginx:latest imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80
[root@k8s-master-1 headless]NAME READY STATUS RESTARTS AGEnginx-d89c7cdcb-5fm2f 1/1 Running 0 46snginx-d89c7cdcb-pgqxj 1/1 Running 0 46s[root@k8s-master-1 headless]NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes ClusterIP 10.0.0.1<none> 443/TCP 160dnginx ClusterIP 10.0.218.131 <none> 88/TCP 97s[root@k8s-master-1 headless]Name:nginxNamespace: defaultLabels: <none>Annotations:<none>Selector: app=nginxType:ClusterIPIP Families:<none>IP: 10.0.218.131IPs: 10.0.218.131Port:<unset> 88/TCPTargetPort: 80/TCPEndpoints: 10.70.2.2:80,10.70.2.63:80Session Affinity: NoneEvents: <none>[root@k8s-master-1 headless]If you don't see a command prompt, try pressing enter./ # nslookup nginx.default.svc.cluster.localServer: 10.0.0.10Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.localName: nginx.default.svc.cluster.localAddress 1: 10.0.218.131 nginx.default.svc.cluster.local## 由于nginx.default.svc.cluster.local 返回的是svc IP,故而88端口会被转发到后端nginx的80端口,而svc 80端口未对外开放故而无法正常访问/ # telnet nginx.default.svc.cluster.local 88eHTTP/1.1 400 Bad RequestServer: nginx/1.21.5Date: Fri, 25 Mar 2022 01:37:00 GMTContent-Type: text/htmlContent-Length: 157Connection: close400 Bad Request400 Bad Request
nginx/1.21.5Connection closed by foreign host/ # telnet nginx.default.svc.cluster.local 80telnet: can't connect to remote host (10.0.218.131): Connection refused
总结
- 配置了selector:对定义selector的Headless Service,Endpoint 控制器在 API 中创建了 Endpoints 记录,并且修改 DNS 配置返回 A 记录(地址),通过这个地址直接到达Service的后端Pod上
- 未配置selector:对没有定义 selector 的 Headless Service,Endpoint 控制器不会创建Endpoints记录
- 我们在容器里面ping FQDN ,clusterIP!=None 解析出的地址是 service的 clusterip,headless service 解析出来的地址是 pod ip
- 通过headless service 可以轻松找到statefulSet 的所有节点。特别是在部署集群的时候,很多服务需要配置节点信息来创建集群
- statefulSet.spec.serviceName:当serviceName 配置成与headless service的Name 相同的时候,可以通过 {hostName}.{service-name}.{namespace}.svc.cluster.local 解析出节点IP。hostName 由 {statefulSet name}-{编号} 组成