己經看到如何使用服務來提供穩定的ip地址,從而允許客戶端連接到支持服務的每個pod (或其他端點)。到服務的每個連接都被轉發到一個隨機選擇的pod上。但是如果客戶端需要鏈接到所有的pod呢?如果后端的pod都需要連接到所有其他 pod呢?通過服務連接顯然不是這樣的,那是怎樣的呢?
要讓客戶端連接到所有pod,需要找出每個pod的IP。一種選擇是讓客戶端調用Kubernetes API服務器並通過API調用獲取pod及其IP地址列表,但由於應始終努力保持應用程序與Kubernetes無關,因此使用API服務器並不理想。
幸運的是,Kubernetes允許客戶通過DNS查找發現pod IP。通常,當執行服務的DNS查找時,DNS服務器會返回單個IP——服務的集群IP。但是,如果告訴 Kubernetes,不需要為服務提供集群IP (通過在服務spec中將clusterIP字段設置為None來完成此操作),則DNS服務器將返回podIP而不是單個服務IP。
DNS服務器不會返回單個DNS A記錄,而是會為該服務返回多個A記錄,每個記錄指向當時支持該服務的單個pod的IP。客戶端因此可以做一個簡單的DNS A 記錄查找並獲取屬於該服務一部分的所有pod的IP。客戶端可以使用該信息連接到其中的一個、多個或全部。
1.創建headless服務
將服務spec中的clusterIP字段設置為None會使服務成為headless服務,因為Kubernetes不會為其分配集群IP,客戶端可通過該IP將其連接到支持它的pod。
現在將創建一個名為kubia-headless的headless服務。以下代碼清單顯示了它的定義。
apiVersion: v1 kind: Service metadata: name: kubia-headless spec: clusterIP: None #這使得服務成為headless ports: - port: 80 targetPort: 8080 selector: app: kubia
在使用kubectl create創建服務之后,可以通過kubectl get和kubectl describe來查看服務,你會發現它沒有集群IP,並且它的后端包含與pod選擇器匹配的(部分)pod。“部分”是因為pod包含就緒探針,所以只有准備就緒的pod會被列出作為服務的后端文件來確保至少有兩個pod報告己准備就緒。
2.通過DNS發現pod
准備好pod后,現在可以嘗試執行DNS查找以查看是否獲得了實際的pod IP。需要從其中一個pod中執行查找。不幸的是,kubia容器鏡像不包含nslookup(或dig)二進制文件,因此無法使它執行DNS查找。
所要做的就是在集群中運行的一個pod中執行DNS查詢。為什么不尋找一個包含所需二進制文件的鏡像來運行新的容器?要執行與DNS相關的操作,可以使用Docker Hub上提供的tutum/dnsutils容器鏡像,它包含nslookup和dig二進制文件。要運行pod,可以完成創建YAML清單並將其傳給kubectl create的整個過程。但是太煩瑣了,對嗎?幸運的是,有一個更快的方法。
不通過YAML文件運行pod
使用kubectl run是這次只想創建一個pod,不需要創建一個ReplicationController來管理pod。可以這樣做:
$ kubectl run dnsutils --image=tutum/dnsutils --generator=run-pod/v1 --command -- sleep infinity pod "dnsutils" created
訣竅在--generator=run-pod/vl選項中,該選項讓kubectl直接創建 pod,而不需要通過ReplicationController之類的資源來創建。
理解headless服務的DNSA記錄解析
使用新創建的pod執行DNS查找:
$ kubectl exec dnsutils nslookup kubia-headless Name: kubia-headless.default.svc.cluster.local Address: 10.108.1.4 Name: kubia-headless.default.svc.cluster.local Address: 10.108.2.5
DNS服務器為kubia-headless.default.svc.cluster.local FQDN返回兩個不同的IP。這些是報告准備就緒的兩個pod的IP。可以通過使用kubectl get pods -o wide列出pod來確認此問題,該清單顯示了pod的IP。
這與常規(非headless服務)服務返回的DNS不同,比如kubia服務,返回的IP是服務的集群IP。(這里就不做代碼演示了)
盡管headless服務看起來可能與常規服務不同,但在客戶的視角上它們並無不同。即使使用headless服務,客戶也可以通過連接到服務的DNS名稱來連接到pod上,就像使用常規服務一樣。但是對於headless服務,由於DNS返回了pod的IP, 客戶端直接連接到該pod,而不是通過服務代理。
注意:headless服務仍然提供跨pod的負載平衡,但是通過DNS輪詢機制不是
3.發現所有的pod--包括未就緒的pod
只有准備就緒的pod能夠作為服務的后端。但有時希望即使pod沒有准備就緒,服務發現機制也能夠發現所有匹配服務標簽選擇器的pod。
幸運的是,不必通過查詢KubernetesAPI服務器,可以使用DNS查找機制來查找那些未准備好的pod。要告訴Kubernetes無論pod的准備狀態如何,希望將所有pod添加到服務中。必須將以下注解添加到服務中:
kind: Service metadata: annotations: service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
警告: 就像說的那樣,注解名稱表明了這是一個alpha功能。KubernetesService API己經支持一個名為publishNotReadyAddresses的新服務規范字段,它將替換tolerate-unready-endpoints注解。在Kubernetes1.9.0版本中,這個字段還沒有實現(這個注解決定了未准備好的endpoints是否在DNS的記錄中)。檢查文檔以查看是否己更改。