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


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

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

理解OpenShift(3):網絡之 SDN

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

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

 

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

 

OpenShift 集群中,至少有三個地方需要用到 DNS:

  • 一是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,並將結果返回客戶端。

 

參考文檔:

 

感謝您的閱讀,歡迎關注我的微信公眾號:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM