1、Kubernetes中如何發(fā)現(xiàn)服務(wù)
- 發(fā)現(xiàn)Pod提供的服務(wù)
首先使用nginx-deployment.yaml文件創(chuàng)建一個Nginx Deployment儡炼,文件內(nèi)容如圖所示擎浴,首先創(chuàng)建兩個運行Nginx服務(wù)的Pod:
使用kubectl create -f nginx-deployment.yaml指令創(chuàng)建伦吠,這樣便可以得到兩個運行nginx服務(wù)的Pod虱疏。待Pod運行之后查看一下它們的IP惹骂,并在k8s集群內(nèi)通過podIP和containerPort來訪問Nginx服務(wù):
獲取Pod IP:
在集群內(nèi)訪問Nginx服務(wù):
看到這里相信很多人會有以下疑問:
1.每次收到獲取podIP太扯了,總不能每次都要手動改程序或者配置才能訪問服務(wù)吧做瞪,要怎么提前知道podIP呢对粪?
2.Pod在運行中可能會重建,IP變了怎么解装蓬?
- 如何在多個Pod中實現(xiàn)負載均衡嘞著拭?
這些問題使用k8s Service就可以解決。
-
使用Service發(fā)現(xiàn)服務(wù)
下面為兩個Nginx Pod創(chuàng)建一個Service牍帚。使用nginx-service.yaml文件進行創(chuàng)建儡遮,文件內(nèi)容如下:
創(chuàng)建之后,仍需要獲取Service的Cluster-IP暗赶,再結(jié)合Port訪問Nginx服務(wù)鄙币。
Service可以將pod IP封裝起來,即使Pod發(fā)生重建蹂随,依然可以通過Service來訪問Pod提供的服務(wù)十嘿。此外,Service還解決了負載均衡的問題岳锁,大家可以多訪問幾次Service详幽,然后通過kubectl logs <Pod Name>來查看兩個Nginx Pod的訪問日志來確認。
獲取IP:
在集群內(nèi)訪問Service:
雖然Service解決了Pod的服務(wù)發(fā)現(xiàn)和負載均衡問題浸锨,但存在著類似的問題:不提前知道Service的IP唇聘,還是需要改程序或配置啊≈眩看到這里有沒有感覺身體被掏空迟郎?
接下來聊聊kube-dns是如何解決上面這個問題的。
使用kube-dns發(fā)現(xiàn)服務(wù)
kube-dns可以解決Service的發(fā)現(xiàn)問題聪蘸,k8s將Service的名稱當做域名注冊到kube-dns中宪肖,通過Service的名稱就可以訪問其提供的服務(wù)。
可能有人會問如果集群中沒有部署kube-dns怎么辦健爬?沒關(guān)系控乾,實際上kube-dns插件只是運行在kube-system命名空間下的Pod,完全可以手動創(chuàng)建它娜遵⊥珊猓可以在k8s源碼(v1.2)的cluster/addons/dns目錄下找到兩個模板(skydns-rc.yaml.in和skydns-svc.yaml.in)來創(chuàng)建。
通過skydns-rc.yaml文件創(chuàng)建kube-dns Pod设拟,其中包含了四個containers慨仿,這里開始簡單過一下文件的主要部分久脯,稍后做詳細介紹。
第一部分可以看到kube-dns使用了RC來管理Pod镰吆,可以提供最基本的故障重啟功能帘撰。
創(chuàng)建kube-dns Pod,其中包含了4個containers
接下來是第一個容器 etcd 万皿,它的用途是保存DNS規(guī)則摧找。
第二個容器 kube2sky ,作用是寫入DNS規(guī)則牢硅。
第三個容器是 skydns 蹬耘,提供DNS解析服務(wù)。
最后一個容器是 healthz 唤衫,提供健康檢查功能婆赠。
有了Pod之后,還需要創(chuàng)建一個Service以便集群中的其他Pod訪問DNS查詢服務(wù)佳励。通過skydns-svc.yaml創(chuàng)建Service休里,內(nèi)容如下:
創(chuàng)建完kube-dns Pod和Service,并且Pod運行后赃承,便可以訪問kube-dns服務(wù)妙黍。
下面創(chuàng)建一個Pod,并在該Pod中訪問Nginx服務(wù):
創(chuàng)建之后等待kube-dns處于運行狀態(tài)
再新建一個Pod瞧剖,通過其訪問Nginx服務(wù)
在curl-util Pod中通過Service名稱訪問my-nginx Service:
只要知道需要的服務(wù)名稱就可以訪問拭嫁,使用kube-dns發(fā)現(xiàn)服務(wù)就是那么簡單。
雖然領(lǐng)略了使用kube-dns發(fā)現(xiàn)服務(wù)的便利性抓于,但相信有很多人也是一頭霧水:kube-dns到底怎么工作的做粤?在集群中啟用了kube-dns插件,怎么就能通過名稱訪問Service了呢捉撮?
2怕品、kube-dns原理
Kube-dns組成
之前已經(jīng)了解到kube-dns是由四個容器組成的,它們扮演的角色可以通過下面這張圖來理解巾遭。
其中:
SkyDNS是用于服務(wù)發(fā)現(xiàn)的開源框架肉康,構(gòu)建于etcd之上。作用是為kubernetes集群中的Pod提供DNS查詢接口灼舍。項目托管于https://github.com/skynetservices/skydns
etcd是一種開源的分布式key-value存儲吼和,其功能與ZooKeeper類似。在kube-dns中的作用為存儲SkyDNS需要的各種數(shù)據(jù)骑素,寫入方為kube2sky炫乓,讀取方為SkyDNS。項目托管于https://github.com/coreos/etcd。
exec-healthz是k8s提供的一種輔助容器厢岂,多用于side car模式中光督。它的原理是定期執(zhí)行指定的Linux指令阳距,從而判斷當前Pod中關(guān)鍵容器的健康狀態(tài)塔粒。在kube-dns中的作用就是通過nslookup指令檢查DNS查詢服務(wù)的健康狀態(tài),k8s livenessProbe通過訪問exec-healthz提供的Http API了解健康狀態(tài)筐摘,并在出現(xiàn)故障時重啟容器卒茬。其源碼位于https://github.com/kubernetes/contrib/tree/master/exec-healthz。
從圖中可以發(fā)現(xiàn)咖熟,Pod查詢DNS是通過ServiceName.Namespace子域名來查詢的圃酵,但在之前的示例中只用了Service名稱,什么原理呢馍管?其實當我們只使用Service名稱時會默認Namespace為default郭赐,而上面示例中的my-nginx Service就是在default Namespace中,因此是可以正常運行的确沸。關(guān)于這一點捌锭,后續(xù)再深入介紹。
skydns-rc.yaml中可以發(fā)現(xiàn)livenessProbe是設(shè)置在kube2sky容器中的罗捎,其意圖應(yīng)該是希望通過重啟kube2sky來重新寫入DNS規(guī)則观谦。
域名格式
其中cluster_domain可以使用kubelet的–cluster-domain=SomeDomain參數(shù)進行設(shè)置,同時也要保證kube2sky容器的啟動參數(shù)中–domain參數(shù)設(shè)置了相同的值桨菜。通常設(shè)置為cluster.local豁状。那么之前示例中的my-nginx Service對應(yīng)的完整域名就是my-nginx.default.svc.cluster.local〉沟茫看到這里泻红,相信很多人會有疑問,既然完整域名是這樣的霞掺,那為什么在Pod中只通過Service名稱和Namespace就能訪問Service呢谊路?下面來解釋其中原因。
配置
-
域名解析配置
為了在Pod中調(diào)用其他Service根悼,kubelet會自動在容器中創(chuàng)建域名解析配置(/etc/resolv.conf)凶异,內(nèi)容為:
感興趣的可以在網(wǎng)上查找一些resolv.conf的資料來了解具體的含義。之所以能夠通過Service名稱和Namespace就能訪問Service挤巡,就是因為search配置的規(guī)則剩彬。在解析域名時會自動拼接成完整域名去查詢DNS。
剛才提到的kubelet –cluster-domain參數(shù)與search的具體配置是相對應(yīng)的矿卑。而kube2sky容器的–domain參數(shù)影響的是寫入到etcd中的域名喉恋,kube2sky會獲取Service的名稱和Namespace,并使用–domain參數(shù)拼接完整域名。這也就是讓兩個參數(shù)保持一致的原因轻黑。
- NS相關(guān)配置
kube-dns可以讓Pod發(fā)現(xiàn)其他Service糊肤,那Pod又是如何自動發(fā)現(xiàn)kube-dns的呢?在上一節(jié)中的/etc/resolv.conf中可以看到nameserver氓鄙,這個配置就會告訴Pod去哪訪問域名解析服務(wù)器馆揉。

相應(yīng)的,可以在之前提到的skydns-svc.yaml中看到spec.clusterIP配置了相同的值抖拦。通常來說創(chuàng)建一個Service并不需要指定clusterIP升酣,k8s會自動為其分配,但kube-dns比較特殊态罪,需要指定clusterIP使其與/etc/resolv.conf中的nameserver保持一致噩茄。
修改nameserver配置同樣需要修改兩個地方,一個是kubelet的–cluster-dns參數(shù)复颈,另一個就是kube-dns Service的clusterIP绩聘。
總結(jié)
接下來重新梳理一下本文的主要內(nèi)容:
- 在k8s集群中,服務(wù)是運行在Pod中的耗啦,Pod的發(fā)現(xiàn)和副本間負載均衡是我們面臨的問題凿菩。
- 通過Service可以解決這兩個問題,但訪問Service也需要對應(yīng)的IP芹彬,因此又引入了Service發(fā)現(xiàn)的問題蓄髓。
- 得益于kube-dns插件,我們可以通過域名來訪問集群內(nèi)的Service舒帮,解決了Service發(fā)現(xiàn)的問題会喝。
- 為了讓Pod中的容器可以使用kube-dns來解析域名,k8s會修改容器的/etc/resolv.conf配置玩郊。
有了以上機制的保證肢执,就可以在Pod中通過Service名稱和namespace非常方便地訪問對應(yīng)的服務(wù)了。