Kubernetes(k8s)如何使用kube-dns實現服務發現
大綱:
-
Kubernetes中如何發現 服務
-
kube-dns原理
- 組成
- 域名格式
- 配置
注:本次分享內容基於Kubernetes 1.2版本!
下面從一個簡單的例子開始講解。
1、Kubernetes中如何發現服務
◆ 發現Pod提供的服務
首先使用nginx-deployment.yaml檔案建立一個Nginx Deployment,檔案內容如圖所示:
首先建立兩個執行Nginx服務的Pod:
使用kubectl create -f nginx-deployment.yaml指令建立,這樣便可以得到兩個執行nginx服務的Pod。待Pod執行之後檢視一下它們的IP,並在k8s叢集內通過podIP和containerPort來訪問Nginx服務:
獲取Pod IP:
在叢集內訪問Nginx服務:
看到這裡相信很多人會有以下疑問:
- 每次收到獲取podIP太扯了,總不能每次都要手動改程式或者配置才能訪問服務吧,要怎麼提前知道podIP呢?
- Pod在執行中可能會重建,IP變了怎麼解?
- 如何在多個Pod中實現負載均衡嘞?
這些問題使用k8s Service就可以解決。
◆ 使用Service發現服務
下面為兩個Nginx Pod建立一個Service。使用nginx-service.yaml檔案進行建立,檔案內容如下:
建立之後,仍需要獲取Service的Cluster-IP,再結合Port訪問Nginx服務。
Service可以將pod IP封裝起來,即使Pod發生重建,依然可以通過Service來訪問Pod提供的服務。此外,Service還解決了負載均衡的問題,大家可以多訪問幾次Service,然後通過kubectl logs <Pod Name>來檢視兩個Nginx Pod的訪問日誌來確認。
獲取IP:
在叢集內訪問Service:
雖然Service解決了Pod的服務發現和負載均衡問題,但存在著類似的問題:不提前知道Service的IP,還是需要改程式或配置啊。看到這裡有沒有感覺身體被掏空?
接下來聊聊kube-dns是如何解決上面這個問題的。
◆ 使用kube-dns發現服務
kube-dns可以解決Service的發現問題,k8s將Service的名稱當做域名註冊到kube-dns中,通過Service的名稱就可以訪問其提供的服務。
可能有人會問如果叢集中沒有部署kube-dns怎麼辦?沒關係,實際上kube-dns外掛只是執行在kube-system名稱空間下的Pod,完全可以手動建立它。可以在k8s原始碼(v1.2)的cluster/addons/dns目錄下找到兩個模板(skydns-rc.yaml.in和skydns-svc.yaml.in)來建立,為大家準備的完整示例檔案會在分享結束後提供獲取方式,PPT中只擷取了部分內容。
通過skydns-rc.yaml檔案建立kube-dns Pod,其中包含了四個containers,這裡開始簡單過一下檔案的主要部分,稍後做詳細介紹。
第一部分可以看到kube-dns使用了RC來管理Pod,可以提供最基本的故障重啟功能。
建立kube-dns Pod,其中包含了4個containers
接下來是第一個容器 etcd ,它的用途是儲存DNS規則。
第二個容器 kube2sky ,作用是寫入DNS規則。
第三個容器是 skydns ,提供DNS解析服務。
最後一個容器是 healthz ,提供健康檢查功能。
有了Pod之後,還需要建立一個Service以便叢集中的其他Pod訪問DNS查詢服務。通過skydns-svc.yaml建立Service,內容如下:
建立完kube-dns Pod和Service,並且Pod執行後,便可以訪問kube-dns服務。
下面建立一個Pod,並在該Pod中訪問Nginx服務:
建立之後等待kube-dns處於執行狀態
再新建一個Pod,通過其訪問Nginx服務
在curl-util Pod中通過Service名稱訪問my-nginx Service:
只要知道需要的服務名稱就可以訪問,使用kube-dns發現服務就是那麼簡單。
雖然領略了使用kube-dns發現服務的便利性,但相信有很多人也是一頭霧水:kube-dns到底怎麼工作的?在叢集中啟用了kube-dns外掛,怎麼就能通過名稱訪問Service了呢?
2、kube-dns原理
◆ Kube-dns組成
之前已經瞭解到kube-dns是由四個容器組成的,它們扮演的角色可以通過下面這張圖來理解。
其中:
- SkyDNS是用於服務發現的開源框架,構建於etcd之上。作用是為kubernetes叢集中的Pod提供DNS查詢介面。專案託管於https://github.com/skynetservices/skydns
- etcd是一種開源的分散式key-value儲存,其功能與ZooKeeper類似。在kube-dns中的作用為儲存SkyDNS需要的各種資料,寫入方為kube2sky,讀取方為SkyDNS。專案託管於https://github.com/coreos/etcd。
- kube2sky是k8s實現的一個適配程式,它通過名為kubernetes的Service(通過kubectl get svc可以檢視到該Service,由叢集自動建立)呼叫k8s的list和watch API來監聽k8s Service資源的變更,從而修改etcd中的SkyDNS記錄。程式碼可以在k8s原始碼(v1.2)的cluster/addons/dns/kube2sky/目錄中找到。
- exec-healthz是k8s提供的一種輔助容器,多用於side car模式中。它的原理是定期執行指定的Linux指令,從而判斷當前Pod中關鍵容器的健康狀態。在kube-dns中的作用就是通過nslookup指令檢查DNS查詢服務的健康狀態,k8s livenessProbe通過訪問exec-healthz提供的Http API瞭解健康狀態,並在出現故障時重啟容器。其原始碼位於https://github.com/kubernetes/contrib/tree/master/exec-healthz。
- 從圖中可以發現,Pod查詢DNS是通過ServiceName.Namespace子域名來查詢的,但在之前的示例中只用了Service名稱,什麼原理呢?其實當我們只使用Service名稱時會預設Namespace為default,而上面示例中的my-nginx Service就是在default Namespace中,因此是可以正常執行的。關於這一點,後續再深入介紹。
- skydns-rc.yaml中可以發現livenessProbe是設定在kube2sky容器中的,其意圖應該是希望通過重啟kube2sky來重新寫入DNS規則。
◆ 域名格式
接下來了解一下kube-dns支援的域名格式,具體為:<service_name>.<namespace>.svc.<cluster_domain>。
其中cluster_domain可以使用kubelet的–cluster-domain=SomeDomain引數進行設定,同時也要保證kube2sky容器的啟動引數中–domain引數設定了相同的值。通常設定為cluster.local。那麼之前示例中的my-nginx Service對應的完整域名就是my-nginx.default.svc.cluster.local。看到這裡,相信很多人會有疑問,既然完整域名是這樣的,那為什麼在Pod中只通過Service名稱和Namespace就能訪問Service呢?下面來解釋其中原因。
3、配置
◆ 域名解析配置
為了在Pod中呼叫其他Service,kubelet會自動在容器中建立域名解析配置(/etc/resolv.conf),內容為:
感興趣的可以在網上查詢一些resolv.conf的資料來了解具體的含義。之所以能夠通過Service名稱和Namespace就能訪問Service,就是因為search配置的規則。在解析域名時會自動拼接成完整域名去查詢DNS。
剛才提到的kubelet –cluster-domain引數與search的具體配置是相對應的。而kube2sky容器的–domain引數影響的是寫入到etcd中的域名,kube2sky會獲取Service的名稱和Namespace,並使用–domain引數拼接完整域名。這也就是讓兩個引數保持一致的原因。
◆ NS相關配置
kube-dns可以讓Pod發現其他Service,那Pod又是如何自動發現kube-dns的呢?在上一節中的/etc/resolv.conf中可以看到nameserver,這個配置就會告訴Pod去哪訪問域名解析伺服器。
相應的,可以在之前提到的skydns-svc.yaml中看到spec.clusterIP配置了相同的值。通常來說建立一個Service並不需要指定clusterIP,k8s會自動為其分配,但kube-dns比較特殊,需要指定clusterIP使其與/etc/resolv.conf中的nameserver保持一致。
修改nameserver配置同樣需要修改兩個地方,一個是kubelet的–cluster-dns引數,另一個就是kube-dns Service的clusterIP。
4、總結
接下來重新梳理一下本文的主要內容:
- 在k8s叢集中,服務是執行在Pod中的,Pod的發現和副本間負載均衡是我們面臨的問題。
- 通過Service可以解決這兩個問題,但訪問Service也需要對應的IP,因此又引入了Service發現的問題。
- 得益於kube-dns外掛,我們可以通過域名來訪問叢集內的Service,解決了Service發現的問題。
- 為了讓Pod中的容器可以使用kube-dns來解析域名,k8s會修改容器的/etc/resolv.conf配置。
有了以上機制的保證,就可以在Pod中通過Service名稱和namespace非常方便地訪問對應的服務了。
本文轉自開源中國-Kubernetes(k8s)如何使用kube-dns實現服務發現
相關文章
- Spring Cloud Kubernetes服務發現SpringCloud
- prometheus k8s服務發現PrometheusK8S
- Docker實現服務發現Docker
- etcd實現服務發現
- NodeJs服務註冊與服務發現實現NodeJS
- Kubernetes基於haproxy實現ingress服務暴露
- Prometheus服務發現之kubernetes_sd_configPrometheus
- k8s 服務發現控制器K8S
- 服務發現-從原理到實現
- Zookeeper實現服務註冊/發現
- Kubernetes(K8s)部署 SpringCloud 服務實戰K8SSpringGCCloud
- kubernetes實踐之九:kube-dnsDNS
- 實現etcd服務註冊與發現
- Eureka實現服務註冊與發現
- 如何實現Spark on Kubernetes?Spark
- 如何實現高效地IT服務管理
- Nodejs 使用 ZooKeeper 做服務發現NodeJS
- 用 etcd 實現服務註冊和發現
- .NET Core HttpClientFactory+Consul實現服務發現HTTPclient
- 實現Kubernetes跨叢集服務應用的高可用
- Kubernetes如何實現DNS解析DNS
- NGINX如何實現rtmp推流服務Nginx
- Go | Go 使用 consul 做服務發現Go
- SpringCloudAlibaba - 整合 Nacos 實現服務註冊與發現SpringGCCloud
- 服務註冊與發現的原理和實現
- Spring Cloud Eureka 實現服務註冊與發現SpringCloud
- confd+etcd+nginx 實現簡單服務發現Nginx
- Dubbo+Nacos實現服務註冊和發現
- Spring Cloud Alibaba基礎教程:使用Nacos實現服務註冊與發現SpringCloud
- [翻譯]微服務設計模式 - 5. 服務發現 - 服務端服務發現微服務設計模式服務端
- 基於Kubernetes服務發現機制的探討Non Service
- 如何使用Node.js、TypeScript和Express實現RESTful API服務Node.jsTypeScriptExpressRESTAPI
- Java使用HttpClient實現遠端服務呼叫JavaHTTPclient
- 使用Istio服務網格實現流量映象
- 服務型企業如何使用飛項實現專案化管理?
- 2-服務發現
- 如何發現 Kubernetes 中服務和工作負載的異常負載
- Kubernetes 服務部署最佳實踐(二) ——如何提高服務可用性