本文介紹Kubernetes叢集中容器Pod在網域名稱解析過程中的解析策略和緩衝策略。
DNS解析鏈路全景
以下介紹三種應用部署形式下應用解析網域名稱的鏈路:
關於圖中的timeout、attempts等術語的含義,請參考下文解析策略和緩衝策略。
非容器化應用直接運行於ECS之上。
樣本:App運行於ECS上。
容器化應用運行於Kubernetes中,DNSPolicy注入ClusterFirst的Pod裡。
樣本:App運行於Kubernetes容器Pod中。
容器化應用運行於Kubernetes中,DNSPolicy注入了NodeLocal DNSCache的Pod裡。
樣本:App運行於Kubernetes容器Pod中,同時部署了NodeLocal DNSCache。
解析策略
用戶端側
一般情況下,應用解析網域名稱是通過Glibc提供的介面完成的,下表參數為/etc/resolv.conf中暴露的網域名稱解析參數,即Glibc解析網域名稱時的可配置參數。
參數 | 說明 | Glibc中預設值 | ECS | DNSPolicy為ClusterFirst的Pod | DNSPolicy為Default的Pod | 注入了NodeLocal DNSCache的Pod | DNSPolicy為Default且採用主機網路的Pod |
| 解析網域名稱時使用的DNS伺服器 | 空 | VPC DNS伺服器② | CoreDNS ClusterIP③ | VPC DNS伺服器 |
| VPC DNS伺服器 |
| 請求非完整網域名稱(非FQDN)時,網域名稱會被拼接上 | 空 | 空 | <ns>.svc.cluster.cloal svc.cluster.local cluster.local | 空 | <ns>.svc.cluster.cloal svc.cluster.local cluster.local | 無 |
| 訪問的網域名稱字串內的點字元數量超過ndots值,則認為是完整網域名稱(FQDN),並被直接解析;如果不足ndots值,則追加search段尾碼再進行查詢。 | 1 | 1 | 5 | 1 | 3 | 1 |
| 對於單個網域名稱解析請求的逾時時間,單位為秒 | 5 | 2 | 5 | 5 | 1 | 2 |
| 解析網域名稱失敗時重試的次數 | 2 | 3 | 2 | 2 | 2 | 3 |
| 以Round Robin的形式輪詢DNS伺服器 | 關閉 | 開啟 | 關閉 | 關閉 | 關閉 | 開啟 |
| 開啟該配置後,一旦需要處理同一Socket發送的兩次請求時,解析端會在發送第一次請求後關閉Socket,並在發送第二次請求前開啟新的socket。 | 關閉 | 開啟 | 關閉 | 關閉 | 關閉 | 開啟 |
①attempts參數僅在部分情境下起到重試的效果,例如服務端返回SERVFAIL、NOTIMP、REFUSED時,或服務端返回NOERROR,但沒有解析結果時。更多資訊,請參見attempts參數解析請求說明。
②VPC DNS伺服器是指ECS上預設配置的DNS伺服器,IP為100.100.2.136和100.100.2.138,負責PrivateZone和權威網域名稱的解析。
③CoreDNS ClusterIP是指Kubernetes叢集內預設部署的CoreDNS在kube-system命名空間下提供的kube-dns服務的IP地址,負責叢集內部服務網域名稱的解析,以及PrivateZone、權威網域名稱的解析轉寄。
④NodeLocal DNSCache IP是指部署了NodeLocal DNSCache組件後,組件在每個節點上監聽的169.254.20.10的IP地址。
關於resolv.conf配置的更多資訊,請參見resolv.conf。
部分情況下,用戶端側的網域名稱解析策略可能與上述配置不同:
當採用Alpine作為容器鏡像時,其內建了Musl庫代替Glibc實現,解析行為會有較大不同,例如:
Alpine不遵循/etc/resolv.conf裡面的single-request和single-request-reopen。
3.3及更早版本Alpine不支援search參數,不支援搜尋域,無法完成服務發現。
並發請求/etc/resolv.conf中配置的多個DNS伺服器,導致NodeLocal DNSCache最佳化失效。
並發使用同一Socket請求A和AAAA記錄,在舊版本核心上觸發Conntrack源連接埠衝突導致丟包問題。
說明關於解析行為的更多資訊,請參見musl libc。
當使用Golang、NodeJS等程式設計語言時,應用可能會採用語言內建的網域名稱解析器,其行為也存在較大區別。
叢集內DNS伺服器
CoreDNS的/etc/resolv.conf預設沿用ECS的配置,但在實際轉寄DNS請求時,會使用內建的Forward外掛程式完成。
NodeLocal DNSCache內建了CoreDNS實現DNS服務轉寄,與CoreDNS配置方式一致。
Forward外掛程式的解析策略控制的參數如下表所示。關於CoreDNS Forward外掛程式的更多配置,請參見Forward。
參數 | 說明 | CoreDNS預設值 | NodeLocal DNSCache預設值 |
| 優先使用UDP協議與上遊通訊 | 開啟 | 關閉 |
| 強制使用TCP協議與上遊通訊 | 關閉 | 開啟 |
| 連續多少次健全狀態檢查失敗就認為upstream不健康 | 2 | 2 |
| 與upstream的連結保持10秒 | 10s | 10s |
| 選擇upstream的策略 | random | random |
| 健全狀態檢查時間間隔 | 0.5s | 0.5s |
| 最大請求upstream的連結並發數 | 無 | 無 |
| 串連upstream的逾時 | 30s,根據實際耗時動態減小 | 30s,根據實際耗時動態減小 |
| 從upstream等待資料的逾時 | 2s | 2s |
緩衝策略
用戶端側
用戶端側的緩衝策略是因容器和應用而異的,實際的緩衝策略取決於您的配置。
叢集內DNS伺服器
參數 | 說明 | CoreDNS社區預設配置 | NodeLocal DNSCache ACK預設配置 | CoreDNS ACK預設配置 |
success Max TTL | 成功的網域名稱解析結果緩衝最大TTL | 3600s | 30s | 30s |
success Min TTL | 成功的網域名稱解析結果緩衝最小TTL | 5s | 5s | 5s |
success Capacity | 成功的網域名稱解析結果緩衝數目 | 9984 | 9984 | 9984 |
denial Max TTL | 失敗的網域名稱解析結果緩衝最大TTL | 1800s | 5s | 30s |
denial Min TTL | 失敗的網域名稱解析結果緩衝最小TTL | 5s | 5s | 5s |
denial Capacity | 失敗的網域名稱解析結果緩衝數目 | 9984 | 9984 | 9984 |
ServerError TTL | 上遊DNS伺服器異常時解析結果TTL | 5s | 0s(NodeLocal DNSCache Helm Chart版本低於1.5.0時,預設為5s) | 0s(CoreDNS低於1.8.4.2版本時預設為5s) |
serve_stale | 允許無法串連上遊DNS伺服器時使用已到期的本機快取 | 關閉 | 開啟(NodeLocal DNSCache Helm Chart版本低於1.5.0時,預設關閉) | 關閉 |
實際生效的緩衝時間TTL由網域名稱解析結果自身TTL、最大TTL、最小TTL共同決定,規則如下:
解析結果TTL>Max TTL時,實際生效的TTL為Max TTL。
解析結果TTL<Min TTL時,實際生效的TTL為Min TTL。
Min TTL<解析結果TTL<Max TTL時,實際生效的TTL為解析結果TTL。
最佳化建議
本文介紹了Kubernetes叢集的解析路徑及各環節參數配置,您可以通過修改Pod Yaml、CoreDNS ConfigMap、NodeLocal DNSCache ConfigMap等方式來修改參數,樣本如下。
當用戶端Pod配置dnsPolicy:Default
時,ECS上VPC DNS伺服器會被拷貝至容器內/etc/resolv.conf設定檔中。
apiVersion: v1
kind: Pod
metadata:
name: example
namespace: default
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/example-ns/example:v1
name: example
#Pod YAML中dnsPolicy值為Default。
dnsPolicy: Default
# 此時容器內/etc/resolv.conf。
# cat /etc/resolv.conf
nameserver 100.100.2.136
nameserver 100.100.2.138
容器內對比ECS上,缺少了rotate single-request-reopen timeout:2 attempts:3
的options參數,可能會使一個偶發的網路鏈路抖動導致業務側網域名稱解析異常,需要補充這些參數以提升容錯能力。調整Pod YAML如下:
apiVersion: v1
kind: Pod
metadata:
name: example
namespace: default
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/example-ns/example:v1
name: example
# Pod YAML中dnsPolicy值為Default。
dnsPolicy: Default
# 增加以下容錯配置。
dnsConfig:
options:
- name: timeout
value: "2"
- name: attempts
value: "3"
- name: rotate
- name: single-request-reopen
# 修改後重新部署Pod,容器內/etc/resolv.conf新增了options參數。
# cat /etc/resolv.conf
nameserver 100.100.2.136
nameserver 100.100.2.138
options rotate single-request-reopen timeout:2 attempts:3