Kubernetes如何使用kube-dns實現服務發現

大綱:nginx

•       Kubernetes中如何發現服務git

•       如何發現Pod提供的服務github

•       如何使用Service發現服務服務器

•       如何使用kube-dns發現服務負載均衡

•       kube-dns原理框架

•       組成dom

•       域名格式curl

•       配置分佈式

注:本次分享內容基於Kubernetes 1.2版本!ide

下面從一個簡單的例子開始講解。

1.Kubernetes中如何發現服務

◆   發現Pod提供的服務

首先使用nginx-deployment.yaml文件建立一個Nginx Deployment,文件內容如圖所示:

首先建立兩個運行Nginx服務的Pod:

1

使用kubectl create -f nginx-deployment.yaml指令建立,這樣即可以獲得兩個運行nginx服務的Pod。待Pod運行以後查看一下它們的IP,並在k8s集羣內經過podIP和containerPort來訪問Nginx服務:

獲取Pod IP:

2

在集羣內訪問Nginx服務:

3

看到這裏相信不少人會有如下疑問:

1.  每次收到獲取podIP太扯了,總不能每次都要手動改程序或者配置才能訪問服務吧,要怎麼提早知道podIP呢?

2.  Pod在運行中可能會重建,IP變了怎麼解?

3.  如何在多個Pod中實現負載均衡嘞?

這些問題使用k8s Service就能夠解決。

◆   使用Service發現服務

下面爲兩個Nginx Pod建立一個Service。使用nginx-service.yaml文件進行建立,文件內容以下:

4

建立以後,仍須要獲取Service的Cluster-IP,再結合Port訪問Nginx服務。

Service能夠將pod  IP封裝起來,即便Pod發生重建,依然能夠經過Service來訪問Pod提供的服務。此外,Service還解決了負載均衡的問題,你們能夠多訪問幾回Service,而後經過kubectl logs <Pod Name>來查看兩個Nginx Pod的訪問日誌來確認。

獲取IP:

5

在集羣內訪問Service:

6

雖然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

7

接下來是第一個容器  etcd  ,它的用途是保存DNS規則。

8

第二個容器  kube2sky ,做用是寫入DNS規則。

9

第三個容器是  skydns ,提供DNS解析服務。

10

最後一個容器是  healthz ,提供健康檢查功能。

11

有了Pod以後,還須要建立一個Service以便集羣中的其餘Pod訪問DNS查詢服務。經過skydns-svc.yaml建立Service,內容以下:

12

建立完kube-dns Pod和Service,而且Pod運行後,即可以訪問kube-dns服務。

下面建立一個Pod,並在該Pod中訪問Nginx服務:

建立以後等待kube-dns處於運行狀態

13

再新建一個Pod,經過其訪問Nginx服務

14

在curl-util Pod中經過Service名稱訪問my-nginx Service:

15

只要知道須要的服務名稱就能夠訪問,使用kube-dns發現服務就是那麼簡單。

雖然領略了使用kube-dns發現服務的便利性,但相信有不少人也是一頭霧水:kube-dns到底怎麼工做的?在集羣中啓用了kube-dns插件,怎麼就能經過名稱訪問Service了呢?

2.kube-dns原理

◆   Kube-dns組成

以前已經瞭解到kube-dns是由四個容器組成的,它們扮演的角色能夠經過下面這張圖來理解。

kube-dns%e6%9e%b6%e6%9e%84

其中:

●  SkyDNS是用於服務發現的開源框架,構建於etcd之上。做用是爲k8s集羣中的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),內容爲:

16

感興趣的能夠在網上查找一些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去哪訪問域名解析服務器。

17

相應的,能夠在以前提到的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很是方便地訪問對應的服務了。

5.Q&A

1. 問: 請問若是公司已有的應用接入的話,那麼現有的沒有接入的應用就沒法訪問了,由於這個服務發現是k8s集羣內部的,外部沒法訪問。主要是k8s集羣內的服務和集羣外的己有的生產的域名訪問如何實現,能在kube-dns整合嗎?

答:兩個問題能夠抽象爲k8s集羣內與集羣外服務連通性問題,咱們從兩個方面講:

1、集羣內訪問集羣外

這個問題比較簡單,集羣內的Pod會繼承Node上的DNS解析規則。所以只要Node能夠訪問的服務,Pod中也能夠訪問到。

另外,在1.4版本中,k8s支持了一種ExternalName類型的Service,能夠與一個公網域名綁定,經過該Service能夠訪問對應公網服務。

2、集羣外訪問集羣內

1. 能夠將Service設置爲NodePort類型,這樣經過任意Node的IP和Service Port即可以訪問Service。適合對外的Service比較少的場景。

2. 經過kube-proxy能夠對外暴露集羣內的服務。

3. 根據實際狀況在集羣內自定義實現反向代理。

2. 問:我想問下etcd這個容器能夠省掉嗎?k8s集羣有etcd不能夠共用嗎?

答:理論上能夠共用etcd。從隔離性的角度考慮來講仍是分開好,這樣kube-dns服務不會對整個k8s集羣的穩定性產生影響。另外若是把kube-dns看作一個微服務的話,那麼應該保證內部組件不依賴外部,能夠獨立運行。

相關文章
相關標籤/搜索