文章目錄
- 問題背景
- 1、什么是Headless Service
- 1.2 為什么 Zookeeper 使用 Headless Service?
- 1.2 Headless Service 的 DNS 行為
- 1.3 驗證示例
- 1.4 如何創建 Headless Service?
- 2. zk-0.zookeeper.default.svc.cluster.local 域名是如何創建出來的? 是無頭服務自動映射的嗎
問題背景
zookeeper ClusterIP None 這中svc作用是什么,為什么沒有cluster ip
1、什么是Headless Service
在 Kubernetes 中,ClusterIP 類型的 Service 被設置為 None(即 ClusterIP: None)時,表示這是一個 Headless Service(無頭服務)。這種設計有特定的用途和行為模式:
Headless Service 的核心作用:
-
直接訪問 Pod IP,跳過 Service 代理
-
普通 Service:會分配一個虛擬 ClusterIP,流量通過 kube-proxy 負載均衡到后端 Pod。
-
Headless Service:沒有 ClusterIP,DNS 查詢直接返回所有后端 Pod 的 IP 地址(而非 Service 的虛擬 IP)。
-
-
適用場景
-
有狀態應用(如 Zookeeper、Kafka、MongoDB):需要直接訪問特定 Pod(如通過 Pod 域名)。
-
自定義服務發現:應用需要自行處理負載均衡或直接連接 Pod。
-
StatefulSet 配套使用:StatefulSet 的 Pod 具有穩定的域名(如
pod-name.svc-name.namespace.svc.cluster.local
)。
1.2 為什么 Zookeeper 使用 Headless Service?
簡單來說,當一個pod 是sts
類型,每個副本的名稱,都是固定的(固定名稱是前提,不像deployment生成的pod都會帶隨機字符串 ),如 zk-0、zk-1,此時需要無頭服務,被訪問時,都是指定訪問,不能直接負載均衡隨機調度。
Zookeeper 是一個有狀態分布式協調服務,它的典型配置需求:
支持應用層的負載均衡或服務發現:
- 客戶端應用(或應用內置的邏輯)可以獲取到所有后端 Pod 的 IP 列表,然后自己決定如何連接(例如,輪詢、根據角色選擇 leader 等)。
- 對于像 ZooKeeper 這樣的集群,成員之間需要互相知道彼此的地址來形成集群,Headless Service 提供了完美的解決方案。
支持直接的 Pod-to-Pod 通信:
- 當你需要直接連接到某個特定的 Pod 實例時(比如訪問主節點進行寫操作,或進行健康檢查),可以通過其唯一的 DNS 名稱直接訪問。:
StatefulSet + Headless Service 能為每個 Pod 提供固定域名
。
1.2 Headless Service 的 DNS 行為
對于 Service zookeeper:
-
普通查詢(非 Headless):
nslookup zookeeper.mano-2.svc.cluster.local
返回一個虛擬 ClusterIP。
-
Headless 查詢:
nslookup zookeeper.mano-2.svc.cluster.local
返回所有后端 Pod 的 IP 地址(例如):
Name: zookeeper.mano-2.svc.cluster.local Address: 10.244.1.10 # zk-0 的 IP Address: 10.244.2.20 # zk-1 的 IP Address: 10.244.3.30 # zk-2 的 IP
如果您的 ZooKeeper StatefulSet 有 3 個副本,名為 zk-0, zk-1, zk-2,那么 DNS 會解析:
- zookeeper.default.svc.cluster.local -> 返回 zk-0, zk-1, zk-2 的 IP 地址列表(A 記錄)。
- zk-0.zookeeper.default.svc.cluster.local -> 返回 zk-0 Pod 的 IP 地址。
- zk-1.zookeeper.default.svc.cluster.local -> 返回 zk-1 Pod 的 IP 地址。
- zk-2.zookeeper.default.svc.cluster.local -> 返回 zk-2 Pod 的 IP 地址。
1.3 驗證示例
1、查看 Service 定義
kubectl get svc zookeeper -o yaml
輸出關鍵字段:
spec:clusterIP: None # 明確標記為 Headlessports:- port: 2181targetPort: 2181selector:app: zookeeper
2、通過 DNS 直接訪問 Pod
每個 StatefulSet 的 Pod 會獲得獨立域名:
# 查詢單個 Pod 的 DNS
nslookup zk-0.zookeeper.mano-2.svc.cluster.local# 客戶端連接示例(Zookeeper 客戶端)
zkCli.sh -server zk-0.zookeeper:2181,zk-1.zookeeper:2181,zk-2.zookeeper:2181
與普通 Service 的對比:
特性 | Headless Service | 普通 Service |
---|---|---|
ClusterIP | None | 自動分配虛擬 IP (如 10.96.x.x ) |
DNS 解析結果 | 返回所有 Pod IP | 返回 Service 的 ClusterIP |
負載均衡 | 由客戶端或應用層實現 | 由 kube-proxy 實現(iptables/IPVS) |
典型應用場景 | 有狀態服務(如 Zookeeper、MySQL) | 無狀態服務(如 Nginx、微服務) |
1.4 如何創建 Headless Service?
Headless 示例:
apiVersion: v1
kind: Service
metadata:name: zookeepernamespace: default
spec:clusterIP: None # 這是關鍵,指定為 Noneports:- port: 2181name: client- port: 2888name: server- port: 3888name: leader-electionselector:app: zookeeper # 選擇后端 Pod 的標簽# 注意:Headless Service 通常不指定 type,默認就是 ClusterIP
- clusterIP: None:這不是“不想要 IP”,而是明確地、主動地要求創建一個 Headless Service(無頭服務)。它告訴 Kubernetes:“我不要你為這個服務分配一個虛擬的 ClusterIP,我要直接訪問后端的 Pod”。
- 自動分配 ClusterIP:這是 Kubernetes Service 的默認行為。你不需要做任何特殊配置來“開啟”自動分配。
有頭示例:
apiVersion: v1
kind: Service
metadata:name: my-web-service
spec:# 注意:這里完全不寫 clusterIP 字段ports:- port: 80targetPort: 8080protocol: TCPname: httpselector:app: my-web-app# type: ClusterIP # type 字段也可以省略,默認就是 ClusterIP
當你創建這個 Service 時,Kubernetes 會:
- 自動從集群的 Service IP 池(由
--service-cluster-ip-range
參數定義)中選擇一個可用的 IP 地址。 - 將這個 IP 地址分配給該 Service。
- 你可以在 kubectl get svc 的輸出中看到這個分配的 IP(不再是 None)。
2. zk-0.zookeeper.default.svc.cluster.local 域名是如何創建出來的? 是無頭服務自動映射的嗎
是的,zk-0.zookeeper.default.svc.cluster.local 這個域名是由 Kubernetes 的 Headless Service(無頭服務)機制自動創建的,其核心原理依賴于 Kubernetes DNS 系統(如 CoreDNS)的自動服務發現功能。
下面簡述其工作原理:
1、 前提條件:Headless Service + StatefulSet
這個域名的自動生成,通常發生在以下組合中:
- 一個 Headless Service:clusterIP: None
- 一個 StatefulSet:管理有狀態應用的 Pod,如 zk-0, zk-1, zk-2
2、DNS 自動映射原理
當滿足上述條件時,Kubernetes DNS 組件(如 CoreDNS)會根據以下規則自動為每個 Pod 生成穩定的 DNS 記錄:
規則一:Pod 主機名 DNS 記錄
對于每一個由 StatefulSet 創建的 Pod(如 zk-0),DNS 會生成一條 A 記錄:
<pod-name>.<service-name>.<namespace>.svc.cluster.local --> <pod-ip>
在你的例子中:
pod-name = zk-0
service-name = zookeeper
namespace = default
cluster.local = 集群默認域名