Kube-dns組成nginx
kube-dns能夠解決Service的發現問題,k8s將Service的名稱當作域名註冊到kube-dns中,經過Service的名稱就能夠訪問其提供的服務。git
kube-dns四個組件:
github
etcd,它的用途是保存DNS規則。
服務器
kube2sky,做用是寫入DNS規則。負載均衡
skydns,提供DNS解析服務。框架
healthz,提供健康檢查功能。dom
以前已經瞭解到kube-dns是由四個容器組成的,它們扮演的角色能夠經過下面這張圖來理解。分佈式
其中:ide
SkyDNS是用於服務發現的開源框架,構建於etcd之上。做用是爲k8s集羣中的Pod提供DNS查詢接口。項目託管於https://github.com/skynetservices/skydnsspa
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呢?下面來解釋其中緣由。
配置
域名解析配置
爲了在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。
總結
接下來從新梳理一下本文的主要內容。
在k8s集羣中,服務是運行在Pod中的,Pod的發現和副本間負載均衡是咱們面臨的問題。
經過Service能夠解決這兩個問題,但訪問Service也須要對應的IP,所以又引入了Service發現的問題。
得益於kube-dns插件,咱們能夠經過域名來訪問集羣內的Service,解決了Service發現的問題。
爲了讓Pod中的容器可使用kube-dns來解析域名,k8s會修改容器的/etc/resolv.conf配置。
有了以上機制的保證,就能夠在Pod中經過Service名稱和namespace很是方便地訪問對應的服務了。