已經看到如何使用Service來提供穩定IP,從而允許客戶端連接到服務後端的每個pod(或其他endpoint),打到Service的每個連線都會被轉發到隨機選擇的後端pod上。 但假如客戶端需要直接連接到所有的pod呢? 如果後端pod都需要連接到其它所有的後端pod呢? 透過Service連接顯然不是這樣做的。

要讓客戶端連接到所有pod,需要找出每個pod的IP。一種選擇是讓客戶端用k8s API獲取pod及其IP列表。但由於應該始終努力保持你的app跟k8s無關,因此使用k8s api並不理想。

k8s允許客戶端透過DNS查詢發現pod IP,通常,當執行服務的DNS查詢時,DNS server會返回單一IP(Service的clusterIP)。但是,如果告訴k8s不需要幫Service提供clusterIP (透過服務spec終將clusterIP設定為None來完成),則DNS將返回pod IP而不是單個服務IP。

DNS server不會返回單個DNS A record,而是會幫Service返回多個A record,每筆record指向Service後端的個別pod IP。因此客戶端可以做一個簡單的DNS A record查詢並獲得屬於該Service的一部分的所有pod IP。客戶端可以利用該資訊來連線到其中一個、多個或全部。

建立headless服務

將Service spec中的clusterIP設定為None會使Service成為headless,因為k8s將不會幫Service配置clusterIP,客戶端無法透過該IP將連線到服務後端的pod。 建立 kubia-svc-headless.yaml,如下:

apiVersion: v1
kind: Service
metadata:
  name: kubia-headless
spec:
  clusterIP: None        # 讓Service變成headless類型
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: kubia

部屬headless服務

[root@cp200 ch5]# kubectl create -f kubia-svc-headless.yaml
service/kubia-headless created

建立headless服務後,可以利用 kubectl getkubectl describe 查看服務,會發現沒有clusterIP,並且它的endpoint包含與pod選擇器匹配的(部分)pod。"部分"是因為pod包含就緒探針,所以只有準備就緒的pod會被列出來作為服務的endpoint。

目前3個pod中只有一個pod準備就緒,在利用以下指令,來確保有兩個pod準備就緒。

[root@cp200 ch5]# kubectl get po
NAME          READY   STATUS    RESTARTS   AGE
kubia-jtm2r   1/1     Running   0          12m
kubia-qlmwt   0/1     Running   0          12m
kubia-sk89x   0/1     Running   0          12m
[root@cp200 ch5]# kubectl exec kubia-qlmwt -- touch /var/ready
[root@cp200 ch5]# kubectl get po
NAME          READY   STATUS    RESTARTS   AGE
kubia-jtm2r   1/1     Running   0          13m
kubia-qlmwt   1/1     Running   0          13m
kubia-sk89x   0/1     Running   0          13m

透過DNS發現pod

現在需要建立一個可以執行dns查詢的pod(映像檔tutum/dnsutils有包含nslookup和dig工具),提供一個不透過YAML檔案來建立pod (這個pod裡面有包含可以使用nslookup的工具),使用以下指令單獨建立一個pod,如下:

[root@cp200 ch5]# kubectl run dnsutils --image=tutum/dnsutils --command -- sleep infinity
pod/dnsutils created

理解headless服務的DNS A record解析

使用剛建立的pod執行DNS查詢

kubectl exec dnsutils -- nslookup kubia-headless

DNS為 kubia-headless.default.svc.cluster.local FQDN返回幾個不同的IP。這些都是”準備就緒”的pod IP。可以透過使用 kubectl get pods -o wide 列出pod來確認全部的pod IP清單。 這跟常規的服務(非headless服務)返回的DNS不同,比如:kubia服務返回的IP是服務的clusterIP

[root@cp200 ch5]# kubectl exec dnsutils -- nslookup kubia-headless
Server:		10.96.0.10
Address:	10.96.0.10#53

Name:	kubia-headless.default.svc.cluster.local
Address: 10.244.141.248
Name:	kubia-headless.default.svc.cluster.local
Address: 10.244.172.249