DNS是Kubernetes叢集中至關重要的基礎服務之一,在用戶端設定不合理、叢集規模較大等情況下DNS容易出現解析逾時、解析失敗等現象。本文介紹Kubernetes叢集中DNS的最佳實務,協助您避免此類問題。
前提條件
本文目錄
DNS最佳實務包含用戶端和服務端的內容:
在用戶端,您可以通過最佳化網域名稱解析請求降低解析延遲,通過使用合適的容器鏡像、合適的節點作業系統 、節點DNS緩衝NodeLocal DNSCache等方式來減少解析異常。
在CoreDNS服務端,您可以通過監控CoreDNS運行狀態識別DNS異常,快速定位異常根因,通過合理調整叢集CoreDNS部署狀態來提升叢集CoreDNS高可用和QPS輸送量。
有關CoreDNS的更多資訊,請參見CoreDNS官方文檔。
最佳化網域名稱解析請求
DNS網域名稱解析請求是Kubernetes最高頻的網路行為之一,其中很多請求是可以最佳化和避免的。您可以通過以下方式最佳化網域名稱解析請求:
(推薦)使用串連池:當一個容器應用需要頻繁請求另一服務時,推薦使用串連池。串連池可以將請求上遊服務的連結緩衝在記憶體中,避免每次訪問時網域名稱解析和TCP串連的開銷。
使用非同步或者長輪詢模式來擷取 DNS 網域名稱對應的IP。
使用DNS緩衝:
(推薦)當您的應用無法改造成通過串連池串連另一服務時,可以考慮在應用側緩衝DNS解析結果,具體操作,請參見使用NodeLocal DNSCache。
如果無法使用NodeLocal DNSCache,可以在容器內建NSCD(Name Service Cache Daemon)緩衝。關於如何使用NSCD緩衝,請參見在Kubernetes叢集中使用NSCD。
最佳化resolv.conf檔案:由於resolv.conf檔案中ndots和search兩個參數的機製作用,容器內佈建網域名的不同寫法決定了網域名稱解析的效率,關於ndots和search兩個參數的機制詳情,請參見DNS策略配置和網域名稱解析說明。
最佳化網域名稱配置:當容器內應用需要訪問某網域名稱時,該網域名稱按以下原則配置,可以最大程度減少網域名稱解析嘗試次數,從而減少網域名稱解析耗時。
Pod訪問同命名空間的Service,優先使用
<service-name>訪問,其中service-name代指Service名稱。Pod跨命名空間訪問Service,優先使用
<service-name>.<namespace-name>訪問,其中namespace-name代指Service所處的命名空間。Pod訪問叢集外部網域名稱時,優先使用FQDN類型網域名稱訪問,這類網域名稱通過常見網域名稱最後加半形句號(.)的方式來指定地址,可以避免
search搜尋域拼接帶來的多次無效搜尋,例如,訪問www.aliyun.com時,優先使用FQDN類型網域名稱www.aliyun.com.來訪問。
瞭解容器中的DNS配置
不同的DNS resolver 解析器會因為實現的差異有細微差別。可能會遇到dig <網域名稱>解析正常,ping <網域名稱>失敗的情況。
不建議使用Alpine基礎鏡像,Alpine容器鏡像內建的musl libc庫與標準glibc的實現存在一些差異,會導致包括但不限於以下問題。您可嘗試使用其他基礎鏡像,如Debian、CentOS等。
3.18及更早版本的Alpine不支援tc回退到TCP協議。
3.3及更早版本Alpine不支援search參數,不支援搜尋域,無法完成服務發現。
並發請求/etc/resolv.conf中配置的多個DNS伺服器,導致NodeLocal DNSCache最佳化失效。
並發使用同一Socket請求A和AAAA記錄,在舊版本核心上觸發Conntrack源連接埠衝突導致丟包問題。
關於以上問題的更多資訊,請參見musl libc。
如果是GO語言應用,請瞭解CGO和Pure GO不同實現下的DNS Resolver的差異。
避免IPVS缺陷導致的DNS機率性解析逾時問題
當叢集使用IPVS作為kube-proxy負載平衡模式時,您可能會在CoreDNS縮容或重啟時遇到DNS機率性解析逾時的問題。該問題由社區Linux核心缺陷導致,具體資訊,請參見IPVS。
您可以通過以下任意方式降低IPVS缺陷的影響:
使用節點DNS緩衝NodeLocal DNSCache,具體操作,請參見使用NodeLocal DNSCache。
修改kube-proxy中IPVS UDP會話保持的逾時時間,具體操作,請參見如何修改kube-proxy中IPVS UDP會話保持的逾時時間?。
使用NodeLocal DNSCache
在部分情況下,CoreDNS可能會出現下列問題:
小機率情況下,可能會遭遇A和AAAA並發查詢導致的丟包,進而導致的DNS解析失敗問題。
節點conntrack表滿導致丟包,導致DNS解析失敗。
為了提高叢集DNS服務的穩定性和效能,我們推薦您安裝NodeLocal DNSCache組件,它通過在叢集節點上運行DNS緩衝提高叢集DNS效能。關於更多NodeLocal DNSCache的介紹及如何在ACK叢集中部署NodeLocal DNSCache的具體步驟,請參見使用NodeLocal DNSCache組件。
安裝NodeLocal DNSCache後,需將DNS緩衝配置注入Pod中。執行下方的命令可以為指定namespace配置標籤,在此namespace中建立的Pod會自動注入DNS緩衝配置。更多注入方式請參見上方的文檔。
kubectl label namespace default node-local-dns-injection=enabled使用合適的CoreDNS版本
CoreDNS對Kubernetes版本實現了較好的向後相容,建議您保持CoreDNS版本為較新的穩定版本。ACK組件管理中心提供了CoreDNS的安裝、升級、配置能力,您可以關注組件管理中組件狀態,若CoreDNS組件顯示可升級,請儘快選擇業務低峰期進行升級。
關於升級的具體操作,請參見CoreDNS自動升級。
關於CoreDNS版本的發布記錄,請參見CoreDNS。
CoreDNS v1.7.0以下的版本存在風險隱患,包括但不限於以下:
CoreDNS與APIServer連通性異常(例如APIServer重啟、APIServer遷移、網路抖動)時,CoreDNS會因錯誤記錄檔寫入失敗導致容器重啟。更多資訊,請參見Set klog's logtostderr flag。
啟動CoreDNS時會佔用額外記憶體,預設採用的Memory Limit在較大規模叢集下可能觸發OOM(OutOfMemory)問題,嚴重時可能導致CoreDNS Pod反覆重啟無法自動回復。更多資訊,請參見CoreDNS uses a lot memory during initialization phase。
CoreDNS存在若干可能影響Headless Service網域名稱、叢集外部網域名稱解析的問題。更多資訊,請參見plugin/kubernetes: handle tombstones in default processor和Data is not synced when CoreDNS reconnects to kubernetes api server after protracted disconnection。
在叢集節點異常情況下,部分舊版本CoreDNS預設採用的容忍策略,可能會導致CoreDNS Pod部署在異常節點上,且CoreDNS Pod無法被自動驅逐,繼而導致網域名稱解析異常。
不同版本的Kubernetes叢集,推薦的CoreDNS最低版本有所區別。如下表:
Kubernetes版本 | 推薦的最低CoreDNS版本 |
v1.14.8以下(停止維護) | v1.6.2 |
v1.14.8及以上,1.20.4以下 | v1.7.0.0-f59c03d-aliyun |
1.20.4及以上,1.21.0以下 | v1.8.4.1-3a376cc-aliyun |
1.21.0及以上 | v1.11.3.2-f57ea7ed6-aliyun |
Kubernetes 1.14.8以下的版本現已停止維護,請儘快升級至更高版本後,升級CoreDNS。
監控CoreDNS運行狀態
監控指標
CoreDNS通過標準的Prometheus介面暴露出解析結果等健康指標,發現CoreDNS服務端甚至上遊DNS伺服器的異常。
阿里雲Prometheus監控預設內建了CoreDNS相關的指標監控和警示規則,您可以在Container Service管理主控台開啟Prometheus及儀錶盤功能。具體操作,請參見CoreDNS組件監控。
若您是自建Prometheus監控Kubernetes叢集,可以在Prometheus觀測相關指標,並對重點指標設定警示。具體操作,請參見CoreDNS Prometheus官方文檔。
作業記錄
在DNS異常發生的情況下,CoreDNS日誌有助於您快速診斷異常根因。建議您開啟CoreDNS網域名稱解析日誌和其SLS日誌採集,具體操作,請參見分析和監控CoreDNS日誌。
Kubernetes事件投遞
在v1.9.3.6-32932850-aliyun及以上版本的CoreDNS中,您可以開啟k8s_event外掛程式以將CoreDNS關鍵日誌以Kubernetes事件的形式投遞到事件中心。關於k8s_event外掛程式,請參見k8s_event。
全新部署的CoreDNS會預設開啟該功能。如果您是從低版本CoreDNS升級到v1.9.3.6-32932850-aliyun及以上版本的,您需要手動修改設定檔以開啟該功能。
執行如下命令,開啟CoreDNS設定檔。
kubectl -n kube-system edit configmap/coredns新增kubeAPI和k8s_event外掛程式。
apiVersion: v1 data: Corefile: | .:53 { errors health { lameduck 15s } // 新增開始(請忽略其他差異)。 kubeapi k8s_event { level info error warning // 將info、error、warning狀態關鍵日誌投遞。 } // 新增結束。 kubernetes cluster.local in-addr.arpa ip6.arpa { pods verified fallthrough in-addr.arpa ip6.arpa } // 下方略。 }檢查CoreDNS Pod運行狀態和作業記錄,作業記錄中出現
reload字樣後說明修改成功。
保證CoreDNS高可用性
CoreDNS是叢集中的權威DNS,CoreDNS的失效會導致叢集內訪問Service失敗,可能會造成大範圍的業務不可用。您可通過下列措施保證CoreDNS的高可用性:
評估CoreDNS組件壓力
您可在叢集中執行DNS壓力測試評估組件壓力。包括DNSPerf在內的許多開源工具可以協助您完成此目標。如果您無法準確評估叢集DNS壓力,您可參照下方的推薦標準。
建議您在任何情況下設定CoreDNS Pod數應至少為2,單個Pod的資源limit不小於1核1G。
CoreDNS所能提供的網域名稱解析QPS與CPU消耗成正相關,使用NodeLocal DNSCache的情況下,每CPU核可以支撐10000+ QPS的網域名稱解析請求。不同類型的業務對網域名稱請求的QPS需求存在較大差異,您可以觀察每個CoreDNS Pod的峰值CPU使用量,如果其在業務峰值期間佔用CPU大於一核,建議您對CoreDNS進行副本擴容。無法確定峰值CPU使用量時,可以保守地採用Pod數和叢集節點數1:8的比值來部署,即每擴容8個叢集節點,增加一個CoreDNS Pod。
調整CoreDNS Pod數量
CoreDNS擁有的Pod數量直接決定了CoreDNS能夠使用的計算資源,您可根據評估的結果調整CoreDNS所屬Pod數量。
由於UDP報文缺少重傳機制,當叢集節點存在IPVS UDP缺陷導致的丟包風險時,CoreDNS Pod的縮容或重啟可能會導致長達五分鐘的整個叢集網域名稱解析逾時或異常。關於IPVS缺陷導致解析異常的解決方案,請參見DNS解析異常問題排查。
根據建議策略自動調整
您可部署下方的
dns-autoscaler,它會參照前方提到的推薦策略(Pod數和叢集節點數1:8)即時自動調整CoreDNS的Pod數量。其中Pod數量的計算公式為replicas = max (ceil (cores × 1/coresPerReplica), ceil (nodes × 1/nodesPerReplica) ),且受到max、min限制。手動調整
您可通過下方的命令手動調整CoreDNS所屬的Pod數量。
kubectl scale --replicas={target} deployment/coredns -n kube-system # target替換為目標Pod數量請勿使用工作負載自動調整
雖然工作負載自動調整,例如容器水平伸縮(HPA)、容器定時水平伸縮(CronHPA)等也可以自動調整Pod數量,但是它們會頻繁執行擴縮容。由於前文所說的Pod縮容時導致的解析異常,請勿使用工作負載自動調整控制CoreDNS Pod數量。
調整CoreDNS Pod規格
另一種調整CoreDNS資源的方式是調整Pod規格。在ACK託管叢集Pro版中,CoreDNS Pod預設的記憶體限制為2Gi,CPU則未限制。推薦您將CPU Limit設定為4096m, 最小應不低於1024m。您可通過控制台對CoreDNS Pod配置進行調整。
調度CoreDNS Pod
錯誤的調度配置可能會導致CoreDNS Pod無法部署,導致CoreDNS失效。在執行此操作前,請您確保您已經非常瞭解調度相關知識。
建議您在部署CoreDNS Pod時,將其部署在不同可用性區域、不同叢集節點上,避免單節點、單可用性區域故障。版本低於v1.8.4.3的CoreDNS組件預設配置了按節點的弱反親和性,可能會因為節點資源不足導致部分或全部Pod部署在同一節點上,如果遇到這種情況,請刪除Pod觸發調度進行調整,或者升級組件版本到最新。CoreDNS 組件版本v1.8 以下版本不再維護,請儘快升級。
CoreDNS所啟動並執行叢集節點應避免CPU、記憶體用滿的情況,否則會影響網域名稱解析的QPS和響應延遲。當叢集節點條件允許時,可以考慮使用自訂參數將CoreDNS調度至獨立的叢集節點上,以提供穩定的網域名稱解析服務。
最佳化CoreDNS配置
Container ServiceACK僅提供CoreDNS的預設配置,您應關注配置中的各個參數,最佳化其配置,以使CoreDNS可以為您的業務容器正常提供DNS服務。CoreDNS的配置非常靈活,具體操作,請參見DNS策略配置和網域名稱解析說明與CoreDNS官方文檔。
早期版本隨Kubernetes叢集部署的CoreDNS預設配置可能存在一些風險,推薦您按以下方式檢查和最佳化:
您也可以通過容器智能營運中定時巡檢和故障診斷功能完成CoreDNS設定檔的檢查。當容器智能營運檢查結果中提示CoreDNS ConfigMap配置異常時,請逐個檢查以上專案。
CoreDNS重新整理配置過程中,可能會佔用額外記憶體。修改CoreDNS配置項後,請觀察Pod運行狀態,如果出現Pod記憶體不足的情況,請及時修改CoreDNS Deployment中容器記憶體限制,建議將記憶體調整至2 GB。
關閉kube-dns服務的親和性配置
親和性配置可能導致CoreDNS不同副本間存在較大負載差異,建議按以下步驟關閉:
控制台操作方式
登入Container Service管理主控台,在左側導覽列選擇叢集列表。
在叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇。
在kube-system命名空間下,單擊服務kube-dns右側的YAML編輯。
如果發現sessionAffinity欄位為
None,則無需進行以下步驟。如果發現sessionAffinity為
ClientIP,則進行以下步驟。
刪除sessionAffinity、sessionAffinityConfig及所有子鍵,然後單擊更新。
# 刪除以下所有內容。 sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 10800再次單擊服務kube-dns右側的YAML編輯,校正sessionAffinity欄位是否為
None,為None則Kube-DNS服務變更成功。
命令列方式
執行以下命令查看kube-dns服務配置資訊。
kubectl -n kube-system get svc kube-dns -o yaml如果發現sessionAffinity欄位為
None,則無需執行以下步驟。如果發現sessionAffinity為
ClientIP,則執行以下步驟。
執行以下命令開啟並編輯名為kube-dns的服務。
kubectl -n kube-system edit service kube-dns刪除sessionAffinity相關設定(sessionAffinity、sessionAffinityConfig及所有子鍵),並儲存退出。
# 刪除以下所有內容。 sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 10800修改完成後,再次運行以下命令查看sessionAffinity欄位是否為
None,為None則Kube-DNS服務變更成功。kubectl -n kube-system get svc kube-dns -o yaml
關閉Autopath外掛程式
部分早期版本的CoreDNS開啟了Autopath外掛程式,該外掛程式在一些極端情境下會導致解析結果出錯,請確認其是否處於開啟狀態,並編輯設定檔將其關閉。更多資訊,請參見Autopath。
關閉Autopath外掛程式後,用戶端發起的網域名稱解析請求QPS最高會增加3倍,解析單個網域名稱耗時最高增加3倍,請關注CoreDNS負載和業務影響。
執行
kubectl -n kube-system edit configmap coredns命令,開啟CoreDNS設定檔。刪除
autopath @kubernetes一行後儲存退出。檢查CoreDNS Pod運行狀態和作業記錄,作業記錄中出現
reload字樣後說明修改成功。
配置CoreDNS優雅退出
lameduck是 CoreDNS 中的一種機制,用於實現優雅退出(Graceful Shutdown)。它可在CoreDNS需要停止或重啟時,確保正在處理的請求能夠正常完成,而不會突然中斷。lameduck的工作原理如下:
當CoreDNS進程將要終止時,它會進入 Lameduck 模式。
在
lameduck模式下,CoreDNS會停止接收新的請求,但會繼續處理已經接收到的請求,直到請求全部完成或超過lameduck逾時時間。
控制台操作方式
登入Container Service管理主控台,在左側導覽列選擇叢集列表。
在叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇。
在kube-system命名空間下,單擊配置項coredns右側的YAML編輯。
參考下列的CoreDNS設定檔,保證health外掛程式開啟,並調整lameduck逾時時間為
15s,然後單擊確定。
.:53 {
errors
# health外掛程式在不同的CoreDNS版本中可能有不同的設定情形。
# 情形一:預設未啟用health外掛程式。
# 情形二:預設啟用health外掛程式,但未設定lameduck時間。
# health
# 情形三:預設啟用health外掛程式,設定了lameduck時間為5s。
# health {
# lameduck 5s
# }
# 對於以上三種情形,應統一修改成以下,調整lameduck參數為15s。
health {
lameduck 15s
}
# 其它外掛程式不需要修改,此處省略。
}如果CoreDNS Pod正常運行則說明CoreDNS優雅退出的配置更新成功。如果CoreDNS Pod出現異常,可以通過查看Pod事件及日誌定位原因。
命令列操作方式
執行以下命令開啟CoreDNS設定檔。
參考下列的Corefile檔案,保證
health外掛程式開啟,並調整lameduck參數為15s。修改CoreDNS設定檔後儲存退出。
如果CoreDNS正常運行則說明CoreDNS優雅退出的配置更新成功。如果CoreDNS Pod出現異常,可以通過查看Pod事件及日誌定位原因。
kubectl -n kube-system edit configmap/coredns.:53 {
errors
# health外掛程式在不同的CoreDNS版本中可能有不同的設定情形。
# 情形一:預設未啟用health外掛程式。
# 情形二:預設啟用health外掛程式,但未設定lameduck時間。
# health
# 情形三:預設啟用health外掛程式,設定了lameduck時間為5s。
# health {
# lameduck 5s
# }
# 對於以上三種情形,應統一修改成以下,調整lameduck參數為15s。
health {
lameduck 15s
}
# 其它外掛程式不需要修改,此處省略。
}配置Forward外掛程式與上遊VPC DNS伺服器的預設協議
NodeLocal DNSCache採用TCP協議與CoreDNS進行通訊,CoreDNS會根據請求來源使用的協議與上遊DNS伺服器進行通訊。因此預設情況下,來自業務容器的叢集外部網域名稱解析請求會依次經過NodeLocal DNSCache、CoreDNS,最終以TCP協議請求VPC內DNS伺服器,即ECS上預設配置的100.100.2.136和100.100.2.138兩個 IP。
VPC內DNS伺服器對TCP協議支援有限,如果您使用了NodeLocal DNSCache,您需要修改CoreDNS配置,讓其總是優先採用UDP協議與上遊DNS伺服器進行通訊,避免解析異常。建議您使用以下方式修改CoreDNS設定檔,即修改命名空間kube-system下名為coredns的ConfigMap。具體操作,請參見管理配置項。在forward外掛程式中指定請求上遊的協議為prefer_udp,修改之後CoreDNS會優先使用UDP協議與上遊通訊。修改方式如下所示:
# 修改前
forward . /etc/resolv.conf
# 修改後
forward . /etc/resolv.conf {
prefer_udp
}配置Ready就緒探針外掛程式
大於1.5.0版本的CoreDNS必須配置ready外掛程式以啟用就緒探針。
執行如下命令,開啟CoreDNS設定檔。
kubectl -n kube-system edit configmap/coredns檢查是否包含
ready一行,若無,則增加ready一行,按Esc鍵、輸入:wq!並按Enter鍵,儲存修改後的設定檔並退出編輯模式。apiVersion: v1 data: Corefile: | .:53 { errors health { lameduck 15s } ready # 如果沒有這一行,請增加本行,注意縮排與Kubernetes保持一致。 kubernetes cluster.local in-addr.arpa ip6.arpa { pods verified fallthrough in-addr.arpa ip6.arpa } prometheus :9153 forward . /etc/resolv.conf { max_concurrent 1000 prefer_udp } cache 30 loop log reload loadbalance }檢查CoreDNS Pod運行狀態和作業記錄,作業記錄中出現
reload字樣後說明修改成功。

