DNS是Kubernetes叢集中至關重要的基礎服務之一,在用戶端設定不合理、叢集規模較大等情況下DNS容易出現解析逾時、解析失敗等現象。本文介紹Kubernetes叢集中DNS的最佳實務,協助您避免此類問題。
前提條件
本文目錄
DNS最佳實務包含用戶端和服務端的內容:
在用戶端,您可以通過最佳化網域名稱解析請求降低解析延遲,通過使用合適的容器鏡像、合適的節點作業系統 、節點DNS緩衝NodeLocal DNSCache等方式來減少解析異常。
在CoreDNS服務端,您可以通過監控CoreDNS運行狀態識別DNS異常,快速定位異常根因,通過合理調整叢集CoreDNS部署狀態來提升叢集CoreDNS高可用和QPS吞吐。
有關CoreDNS的更多資訊,請參見CoreDNS官方文檔。
最佳化網域名稱解析請求
DNS網域名稱解析請求是Kubernetes最高頻的網路行為之一,其中很多請求是可以最佳化和避免的。您可以通過以下方式最佳化網域名稱解析請求:
(推薦)使用串連池:當一個容器應用需要頻繁請求另一服務時,推薦使用串連池。串連池可以將請求上遊服務的連結緩衝在記憶體中,避免每次訪問時網域名稱解析和TCP建連的開銷。
使用DNS緩衝:
(推薦)當您的應用無法改造成通過串連池串連另一服務時,可以考慮在應用側緩衝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.來訪問。
使用合適的容器鏡像
Alpine容器鏡像內建的musl libc庫與標準glibc的實現存在以下差異:
3.3及更早版本Alpine不支援search參數,不支援搜尋域,無法完成服務發現。
並發請求/etc/resolv.conf中配置的多個DNS伺服器,導致NodeLocal DNSCache最佳化失效。
並發使用同一Socket請求A和AAAA記錄,在舊版本核心上觸發Conntrack源連接埠衝突導致丟包問題。
關於以上問題的更多資訊,請參見musl libc。
當Kubernetes叢集中部署的容器採用了Alpine作為基礎鏡像時,可能會因為上述musl libc特性而無法正常解析網域名稱,建議嘗試更換基礎鏡像,如Debian、CentOS等。
避免IPVS缺陷導致的DNS機率性解析逾時問題
當叢集使用IPVS作為kube-proxy負載平衡模式時,您可能會在CoreDNS縮容或重啟時遇到DNS機率性解析逾時的問題。該問題由社區Linux核心缺陷導致,具體資訊,請參見IPVS。
您可以通過以下任意方式降低IPVS缺陷的影響:
使用節點DNS緩衝NodeLocal DNSCache,具體操作,請參見使用節點DNS緩衝NodeLocal DNSCache。
修改kube-proxy中IPVS UDP會話保持的逾時時間,具體操作,請參見如何修改kube-proxy中IPVS UDP會話保持的逾時時間?。
使用節點DNS緩衝NodeLocal DNSCache
在ACK叢集中部署NodeLocal DNSCache可以提升服務發現的穩定性和效能,NodeLocal DNSCache通過在叢集節點上作為DaemonSet運行DNS緩衝代理來提高叢集DNS效能。
關於更多NodeLocal DNSCache的介紹及如何在ACK叢集中部署NodeLocal DNSCache的具體步驟,請參見使用NodeLocal DNSCache。
使用合適的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及以上 | v1.8.4.1-3a376cc-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應部署於您的Kubernetes叢集中,預設情況下與您的業務容器運行在同樣的叢集節點上,注意事項如下:
合理調整CoreDNS副本數
建議您在任何情況下設定CoreDNS副本數應至少為2,且副本數維持在一個合適的水位以承載整個叢集的解析。
CoreDNS所能提供的網域名稱解析QPS與CPU消耗成正相關,開啟緩衝的情況下,單個CPU可以支撐10000+ QPS的網域名稱解析請求。不同類型的業務對網域名稱請求的QPS需求存在較大差異,您可以觀察每個CoreDNS副本的峰值CPU使用量,如果其在業務峰值期間佔用CPU大於一核,建議您對CoreDNS進行副本擴容。無法確定峰值CPU使用量時,可以保守採用副本數和叢集節點數1:8的比值來部署,即每擴容8個叢集節點,增加一個CoreDNS副本,但副本數不應大於10。針對100節點以上的叢集,推薦使用節點DNS緩衝NodeLocal DNSCache。具體操作,請參見使用節點DNS緩衝NodeLocal DNSCache。
當叢集節點數目長時間較為固定時,可以手動擴容副本數。具體操作,請參見手動擴容副本數。
如果叢集節點數持續增長,可以設定自動擴容副本數。具體操作,請參見自動擴容副本數(cluster-autoscaler)。
UDP報文缺少重傳機制,在CoreDNS副本停止過程中,CoreDNS任意副本縮容或重啟可能會導致接收到的UDP報文丟失,觸發整個叢集網域名稱解析逾時或異常。當叢集節點存在IPVS UDP缺陷導致的丟包風險時,CoreDNS任意副本縮容或重啟可能會導致長達五分鐘的整個叢集網域名稱解析逾時或異常。關於IPVS缺陷導致解析異常的解決方案,請參見IPVS缺陷導致解析異常。
合理分配CoreDNS副本啟動並執行位置
建議您在部署CoreDNS副本時,應將CoreDNS副本打散在不同可用性區域、不同叢集節點上,避免單節點、單可用性區域故障。CoreDNS預設配置了按節點的弱反親和性,可能會因為節點資源不足導致部分或全部副本部署在同一節點上,如果遇到這種情況,請刪除Pod重新觸發其調度來調整。
CoreDNS所啟動並執行叢集節點應避免CPU、記憶體用滿的情況,否則會影響網域名稱解析的QPS和響應延遲。當叢集節點條件允許時,可以考慮使用自訂參數將CoreDNS調度至獨立的叢集節點上,以提供穩定的網域名稱解析服務。關於CoreDNS調度至獨立的叢集節點的方式,請參見使用自訂參數完成CoreDNS獨佔部署。
手動擴容副本數
當叢集節點數長時間較為固定時,您可以通過以下命令擴容CoreDNS副本數。
kubectl scale --replicas={target} deployment/coredns -n kube-system
將目標副本數{target}
設定成目標值。
自動擴容副本數(cluster-autoscaler)
當叢集節點數不斷增長時,您可以通過以下YAML部署叢集水平伸縮器cluster-proportional-autoscaler動態擴容副本數量:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dns-autoscaler
namespace: kube-system
labels:
k8s-app: dns-autoscaler
spec:
selector:
matchLabels:
k8s-app: dns-autoscaler
template:
metadata:
labels:
k8s-app: dns-autoscaler
spec:
serviceAccountName: admin
containers:
- name: autoscaler
image: registry.cn-hangzhou.aliyuncs.com/acs/cluster-proportional-autoscaler:1.8.4
resources:
requests:
cpu: "200m"
memory: "150Mi"
command:
- /cluster-proportional-autoscaler
- --namespace=kube-system
- --configmap=dns-autoscaler
- --nodelabels=type!=virtual-kubelet
- --target=Deployment/coredns
- --default-params={"linear":{"coresPerReplica":64,"nodesPerReplica":8,"min":2,"max":100,"preventSinglePointFailure":true}}
- --logtostderr=true
- --v=9
上述使用線程伸縮策略中,CoreDNS副本數的計算公式為replicas = max (ceil (cores × 1/coresPerReplica), ceil (nodes × 1/nodesPerReplica) ),且CoreDNS副本數受到max
、min
限制。線程伸縮策略參數如下。
{
"coresPerReplica": 64,
"nodesPerReplica": 8,
"min": 2,
"max": 100,
"preventSinglePointFailure": true
}
基於CPU負載指標自動擴容副本數(HPA)
由於HPA會頻繁觸發CoreDNS副本縮容,建議您不要使用容器水平擴縮容(HPA),如果您的情境下必須依賴於HPA,請參考以下基於CPU負載的策略配置:
---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: coredns-hpa
namespace: kube-system
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: coredns
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 50
關於HPA使用方式的更多資訊,請參見容器水平伸縮(HPA)。
使用自訂參數完成CoreDNS獨佔節點部署
登入Container Service管理主控台,在左側導覽列單擊叢集。
在叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇
。在節點頁面,單擊標籤與汙點管理。
在標籤與汙點管理頁面,選中目標節點,單擊添加標籤。
說明節點數應大於CoreDNS副本數,避免單個節點上運行多個CoreDNS副本。
在添加對話方塊中,設定以下參數,然後單擊確定。
名稱:node-role.kubernetes.io/coredns
值:true
在叢集管理頁左側導覽列中,選擇
,然後搜尋CoreDNS。單擊CoreDNS卡片的配置,在配置對話方塊,單擊NodeSelector右側的+,設定以下參數,然後單擊確定。
Key:node-role.kubernetes.io/coredns
Value:true
CoreDNS會重新調度至指定標籤的節點上。
合理配置CoreDNS
Container ServiceACK僅提供CoreDNS的預設配置,您應關注配置中的各個參數,最佳化其配置,以使CoreDNS可以為您的業務容器正常提供DNS服務。CoreDNS的配置非常靈活,具體操作,請參見DNS原理和配置說明和CoreDNS官方文檔。
早期版本隨Kubernetes叢集部署的CoreDNS預設配置可能存在一些風險,推薦您按以下方式檢查和最佳化:
您也可以通過容器智能營運中定時巡檢和故障診斷功能完成CoreDNS設定檔的檢查。當容器智能營運檢查結果中提示CoreDNS Configmap配置異常時,請逐個檢查以上專案。
合理調整CoreDNS的資源Request和Limit
CoreDNS的資源消耗具有以下特點:
CoreDNS啟動、設定檔重新載入,APIServer串連、重連的過程中,CPU和記憶體佔用會有增加。
CoreDNS的CPU佔用和其承載的網域名稱QPS呈正相關。
CoreDNS的記憶體佔用和叢集規模、Service數量呈正相關。
部署CoreDNS時採用的預設資源Request和Limit如下表,建議您根據叢集實際運行情況及時做出調整,具體操作,請參見營運管理-組件管理-網路-CoreDNS-參數配置。
資源類型 | Request/Limit | 預設值 | 備忘 |
CPU | Request | 100m | 無 |
Limit | 不設定 | 調低該值會影響CoreDNS能提供的網域名稱解析QPS。 | |
記憶體 | Request | 100 Mi | 無 |
Limit | 2 Gi | 調低該值可能會有記憶體不足OOM風險。 |
低於1.8.4版本的CoreDNS預設設定可能會與上表有所差異,請進行調整。
關閉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優雅退出
CoreDNS重新整理配置過程中,可能會佔用額外記憶體。修改CoreDNS配置項後,請觀察Pod運行狀態,如果出現Pod記憶體不足的情況,請及時修改CoreDNS Deployment中容器記憶體限制,建議將記憶體調整至2 GB。
控制台操作方式
在控制台左側導覽列中,單擊叢集。
在叢集列表頁面中,單擊目的地組群名稱或者目的地組群右側操作列下的詳情。
在叢集管理頁左側導覽列中,選擇
。在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
外掛程式中指定請求上遊的協議為perfer_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
字樣後說明修改成功。