Kubernetes中的Headless Services(無頭服務)是一種特殊類型的服務(Service)定義,它不提供傳統意義上的負載均衡和集群IP地址分配。在無頭服務中,spec.clusterIP 字段被顯式設置為None ,Kubernetes不會為該服務分配一個虛擬IP(ClusterIP)地址。
一、無頭服務的特點
-
沒有Cluster IP:不分配Cluster IP,客戶端不能通過服務的Cluster IP地址訪問后端Pod,而是直接通過Pod的具體地址進行通信。
-
直接使用DNS解析:Kubernetes的DNS系統會為無頭服務生成一條特殊的DNS記錄,這條記錄列出所有關聯Pod的IP地址,允許客戶端通過域名解析直接獲得Pod列表,進而實現自定義的負載均衡或服務發現邏輯。
-
適用于狀態服務應用:特別適合那些需要直接與特定實例通信的應用場景,如分布式數據庫、消息隊列等有狀態服務,因為這些服務往往需要客戶端直接與服務實例建立會話或維持連接狀態。
二、headless Service和普通Service的區別
-
headless不分配clusterIP
-
headless service可以通過解析service的DNS,返回所有Pod的地址
-
普通的service,只能通過解析service的DNS返回service的ClusterIP。client訪問ClusterIP,通過iptables或者ipvs轉發到Real Server(Pod)
三、無頭服務應用場景
-
有狀態應用(StatefulSet):在部署有狀態應用時,如分布式數據庫集群(如Zookeeper、MySQL等),需要客戶端直接訪問特定節點,而不是通過負載均衡隨機分配。比如MongoDB副本集,需要每個節點直接相互通信或客戶端直接訪問特定節點。比如Zookeeper、etcd集群,節點間需要相互發現并建立連接。
-
服務發現與自定義負載均衡:當應用需要實現自定義的負載均衡算法或服務發現邏輯時,無頭服務允許應用直接與后端Pod列表交互,便于實現更精細的控制邏輯。
-
Session親和性:對于需要維護會話狀態的應用,使用無頭服務可以直接指向會話所屬的Pod,確保會話的一致性。
四、實驗測試
- 普通的service
[root@node1 ~]# kubectl get po -n test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-5977dc5756-ksff2 1/1 Running 0 22h 172.16.28.42 node3 <none> <none>
test-5977dc5756-vrbg2 1/1 Running 0 22h 172.16.154.23 node1 <none> <none>
test-5977dc5756-zgw4c 1/1 Running 0 22h 172.16.44.33 node2 <none> <none>
[root@node1 ~]# kubectl get svc -n test
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-svc ClusterIP 10.233.23.79 <none> 80/TCP 19d
[root@node1 ~]#
[root@node1 ~]# kubectl get endpoints -n test
NAME ENDPOINTS AGE
nginx-svc 172.16.154.23:80,172.16.28.42:80,172.16.44.33:80 19d
[root@node1 ~]# 我們在物理機使用dig指定coredns 地址進行解析svc,如下:
[root@node1 ~]# dig @10.233.0.3 nginx-svc.test.svc.test.com; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.13 <<>> @10.233.0.3 nginx-svc.test.svc.test.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1089
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;nginx-svc.test.svc.test.com. IN A;; ANSWER SECTION:
nginx-svc.test.svc.test.com. 30 IN A 10.233.23.79 ###此處得知返回結果為cluster ip;; Query time: 1 msec
;; SERVER: 10.233.0.3#53(10.233.0.3)
;; WHEN: Thu May 09 14:42:27 CST 2024
;; MSG SIZE rcvd: 99
- headless service
[root@node1 ~]# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
maradb-0 1/1 Running 0 22h 172.16.44.32 node2 <none> <none>
maradb-1 1/1 Running 0 22h 172.16.28.44 node3 <none> <none>
maradb-2 1/1 Running 0 21h 172.16.154.25 node1 <none> <none>
[root@node1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 396d
mariadb ClusterIP None <none> 3306/TCP 22h我們在物理機使用dig指定coredns 地址進行解析svc,如下:
[root@node1 ~]# dig @10.233.0.3 mariadb.default.svc.test.com; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.13 <<>> @10.233.0.3 mariadb.default.svc.test.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35068
;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;mariadb.default.svc.test.com. IN A;; ANSWER SECTION:
mariadb.default.svc.test.com. 30 IN A 172.16.28.44 ##此處得知返回的結果為pod的真實地址
mariadb.default.svc.test.com. 30 IN A 172.16.154.25
mariadb.default.svc.test.com. 30 IN A 172.16.44.32;; Query time: 1 msec
;; SERVER: 10.233.0.3#53(10.233.0.3)
;; WHEN: Thu May 09 14:27:43 CST 2024
;; MSG SIZE rcvd: 189
五、使用無頭服務的好處
-
簡化服務發現:通過DNS記錄直接提供Pod列表,簡化了服務發現過程,特別是對于需要直接與各個實例交互的應用。
-
增強控制靈活性:允許應用層決定如何分配請求到各個Pod,適應特定的業務邏輯或性能需求。
-
支持有狀態應用部署:更好地匹配有狀態應用的部署需求,確保數據的一致性和可靠性。
-
減少網絡跳轉:去除了一層負載均衡,減少了網絡延遲,提高了通信效率。
使用無頭服務是為了在某些特定場景下,繞過Kubernetes的常規服務代理和負載均衡機制,以實現更直接、更靈活的服務實例訪問方式,特別是在需要保持會話狀態、實現自定義負載策略或部署有狀態應用的場景中。這種方式提供了更高的靈活性和對底層基礎設施的直接控制能力。