https://juejin.cn/post/6844903665879220231
https://mp.weixin.qq.com/s/r1ZjtBVe4XPLmsMTj2oZNQ
Kubernetes DNS 高階指南
DNS
是 Kubernetes 的核心功能之一,Kubernetes 通過(guò) kube-dns
或 CoreDNS
作為集群的必備擴(kuò)展來(lái)提供命名服務(wù)豪嗽,通過(guò) DNS 擴(kuò)展慕的,每一個(gè) Service
都會(huì)產(chǎn)生一個(gè)獨(dú)一無(wú)二的 FQDN(Fully Qualified Domain Name)名稱(chēng)噪矛。
在大多數(shù)使用場(chǎng)景下华糖,我們并不會(huì)太關(guān)心 DNS 插件的內(nèi)部運(yùn)作細(xì)節(jié)作郭,直接使用 Kubernetes 預(yù)設(shè)的 DNS 配置和策略就可以滿足需求诗充。然而隨著使用場(chǎng)景越來(lái)越復(fù)雜黑毅,譬如跟 NFV(Network Function Virtualization)相關(guān)的場(chǎng)景祭衩,我們的應(yīng)用(Pod)可能就會(huì)需要更加個(gè)性化的 DNS 配置灶体。
接下來(lái)使用下面這張架構(gòu)圖來(lái)說(shuō)明可能的使用場(chǎng)景:
[圖片上傳失敗...(image-87df61-1615508286754)]
1. 為什么需要自定義 DNS
一般的使用場(chǎng)景下,我們的 Kubernetes 集群的使用方式就像圖中紫色/粉紅色(Pod3)區(qū)域一樣掐暮,所有的 Pod 如果有任何要存取 DNS
的需求蝎抽,都會(huì)透過(guò)集群內(nèi)的的 k8s DNS
來(lái)處理對(duì)應(yīng)的請(qǐng)求與回復(fù)。
然而在 NFV
的使用場(chǎng)景下路克,網(wǎng)絡(luò)變成一個(gè)很重要的區(qū)域樟结,整體的性能都取決于該應(yīng)用的設(shè)計(jì)與集群的網(wǎng)絡(luò)架構(gòu)設(shè)計(jì)。這部分應(yīng)用通常都會(huì)追求高輸出或是低延遲精算,為了得到更好的性能瓢宦,需要避免這些流量跟其他無(wú)關(guān)的流量使用相同的網(wǎng)絡(luò)線路進(jìn)行傳輸。
在這種情況下灰羽,通常就會(huì)把整個(gè)集群的網(wǎng)絡(luò)設(shè)計(jì)成兩種架構(gòu)驮履,分別是 Control Network
和 Data Network
這兩個(gè)不同用途的網(wǎng)絡(luò)架構(gòu)。在 Kubernetes 中廉嚼,Control Network
就類(lèi)似于圖中的 Cluster Network
玫镐,負(fù)責(zé)整個(gè)集群之間的溝通。圖中綠色/橘色(Pod1怠噪,Pod2)這兩個(gè)區(qū)域就是所謂的 Data Network
恐似,其網(wǎng)卡本身也被獨(dú)立出來(lái),不會(huì)與本來(lái)的 Kubernetes 集群發(fā)生沖突傍念,它們之間的流量通過(guò)獨(dú)立的網(wǎng)絡(luò)進(jìn)行傳輸矫夷。
存在于獨(dú)立出來(lái)的網(wǎng)絡(luò)架構(gòu)中的這些特殊的 Pod 基本上沒(méi)法跟 Kubernetes 集群內(nèi)的 DNS 互連,而且這些應(yīng)用還有可能在外部有自己的 DNS Server
憋槐,所以在這種場(chǎng)景下双藕,我們希望這些應(yīng)用(Pod1/Pod2)能夠使用自定義的 DNS Server
。
2. 如何自定義 DNS
為了讓用戶更容易控制 Pod 中的 DNS 設(shè)置阳仔,Kubernetes v1.9 引入了一項(xiàng)新的 Alpha 特性(在 v1.10 中處于 Beta 階段)蔓彩。該特性在 v1.10 中被默認(rèn)啟用,在 v1.9 中如果想要啟用此功能,集群管理員需要在 apiserver 和 kubelet 上啟用 CustomPodDNS
特性赤嚼,例如: “--feature-gates=CustomPodDNS=true,...”
旷赖。啟用了該特性之后,用戶可以將 Pod 的 dnsPolicy
字段設(shè)置為 "None"
更卒,并且可以在 Pod.Spec
中添加新的字段 dnsConfig
等孵。
其中 dnsConfig
用來(lái)自定義 DNS 參數(shù),而 dnsPolicy
用來(lái)給 Pod 選取預(yù)設(shè)的 DNS蹂空。接下來(lái)就看看可以通過(guò)哪些手段自定義 DNS俯萌。
dnsConfig
dnsConfig 可以讓操作者延伸到 Pod 內(nèi)部關(guān)于 DNS 的配置,這邊需要特別注意的是上枕,我使用的字眼是 延伸 而不是 配置咐熙,這是因?yàn)橥ㄟ^(guò)下一節(jié)的 dnsPolicy,每個(gè) Pod 都會(huì)有一組預(yù)設(shè)的 DNS 配置辨萍。通過(guò) dnsConfig 我們可以繼續(xù)往上迭加相關(guān)的 DNS 參數(shù)到 Pod 之中棋恼。
目前總共支持三個(gè)參數(shù),分別是:
nameservers
searches
options
這三個(gè)參數(shù)對(duì)應(yīng)的就是大家熟悉的 /etc/resolv.conf
里面的三個(gè)參數(shù)锈玉,這里就不針對(duì) DNS 進(jìn)行詳細(xì)解釋了爪飘,不熟悉的朋友可以自行去 Google 學(xué)一下這些參數(shù)的意思。
在 Kubernetes 里面拉背,這三個(gè)參數(shù)都包含在 dnsConfig 配置項(xiàng)中师崎,而 dnsConfig 包含在 PodSpec
配置項(xiàng)中,因?yàn)?Pod 內(nèi)所有的容器都共享相同的 Network Namespace椅棺,所以網(wǎng)絡(luò)方面的配置都會(huì)共享犁罩。
這邊提供一個(gè)簡(jiǎn)單的 yaml 示例:
[圖片上傳失敗...(image-4b8e1f-1615508286753)]
通過(guò)上述 yaml 創(chuàng)建 Pod 之后,通過(guò)下面的命令可以觀察到容器中 DNS 配置文件中會(huì)出現(xiàn)額外的配置两疚。
$ kubectl exec ubuntu-setting cat /etc/resolv.confnameserver 10.254.0.2nameserver 1.2.3.4search default.svc.cluster.local svc.cluster.local cluster.local ns1.svc.cluster.local my.dns.search.suffixoptions ndots:2 edns0
復(fù)制代碼
可以看到 nameserver 多了一個(gè) 1.2.3.4床估,而 search 則多了 ns1.svc.cluster.local my.dns.search.suffix
這兩個(gè)自定義的值,最后 options 則增加了我們示例中指定的 ndots:2 edns0
鬼雀。
dnsConfig 非常簡(jiǎn)單直觀顷窒,如果你需要自定義 DNS 參數(shù)蛙吏,就可以通過(guò)這個(gè)字段來(lái)指定源哩。
dnsPolicy
前面提過(guò),dnsConfig
提供的是延伸 Pod 內(nèi)預(yù)設(shè)的 DNS 配置鸦做,而 dnsPolicy
就是決定 Pod 內(nèi)預(yù)設(shè)的 DNS 配置有哪些励烦。
目前總共有四個(gè)類(lèi)型可以選擇:
None
Default
ClusterFirst
ClusterFirstHostNet
接下來(lái)針對(duì)這四個(gè)類(lèi)型分別介紹。
None
None
表示會(huì)清除 Pod 預(yù)設(shè)的 DNS 配置泼诱,當(dāng) dnsPolicy 設(shè)置成這個(gè)值之后坛掠,Kubernetes 不會(huì)為 Pod 預(yù)先載入任何自身邏輯判斷得到的 DNS 配置。因此若要將 dnsPolicy 的值設(shè)為 None,為了避免 Pod 里面沒(méi)有配置任何 DNS屉栓,最好再添加 dnsConfig 來(lái)描述自定義的 DNS 參數(shù)舷蒲。
使用下面的示例來(lái)進(jìn)行測(cè)試:
[圖片上傳失敗...(image-170b2b-1615508286753)]
通過(guò)上述 yaml 創(chuàng)建 Pod 之后,通過(guò)下面的命令可以觀察容器中的 DNS 配置文件友多,可以觀察到跟之前的 dnsConfig
的結(jié)果有一點(diǎn)差異牲平,這里只有我們?cè)?yaml 里配置的那些參數(shù),而沒(méi)有加入集群預(yù)設(shè)的 DNS 配置域滥。
$ kubectl exec ubuntu-none cat /etc/resolv.confnameserver 1.2.3.4search ns1.svc.cluster.local my.dns.search.suffixoptions ndots:2 edns0
復(fù)制代碼
Default
Default
表示 Pod 里面的 DNS 配置繼承了宿主機(jī)上的 DNS 配置纵柿。簡(jiǎn)單來(lái)說(shuō),就是該 Pod 的 DNS 配置會(huì)跟宿主機(jī)完全一致启绰。
使用下面的示例來(lái)進(jìn)行測(cè)試:
[圖片上傳失敗...(image-aad2ab-1615508286753)]
首先昂儒,我們先觀察 Node 上面的 DNS 配置:
$ cat /etc/resolv.conf# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTENnameserver 10.0.2.3
復(fù)制代碼
可以觀察到,Node 上面的 DNS 配置得很簡(jiǎn)單委可,只有單純的 10.0.2.3
渊跋。 接下來(lái)我們觀察該 Pod 內(nèi)的 DNS 配置:
$ kubectl exec ubuntu-default cat /etc/resolv.confnameserver 10.0.2.3
復(fù)制代碼
可以看到這兩個(gè)的 DNS 配置完全一致,該 Pod 內(nèi)的 DNS 配置已經(jīng)直接繼承 Node 上面的配置了撤缴。
ClusterFirst
相對(duì)于上述的 Default刹枉,ClusterFirst
是完全相反的操作,它會(huì)預(yù)先把 kube-dns
(或 CoreDNS)的信息當(dāng)作預(yù)設(shè)參數(shù)寫(xiě)入到該 Pod 內(nèi)的 DNS 配置屈呕。
ClusterFirst 是預(yù)設(shè)的行為微宝,若沒(méi)有在 Pod 內(nèi)特別描述 PodPolicy, 則會(huì)將 dnsPolicy 預(yù)設(shè)為 ClusterFirst。
使用下面的示例來(lái)進(jìn)行測(cè)試:
[圖片上傳失敗...(image-33a41d-1615508286753)]
通過(guò)上述 yaml 創(chuàng)建 Pod 之后虎眨,通過(guò)下面的命令觀察容器中的 DNS 配置文件:
$ kubectl exec ubuntu-clusterfirst cat /etc/resolv.confnameserver 10.254.0.2search default.svc.cluster.local svc.cluster.local cluster.localoptions ndots:5
復(fù)制代碼
可以看到這里使用的是 k8s DNS 的設(shè)置蟋软。
此外,ClusterFirst 還有一個(gè)沖突嗽桩,如果你的 Pod 設(shè)置了 HostNetwork=true
岳守,則 ClusterFirst 就會(huì)被強(qiáng)制轉(zhuǎn)換成 Default
。
HostNetwork
使用下面的示例來(lái)進(jìn)行測(cè)試:
[圖片上傳失敗...(image-44b2ab-1615508286753)]
通過(guò)上述 yaml 創(chuàng)建 Pod 之后碌冶,通過(guò)下面的命令觀察容器中的 DNS 配置文件:
$ kubectl exec ubuntu-hostnetwork-policy-default cat /etc/resolv.confnameserver 10.0.2.3
復(fù)制代碼
可以觀察到湿痢,Pod 里面的 DNS 配置直接繼承了宿主機(jī)上的 DNS 配置。
這邊稍微來(lái)解釋一下這個(gè)設(shè)計(jì)上的原理以及流程:
因?yàn)樵O(shè)置了
HostNetwork=true
, 會(huì)讓該 Pod 與該節(jié)點(diǎn)共用相同的網(wǎng)路空間(網(wǎng)卡/路由等功能)扑庞。預(yù)設(shè)的 k8s DNS 是使用
ClusterIP
的 kubernetes serivce. 這種情況下譬重,只有屬于 Cluster 內(nèi)的Pod
可以獲取該 ClusterIP。所以設(shè)置了
HostNetwork=true
的 Pod 就沒(méi)有辦法獲取該 ClusterIP罐氨。于是預(yù)設(shè)就會(huì)將對(duì)應(yīng)的 DNS 配置改回
Default
的形式臀规,從節(jié)點(diǎn)繼承其 DNS 配置信息。
這種情況下栅隐,就會(huì)有人想要問(wèn)塔嬉,如果我刻意想要這樣設(shè)置不行嗎玩徊?
原先的設(shè)計(jì)中,是沒(méi)有辦法刻意處理的谨究,原因是當(dāng) Pod yaml
配置文件被發(fā)送出去后恩袱,在發(fā)現(xiàn)沒(méi)有設(shè)定 dnsPolicy
的情況下,會(huì)自動(dòng)幫你把該 dnsPolicy 補(bǔ)上 ClusterFirst
的數(shù)值胶哲。
然后最后面的程序處理邏輯中憎蛤,其實(shí)並沒(méi)有辦法分別下列兩種情況:
HostNetwork:我希望走 Host DNS
HostNetwork & dnsPolicy=ClusterFirst:我希望走 ClusterIP DNS
上述兩種情況對(duì)于后端的程序來(lái)看都長(zhǎng)得一樣,完全沒(méi)有辦法分辨纪吮,我們可以直接從 Kubernetes 源碼 來(lái)閱讀一下其運(yùn)作流程:
func getPodDNSType(pod *v1.Pod) (podDNSType, error) { dnsPolicy := pod.Spec.DNSPolicy switch dnsPolicy { case v1.DNSNone: if utilfeature.DefaultFeatureGate.Enabled(features.CustomPodDNS) { return podDNSNone, nil } // This should not happen as kube-apiserver should have rejected // setting dnsPolicy to DNSNone when feature gate is disabled. return podDNSCluster, fmt.Errorf(fmt.Sprintf("invalid DNSPolicy=%v: custom pod DNS is disabled", dnsPolicy)) case v1.DNSClusterFirstWithHostNet: return podDNSCluster, nil case v1.DNSClusterFirst: if !kubecontainer.IsHostNetworkPod(pod) { return podDNSCluster, nil } // Fallback to DNSDefault for pod on hostnetowrk. fallthrough case v1.DNSDefault: return podDNSHost, nil } // This should not happen as kube-apiserver should have rejected // invalid dnsPolicy. return podDNSCluster, fmt.Errorf(fmt.Sprintf("invalid DNSPolicy=%v", dnsPolicy))}
復(fù)制代碼
這邊可以看到一旦是 DNSClusterFirst
的情況下俩檬,若設(shè)置了 HostNetwork, 最后就會(huì)直節(jié)回傳 podDNSHost
節(jié)點(diǎn)的 DNS 設(shè)定回去。
為了解決上述的問(wèn)題碾盟,所以引進(jìn)了一個(gè)新的類(lèi)型 ClusterFirstHostNet
棚辽。
ClusterFirstWithHostNet
ClusterFirstWithHostNet
用途非常簡(jiǎn)單,我希望滿足使用 HostNetwork 同時(shí)使用 k8s DNS
作為我 Pod 預(yù)設(shè) DNS 的配置冰肴。
根據(jù)上面的源碼也可以觀察到:
case v1.DNSClusterFirstWithHostNet: return podDNSCluster, nil
復(fù)制代碼
只要將 dnsPolicy 設(shè)置為 ClusterFirstWithHostNet
, 就會(huì)一律返回 k8s DNS 的 clusterIP
這種形式屈藐。
使用下面的示例來(lái)進(jìn)行測(cè)試:
[圖片上傳失敗...(image-cfe007-1615508286752)]
通過(guò)上述 yaml 創(chuàng)建 Pod 之后,通過(guò)下面的命令觀察該 Pod 的狀態(tài):
$ kubectl exec ubuntu-hostnetwork-policy cat /etc/resolv.confnameserver 10.254.0.2search default.svc.cluster.local svc.cluster.local cluster.localoptions ndots:5
復(fù)制代碼
可以發(fā)現(xiàn)這時(shí)候的 DNS 就會(huì)配置成 k8s DNS 的 ClusterIP
了熙尉。
作者:rowenan
鏈接:https://juejin.cn/post/6844903665879220231
來(lái)源:掘金
著作權(quán)歸作者所有联逻。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處检痰。