理解OpenShift(2):網絡之 DNS(域名服務)

理解OpenShift(1):網絡之 Router 和 Routehtml

理解OpenShift(2):網絡之 DNS(域名服務)node

理解OpenShift(3):網絡之 SDNgit

理解OpenShift(4):用戶及權限管理github

理解OpenShift(5):從 Docker Volume 到 OpenShift Persistent Volumedocker

 

** 本文基於 OpenShift 3.11,Kubernetes 1.11 進行測試 ***後端

 

OpenShift 集羣中,至少有三個地方須要用到 DNS:api

  • 一是Pod 中的應用經過域名訪問外網的時候,須要DNS來解析外網的域名
  • 二是在集羣內部(pod 中或者宿主機上)經過服務的域名來訪問集羣內服務的時候,這也是一般所說的服務發現功能,須要經過服務域名來先發現(獲取其IP地址)再使用該服務
  • 三是從集羣外部經過域名訪問部署在OpenShift pod 中的服務的時候,須要DNS來解析服務的外網域名

本文就從這三點出發,解釋 OpenShift 是如何實現這三種DNS功能的。緩存

1. OpenShift 中的DNS 相關組件及其配置

1.1 Pod 中的 DNS 配置

在Linux 系統上,當一個應用經過域名鏈接遠端主機時,DNS 解析會經過系統調用來進行,好比 getaddrinfo()。和任何Linux 操做系統同樣,Pod 的 DNS 定義在 resolv.conf 文件中,其示例以下:服務器

sh-4.2$ cat /etc/resolv.conf 
nameserver 172.22.122.9
search dev.svc.cluster.local svc.cluster.local cluster.local exampleos.com
options ndots:5

其中,微信

  • nameserver 字段是 pod 所在的宿主機的主網卡的IP 地址。也就是說 pod 中發起的全部DNS 查詢請求都會被轉發到運行在宿主機的 53 端口上的DNS服務器上。
  • search 字段指定當解析一個非FQDN域名時被附加的搜索域(search domain)列表。其解釋以下:
域名(Domain Name)分爲兩種,一種是絕對域名(Absolute Domain Name,也稱爲 Fully-Qualified Domain Name,簡稱 FQDN),另外一種是相對域名(Relative Domain Name,也稱爲 Partially Qualified Domain Name,簡稱PQDN)。FQDN 是完整域名,它可以惟一地在DNS名字空間中肯定一個記錄。好比最高級別的域名A包括子域名B它又包括子域名C,那麼FQDN 是 C.B.A.,好比 cs.widgetopia.edu.。 有時候咱們也會使用PQDN,它是不徹底的、模糊的。
FQDN 能被直接到 DNS 名字服務器中查詢;而 PQDN 須要先轉化爲FQDN 再進行查詢。其作法是將 PQDN 附加一個搜索域名(search domain)來生成一個 FQDN。在域名系統中,域名結尾是不是『.』被用來區分 FQDN 和 PQDN。好比  apple.com. 表示一個Apple公司的 FQDN,而 apple 則表示一個 PQDN,它的FQDN 多是  apple.cs.widgetopia.edu.; apple.com 仍然是一個 PQDN,它的FQDN 多是  apple.com.cs.widgetopia.edu.。
  • options ndots:5

默認地,許多DNS 解析器若是發現被解析的域名中有任何的點(.)就把它當作一個 FQDN 來解析;若是域名中沒有任何點,就把它當作 PQDN 來處理,而且會加上系統的默認domain name 和最後的點,來組成 FQDN。若是沒有指定默認的 domain name (經過 domain 字段)或查詢失敗,則會將 search 字段的第一個值當作默認domain name,若是解析不成功,則依次往下試,直到有一個成功或者所有失敗爲止。

這個行爲是經過 options ndots 來指定的,其默認值爲1,這意味着只要被解析域名中有任何一個點(.),那麼它就會被當作 FQDN,而不會附加任何 search domain,直接用來查詢。OpenShift 環境中,這個值被設置爲 5。這意味着,只要被解析域名中包含不超過五個點,該域名就會被當作PQDN,而後挨個使用 search domain,來組裝成 FQDN 來作DNS查詢。若是所有不成功過,則會嘗試將它直接做爲 FQDN 來解析。

所以,這某些場景中,pod 中的DNS 查詢速度會下降應用的性能。解決方法主要有兩種,要麼直接使用 FQDN,要麼減少 ndots 的值,具體請查看 Kubernetes 和 DNS 的有關文檔。

1.2 Pod 所在宿主機上的 DNS 配置及服務

1.2.1 resolv.conf 文件

[root@node2 cloud-user]# cat /etc/resolv.conf
# nameserver updated by /etc/NetworkManager/dispatcher.d/99-origin-dns.sh
# Generated by NetworkManager
search cluster.local exampleos.com
nameserver 172.22.122.9

在部署環境時,會在每一個節點上部署 /etc/NetworkManager/dispatcher.d/99-origin-dns.sh 文件。每當節點上的 NetworkManager 服務啓動時,該文件會被運行。它的任務包括:

  • 建立 dnsmasq 配置文件 :
    • node-dnsmasq.conf (在個人 3.11 版本環境上沒有建立該文件,見下文分析)
    • origin-dns.conf  
    • origin-upstream-dns.conf
  • 當 NetworkManager 服務啓動時啓動 dnsmasq 服務
  • 設置宿主機的全部默認路由 IP 爲 Dnsmasq 的偵聽IP
  • 修改 /etc/resolv.conf,設置搜索域,以及將宿主機的默認 IP 做爲 nameserver
  • 建立 /etc/origin/node/resolv.conf

也就是說,宿主機上的 DNS 請求也會轉到本機上的 53 端口。

1.2.2 dnsmasq 及其配置

宿主機上的 53 端口上,dnsmasq 服務在route 默認路由的全部IP的53端口上偵聽。其中一個負責接受並處理宿主機上全部pod 中以及宿主機上的全部DNS查詢服務。

tcp 0 0 10.128.2.1:53 0.0.0.0:* LISTEN 906/dnsmasq
tcp 0 0 172.17.0.1:53 0.0.0.0:* LISTEN 906/dnsmasq
tcp 0 0 172.22.122.9:53 0.0.0.0:* LISTEN 906/dnsmasq

這些 IP 地址和默認路由IP 地址是符合的:

10.128.0.0      0.0.0.0         255.252.0.0     U     0      0        0 tun0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 172.22.122.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0 172.30.0.0 0.0.0.0 255.255.0.0 U 0 0 0 tun0

dnsmasq 服務的配置目錄爲 /etc/dnsmasq.d。其中有兩個配置文件(具體含義請查閱有關文檔):

[root@node2 dnsmasq.d]# cat origin-dns.conf 
no-resolv
domain-needed
no-negcache
max-cache-ttl=1
enable-dbus
dns-forward-max=10000
cache-size=10000
bind-dynamic
min-port=1024
except-interface=lo
# End of config

文件 origin-upstream-dns.conf 中定義了上游(upstream) DNS 名字服務器:

[root@node2 dnsmasq.d]# cat origin-upstream-dns.conf 
server=172.22.122.3
server=172.22.122.2
server=172.22.122.4

這些上游服務器的地址是從 DHCP 服務器中獲取到的(個人OpenShift 環境搭建在OpenStack虛擬機中。前兩個地址是OpenStack neutron 網絡的 DNSmasq 地址,最後一個是單獨搭建的 bind9  DNS 服務器地址)。

在早期版本中(個人OpenShift版本是 3.11),還有一個配置文件 node-dnsmasq.conf :

server=/in-addr.arpa/127.0.0.1
server=/cluster.local/127.0.0.1

這意味着全部以 cluster.local 和 in-addr.arpa 結尾的域名,都會被轉到 127.0.0.1:53 上被解析。而其它的解析請求,會被轉到在 origin-upstream-dns.conf  中定義的上游 DNS 服務器。

個人3.11版本環境中並無生成該文件。從代碼 https://github.com/openshift/origin/blob/master/pkg/dns/dnsmasq.go 看,OpenShift 中的 dnsmasq 在啓動時會自動添加這兩條記錄:

而 dnsIP 和 dnsDomain 應該是在 /etc/origin/node/node-config.yaml 中的以下配置:

dnsBindAddress: 127.0.0.1:53
dnsDomain: cluster.local
從 dnsmasq 日誌中也能看到相關記錄:
Dec  3 14:10:57 dnsmasq[29595]: using nameserver 127.0.0.1#53 for domain in-addr.arpa
Dec  3 14:10:57 dnsmasq[29595]: using nameserver 127.0.0.1#53 for domain cluster.local

從上面的分析可見,在 node 節點上的 dnsmasq,其實只是一個DNS 查詢轉發器(轉到上游DNS 服務器或者本機上的 SkyDns)和結果緩存器,它自己並不保存域名的原始記錄。

1.2.3 SkyDNS 及其配置

關於 SkyDNS:它是一個開源的構建在 etcd 之上的分佈式服務宣告(announcement)和發現(discovery)服務。利用它,能夠經過 DNS 查詢來發現可用的服務。其開源社區的地址是 https://github.com/skynetservices/skydns。社區版本的 SkyDns 將記錄保存在 etcd 中,在作查詢時從etcd 獲取數據並封裝成 DNS 結果格式給客戶端。

SkyDNS 的 server 部分支持被做爲庫文件使用,此時能夠爲其實現其它後端。在OpenShift 中並無採用默認的 etcd 後端,而是基於 OpenShift API 服務實現了新的後端,其代碼在https://github.com/openshift/origin/blob/master/pkg/dns/ 。SkyDns 調用 OpenShift API 服務來獲取主機名、IP地址等信息,而後封裝成標準 DNS 記錄並返回給查詢客戶端。 

在 127.0.0.1:53 上,包裝在 openshift 進程中的 SkyDNS 在偵聽。
tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN      17182/openshift 

Node 節點上的 SkyDN 要麼從cache 中直接回答 DNS 查詢,要麼調用 OpenShift API 服務來獲取數據再返回。

1.3 Master 節點上的 DNS 服務

resolv.conf 文件同Node 節點上的:

[root@master1 cloud-user]# cat /etc/resolv.conf 
# nameserver updated by /etc/NetworkManager/dispatcher.d/99-origin-dns.sh
# Generated by NetworkManager
search cluster.local haihangyun.cn exampleos.com
nameserver 172.22.122.5

dnsmasq 在多個IP 地址的 53 端口上偵聽,爲本機上的以及本機上Pod 中的DNS查詢服務:

udp        0      0 10.128.0.1:53           0.0.0.0:*                           866/dnsmasq         
udp        0      0 172.17.0.1:53           0.0.0.0:*                           866/dnsmasq         
udp        0      0 172.22.122.5:53         0.0.0.0:*                           866/dnsmasq 

和 Node 節點不一樣,Master 節點上有兩個SkyDns 進程。一個在 127.0.0.1:53 偵聽,負責本機上的集羣內服務的DNS查詢,由於 Master 節點同時承擔 node 節點的角色:

udp        0      0 127.0.0.1:53            0.0.0.0:*                           11700/openshift 
Dec  3 14:50:41 dnsmasq[10607]: using nameserver 127.0.0.1#53 for domain cluster.local
Dec  3 14:50:41 dnsmasq[10607]: using nameserver 127.0.0.1#53 for domain in-addr.arpa

另外一個是在全部網卡的 8053 端口上偵聽,這是由於Master 還具備 master api 角色:

udp        0      0 0.0.0.0:8053            0.0.0.0:*                           15096/openshift 

對於這個 SkyDns 進程的做用尚不清楚,還需進一步研究。從已有資料上看看,全部節點上都須要安裝 SkyDns,並組成一個分佈式集羣。由於 Master 節點上的 53 端口被另外一個 SkyDns 進程佔用,所以換到了端口8053。

2. DNS 查詢流程

2.1 pod 內的應用經過域名訪問外網服務器的DNS查詢流程

流程示意圖如最上面圖中的 1 和 2.1 部分所示。

dnsmasq 日誌:

Nov 21 11:03:44 dnsmasq[17788]: using nameserver 172.22.122.3#53
Nov 21 11:03:44 dnsmasq[17788]: using nameserver 172.22.122.2#53
Nov 21 11:03:44 dnsmasq[17788]: using nameserver 172.22.122.4#53
Nov 21 11:03:49 dnsmasq[17788]: query[A] www.sina.com from 172.22.122.13
Nov 21 11:03:49 dnsmasq[17788]: forwarded www.sina.com to 172.22.122.4
Nov 21 11:03:49 dnsmasq[17788]: forwarded www.sina.com to 172.22.122.2
Nov 21 11:03:49 dnsmasq[17788]: forwarded www.sina.com to 172.22.122.3
Nov 21 11:03:49 dnsmasq[17788]: reply spool.grid.sinaedge.com is 124.228.42.248

能看到 node 上的 dnsmasq 直接將查詢請求轉發給上游 DNS 名字服務器。由於存在多個名字服務器,因此是依次查詢,直到成功爲止。從日誌看,其查詢順序和配置文件中的順序是相反的。

2.2 Pod 內應用經過服務域名查找其IP 地址

流程示意圖如上圖中的 1 + 2.2 + 3 部分所示。

日誌實例:

(1)從一個 pod 中 ping registry-console服務的域名 registry-console.default.svc.cluster.local。

(2)Node宿主機(IP 地址爲 172.22.122.13)上的 dnsmasq 收到該查詢。

(3)dnsmasq 將查詢轉到 127.0.0.1:53 上的 SkyDns 服務。

(4)SkyDNS 作查詢。SkyDNS 能接收的域名格式:<prefix>.<service_name>.<namespace>.(svc|endpoints|pod).<base>,這意味着它支持查詢服務(svc)、端點(endpoints)和 pod 的 DNS信息。

查詢結果:

[root@node2 cloud-user]# nsenter -t 4216 -n dig mybank.dev.svc.cluster.local          

;; QUESTION SECTION:
;mybank.dev.svc.cluster.local.  IN      A

;; ANSWER SECTION: mybank.dev.svc.cluster.local. 30 IN     A       172.30.162.172

;; Query time: 1 msec
;; SERVER: 172.22.122.9#53(172.22.122.9)
;; WHEN: Mon Dec 03 11:43:01 CST 2018
;; MSG SIZE  rcvd: 62

dnsmasq 日誌:

Dec  3 14:19:44 dnsmasq[29595]: query[A] mybank.dev.svc.cluster.local from 10.128.2.128
Dec  3 14:19:44 dnsmasq[29595]: forwarded mybank.dev.svc.cluster.local to 127.0.0.1
Dec  3 14:19:44 dnsmasq[29595]: reply mybank.dev.svc.cluster.local is 172.30.162.172

(5)其它實驗:查詢服務的全部端點

查詢結果:

[root@node2 cloud-user]# nsenter -t 4216 -n dig jenkins.dev.endpoints.cluster.local

;; QUESTION SECTION:
;jenkins.dev.endpoints.cluster.local. IN        A

;; ANSWER SECTION:
jenkins.dev.endpoints.cluster.local. 30 IN A    10.128.2.81
jenkins.dev.endpoints.cluster.local. 30 IN A    10.131.1.70

dnsmasq 日誌:

Dec  3 14:20:48 dnsmasq[29595]: query[A] jenkins.dev.endpoints.cluster.local from 10.128.2.128
Dec  3 14:20:48 dnsmasq[29595]: forwarded jenkins.dev.endpoints.cluster.local to 127.0.0.1
Dec  3 14:20:48 dnsmasq[29595]: reply jenkins.dev.endpoints.cluster.local is 10.128.2.81
Dec  3 14:20:48 dnsmasq[29595]: reply jenkins.dev.endpoints.cluster.local is 10.131.1.70

(6)查詢 pod

待查詢的pod域名的格式爲 <IP_with_dashes>.<namespace>.pod.<base>,SkyDns 會返回其IP 地址,但我沒明白這麼作的場景和價值,也許是確認pod是否存在?

查詢結果:

[root@node2 cloud-user]# nsenter -t 4216 -n dig 172-30-162-172.dev.pod.cluster.local

;; QUESTION SECTION:
;172-30-162-172.dev.pod.cluster.local. IN A

;; ANSWER SECTION: 172-30-162-172.dev.pod.cluster.local. 30 IN A   172.30.162.172

;; Query time: 1 msec
;; SERVER: 172.22.122.9#53(172.22.122.9)
;; WHEN: Mon Dec 03 13:32:05 CST 2018
;; MSG SIZE  rcvd: 70

dnsmasq 日誌:

Dec  3 14:22:24 dnsmasq[29595]: query[A] 172-30-162-172.dev.pod.cluster.local from 10.128.2.128
Dec  3 14:22:24 dnsmasq[29595]: forwarded 172-30-162-172.dev.pod.cluster.local to 127.0.0.1
Dec  3 14:22:24 dnsmasq[29595]: reply 172-30-162-172.dev.pod.cluster.local is 172.30.162.172

(7)對比 FQDN 和 PQDN

這個 PQDN 被加上了搜索域名再進行查詢,能返回正確的IP地址:

[root@node2 cloud-user]# nsenter -t 4216 -n ping mybank.dev.svc
PING mybank.dev.svc.cluster.local (172.30.162.172) 56(84) bytes of data.

而這個 FQDN 被直接作DNS查詢,結果查詢失敗,未能獲取IP地址:

[root@node2 cloud-user]# nsenter -t 4216 -n ping mybank.dev.svc.
ping: mybank.dev.svc.: Name or service not known

2.3 從外網經過服務域名訪問pod 中運行的服務

 

能夠看出,該過程當中只涉及到外部DNS將服務的公共域名解析爲 OpenShift Router 所在節點的公網地址,後面 HAProxy 做爲代理,直接經過 IP 訪問pod,並將結果返回客戶端。

 

參考文檔:

 

感謝您的閱讀,歡迎關注個人微信公衆號:

相關文章
相關標籤/搜索