本文介紹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