×

靈魂拷問(wèn)x8:關(guān)于K8S Pod通信和DNS那些事兒!

分類(lèi):域名資訊 編輯:小新 瀏覽量:9
2020-07-10 11:21:32

在一些項(xiàng)目和技術(shù)交流中,發(fā)現(xiàn)很多朋友對(duì)OCP pod通信機(jī)制和OCP中的DNS犯懵。我專(zhuān)門(mén)寫(xiě)一篇進(jìn)行分析。

本文中大量?jī)?nèi)容和K8S是相通的,文中也直接大量使用了K8S的概念,因此本文題目起的是K8S。OCP=OpenShift Container Platform,OCP內(nèi)部的SDN用的是OVS。

我們以反問(wèn)的方式進(jìn)行“靈魂拷問(wèn)”

拷問(wèn)1. OCP中pod之間通訊是否一定需要service?

不需要。

沒(méi)有service,pod能通信,而且好好的,如下圖所示。

在一個(gè)namespace里(因?yàn)橛衝etworkpolicy,因此先做這個(gè)假設(shè)),只要指定的端口是pod開(kāi)放的端口,在一個(gè)pod中,curl另外一個(gè)pod,就絕對(duì)能通。pod之間能不能通和倆pod跨不跨service,有沒(méi)有service,沒(méi)半毛錢(qián)關(guān)系。

拷問(wèn)2. 從一個(gè)pod curl另外一個(gè)pod+端口號(hào)能通這件事,背后的鏈路機(jī)制是什么?

(1)倆pod在一個(gè)節(jié)點(diǎn)上,鏈路如下,流量沒(méi)有繞出本宿主機(jī)的ovs:

Pod 1的eth0 → vethxx → br0 → vethyy → Pod 2的eth0

(2).倆pod在不同node上,鏈路如下,pod之間的通訊經(jīng)過(guò)了vxlan:

Pod 1的eth0 → vethxx → br0 → vxlan0 → host1 eth0(192.168.1.101)→ network → host2 eth0(192.168.1.102)→ vxlan0 → br0 → vethmm → Pod 3的eth0

也就是說(shuō),截止到目前,我們把倆pod之間的通訊機(jī)制,簡(jiǎn)單介紹了。這里面沒(méi)service啥事,這點(diǎn)記住。還需要記住的是,這是OCP集群中,pod之間通訊的實(shí)際數(shù)據(jù)鏈路(和后面service尋址對(duì)應(yīng))。

拷問(wèn)3:我們都知道K8S service的基本概念,說(shuō)說(shuō)為啥K8S需要它?

我們首先要明確:Service是對(duì)一組提供相同功能的Pods的抽象,并為它們提供一個(gè)統(tǒng)一的內(nèi)部訪(fǎng)問(wèn)入口。它主要解決:

1.負(fù)載均衡(這個(gè)大家會(huì)最先想到)。

2.服務(wù)注冊(cè)與發(fā)現(xiàn):解決不同服務(wù)之間的通信問(wèn)題。在OpenShift中的創(chuàng)建應(yīng)用后,需要提供訪(fǎng)問(wèn)應(yīng)用的地址供其他服務(wù)調(diào)用,這個(gè)地址就是由Service提供。

每創(chuàng)建一個(gè)Service會(huì)分配一個(gè)ServiceIP地址,稱(chēng)為ClusterIP,這個(gè)IP地址是一個(gè)虛擬的地址,無(wú)法執(zhí)行ping操作。同時(shí)自動(dòng)在內(nèi)部DNS注冊(cè)一條對(duì)應(yīng)的A記錄(A記錄很重要,后面展開(kāi)說(shuō)),這就完成了服務(wù)注冊(cè),注冊(cè)信息全部保存在Etcd中。

拷問(wèn)4:詳細(xì)說(shuō)說(shuō)服務(wù)注冊(cè)到底向etcd里注冊(cè)了啥?

注冊(cè)到etcd的,實(shí)際上是service yaml的先關(guān)內(nèi)容。

我們查看etcd中router service 的內(nèi)容。我們看到了什么?

service name、namespace、service ip、port number的,以及對(duì)應(yīng)的endpoints等很多信息。

也就是說(shuō),etcd里有namespace,service name,service ip等,

通過(guò)這三個(gè)信息就可組成DNS A記錄,也就是,service的FQDN和service ip之間的對(duì)應(yīng)關(guān)系。但需要說(shuō)明的是,etcd不是DNS!DNS A記錄是通過(guò)查詢(xún)生成的!OCP的DNS是由SkyDNS/CoreDNS實(shí)現(xiàn)的,這個(gè)后面說(shuō)。

我們?cè)僬f(shuō)說(shuō)服務(wù)發(fā)現(xiàn)。

服務(wù)發(fā)現(xiàn)這個(gè)詞經(jīng)常被妖魔化。我們把字換個(gè)順序,就好理解:發(fā)現(xiàn)服務(wù)。也就說(shuō),service A要和serviceB通訊,我得知道serviceB是誰(shuí)、在哪、service IP、pod ip都是啥?這就叫服務(wù)發(fā)現(xiàn)。

拷問(wèn)5:有了servcice以后,pod之間的通訊和沒(méi)有service有啥區(qū)別?

在數(shù)據(jù)通訊層,沒(méi)區(qū)別!因?yàn)閟ervice只是邏輯層面的東西。

但是,沒(méi)有service,K8S是無(wú)法控制pod之間的通訊的,也無(wú)法為pod之間進(jìn)行尋址。也就是說(shuō),沒(méi)有service,pod之間的通訊,就不會(huì)和K8S發(fā)生任何關(guān)系,和自己在筆記本linux中裝起兩容器ping著玩,沒(méi)太大區(qū)別(在網(wǎng)絡(luò)層)。

有了service以后,pod之間怎么尋址?

回答這個(gè)問(wèn)題,我們要站在開(kāi)發(fā)者角度。如果一個(gè)程序員,要寫(xiě)微服務(wù),微服務(wù)之間要相互調(diào)用,怎么寫(xiě)?寫(xiě) pod IP和service ip都不靠譜吧,你都不知道IP地址會(huì)是啥。

如果程序員決定用k8s做服務(wù)發(fā)現(xiàn)的前提下寫(xiě)服務(wù)之間的調(diào)用(如果使用spring cloud,那就用它的服務(wù)注冊(cè)中心做解析,也就不必用K8S的service了),那么就得寫(xiě)K8S的service名稱(chēng)!

因?yàn)閟ervice名稱(chēng)我們是可以固定的。

K8S中service有短名和長(zhǎng)名。

以下圖為例,jws-app就是service的短名,service的長(zhǎng)名是:..svc.cluser.local,也就是jws-app.web.svc.cluser.local。service短名可以自動(dòng)補(bǔ)充成長(zhǎng)名,這是OCP中的DNS做的,這個(gè)后面說(shuō)。

那么,這時(shí)候大魏也有個(gè)疑問(wèn)了。如果在兩個(gè)不同的namespace中,有兩個(gè)相同的service短名,微服務(wù)調(diào)用不是會(huì)出現(xiàn)混亂?程序員的代碼里是不是要寫(xiě)service全名?

不能說(shuō)想法不對(duì),但一般不這樣干。

首先,站在OCP集群cluster-admin的角度,我們看所有的項(xiàng)目,有幾十個(gè)或者而更多,會(huì)覺(jué)得在不同namespaces中起相同的service短名是可能(比如namespace A中有個(gè)acat的service,namespace B中也有個(gè)acat的service)。但站在程序員角度,他只是OCP的使用者,他有自己的namespace,他能訪(fǎng)問(wèn)的namespace很有限,可能就1個(gè)。絕大多數(shù)情況下,同一個(gè)業(yè)務(wù)項(xiàng)目的微服務(wù)一般會(huì)運(yùn)行在同一個(gè)namespace中,默認(rèn)如果使用短名稱(chēng)(只寫(xiě)service name),則會(huì)自動(dòng)補(bǔ)全成當(dāng)前namespace的FQDN,只有在跨namespace調(diào)用的時(shí)候才必須寫(xiě)全名FQDN。

所以,程序員寫(xiě)的程序,用到了K8S service name,那么,真正跑應(yīng)用的pod之間的通訊,也必然會(huì)以service name去找。通過(guò)service名稱(chēng)找到service ip,然后最終找到pod ip(一個(gè)service可能多個(gè)pod,從service ip到pod ip的負(fù)載均衡實(shí)現(xiàn)后面講)。找到pod的ip以后,接下來(lái)實(shí)際的數(shù)據(jù)交換,就和拷問(wèn)2講述機(jī)制就接上頭了。

拷問(wèn)6. 我們知道Service的作用了,那從service ip到pod ip這段的負(fù)載均衡怎么實(shí)現(xiàn)的?

K8S中通過(guò)service name做服務(wù)發(fā)現(xiàn),首選短名會(huì)自動(dòng)自動(dòng)擴(kuò)展成FQDN,然后解析成service ip,然后再走kube-proxy負(fù)載均衡倒pod ip。

Service的負(fù)載均衡可以由很多的實(shí)現(xiàn)方式,目前Kubernetes官方提供了三種代理模式:userspace、iptables、ipvs。目前版本OpenShift默認(rèn)的代理模式是iptables

從圖中可以看出,當(dāng)客戶(hù)端訪(fǎng)問(wèn)Servcie的ClusterIP時(shí),由Iptables實(shí)現(xiàn)負(fù)載均衡,選擇一個(gè)后端處理請(qǐng)求,默認(rèn)的負(fù)載均衡策略是輪詢(xún)。在這種模式下,每創(chuàng)建一個(gè)Service,會(huì)自動(dòng)匹配后端實(shí)例Pod記錄在Endpoints對(duì)象中,并在所有Node節(jié)點(diǎn)上添加相應(yīng)的iptables規(guī)則,將訪(fǎng)問(wèn)該Service的ClusterIP與Port的連接重定向到Endpoints中的某一個(gè)后端Pod,由于篇幅有限,關(guān)于負(fù)載均衡實(shí)現(xiàn)的細(xì)節(jié)不再贅述。

這種模式有兩個(gè)缺點(diǎn)需要關(guān)注:第一,不支持復(fù)雜的負(fù)載均衡算法;第二,當(dāng)選擇的某個(gè)后端Pod沒(méi)有響應(yīng)時(shí),無(wú)法自動(dòng)重新連接到另一個(gè)Pod,用戶(hù)必須利用Pod的健康監(jiān)測(cè)來(lái)保證Endpoints列表中Pod都是存活的(也就是說(shuō),生產(chǎn)上你最好把liveness和rediness配上。)。

對(duì)于OCP而言,每個(gè)節(jié)點(diǎn)上都有iptables。而iptables之前的通訊和同步,是通過(guò)每個(gè)節(jié)點(diǎn)的kube-proxy實(shí)現(xiàn)的(這個(gè)進(jìn)程在sdn pod中運(yùn)行。想詳細(xì)研究的可以看我前兩天寫(xiě)的文章: 深度解析:kube-proxy在OpenShift上的實(shí)現(xiàn))

拷問(wèn)7. 我記得iptables不是做防火墻的么?

OCP中的iptables,主要目的做的是service ip和pod ip鏈路的事情。一般不涉及常規(guī)意義上的防火墻規(guī)則的INPUT/OUTPUT ACCEPT/DENY。也就是說(shuō),不要嘗試自己ssh到OCP4節(jié)點(diǎn)上通過(guò)iptables做安全規(guī)則,不是這樣玩的。

拷問(wèn)8. 前面7個(gè)問(wèn)題清楚了,說(shuō)說(shuō)OCP的DNS機(jī)制吧。

首先,OCP3和OCP4的DNS機(jī)制是不同的。

OpenShift 3內(nèi)置的是SkyDNS,SkyDNS會(huì)監(jiān)測(cè)Kubernetes API,當(dāng)新創(chuàng)建一個(gè)Service,SkyDNS中就會(huì)提供..svc.cluster.local域名的解析。除了解析Service,還可以通過(guò)..endpoints.cluster.local解析endpoints。

例如,如果 myproject 服務(wù)中存在 myapi 服務(wù),則整個(gè)OpenShift集群中的所有Pod都可以解析 myapi.myproject.svc.cluster.local 主機(jī)名以獲取Service ClusterIP地址。除此之外,OpenShift DNS還提供以下兩種短域名

在簡(jiǎn)單了解了SkyDNS的機(jī)制之后,我們來(lái)看看OpenShift3是如何使用和配置DNS的。為了便于理解,我們用下圖來(lái)進(jìn)行說(shuō)明。

上圖表示了OpenShift 3中DNS解析流程:

以上就是OpenShift 3中DNS的解析流程,核心是通過(guò)每個(gè)節(jié)點(diǎn)上運(yùn)行的Dnsmasq進(jìn)程做了SkyDNS和上游DNS的代理。

在OpenShift 3的DNS里面需要注意以下幾點(diǎn):

OpenShift 4的DNS

OpenShift 4使用CoreDNS替換了OpenShift 3使用的SkyDNS,起到的作用是一樣的,同樣是提供OpenShift內(nèi)部的域名解析服務(wù)。

在OpenShift 4中CoreDNS使用Operator實(shí)現(xiàn)部署,最終會(huì)創(chuàng)建出DaemonSet部署CoreDNS,也就是在每個(gè)節(jié)點(diǎn)會(huì)啟動(dòng)一個(gè)CoreDNS容器。在Kubelet將--cluster-dns設(shè)定為CoreDNS的ServiceClusterIP,這樣Pod中就可以使用CoreDNS進(jìn)行域名解析。

在安裝OpenShift 4時(shí),通過(guò)名為dns的Clusteroperator創(chuàng)建整個(gè)DNS堆棧,最終會(huì)在項(xiàng)目openshift-dns-operator下實(shí)例化一個(gè)dns pod完成具體的部署配置操作。

Cluster Domain定義了集群中Pod和Service域名的基本DNS域,默認(rèn)為cluster.local,域名服務(wù)的地址是CoreDNS的ClusterIP,是配置的Service IP CIDR網(wǎng)段中的第10個(gè)地址,默認(rèn)網(wǎng)段為172.30.0.0/16,第十個(gè)地址為172.30.0.10。DNS解析流程如下圖所示:

上圖表示了OpenShift 4的DNS解析流程

說(shuō)簡(jiǎn)單點(diǎn),在OCP中,隨便創(chuàng)建一個(gè)pod,這個(gè)pod中的name server都會(huì)指向到172.30.0.10,這是coredns pod的service ip。

我們查看coredns的pod和service ip:

我們?cè)L問(wèn)prometheus-k8s-0 這個(gè)pod進(jìn)行查看。

查看這個(gè)規(guī)則:

sh-4.2$ cat /etc/resolv.conf

search openshift-monitoring.svc.cluster.local svc.cluster.local cluster.local

nameserver 172.30.0.10

options ndots:5

我們查看宿主機(jī)的dns。

OCP宿主機(jī)的nameserver可以是數(shù)據(jù)中心內(nèi)部的,也可以自行構(gòu)建。

舉例說(shuō),如果我要在pod中nslookup baidu.com

1.如果coredns pod中有緩存,直接返回

2. coredns pod中沒(méi)有緩存,coredns一看這是外部域名,不歸它管,他就會(huì)轉(zhuǎn)到宿主機(jī)指向的192.168.91.8去解析,如果這192.168.91.8也解析不了,那就看還有沒(méi)有上級(jí)的DNS了。總之,得有dns把baidu.com能解析出來(lái)。如果在OCP在純離線(xiàn)的環(huán)境,baidu.com八成就解析失敗了。(數(shù)據(jù)中心內(nèi)部應(yīng)該沒(méi)人給baidu.com自己配解析)

好了,靈魂拷問(wèn)結(jié)束,這種拷問(wèn)方式是不是感覺(jué)比直接敘述看著爽一些?


聲明:免責(zé)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶(hù)自發(fā)貢獻(xiàn)自行上傳,本網(wǎng)站不擁有所有權(quán),也不承認(rèn)相關(guān)法律責(zé)任。如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,請(qǐng)發(fā)

送郵件至:operations@xinnet.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),本站將立刻刪除涉嫌侵權(quán)內(nèi)容。本站原創(chuàng)內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)

需注明出處:新網(wǎng)idc知識(shí)百科

免費(fèi)咨詢(xún)獲取折扣

Loading