診斷流程的基本概念
集群內部域名:CoreDNS會將集群中的服務暴露為集群內部域名,默認以.cluster.local結尾,這類域名的解析通過CoreDNS內部緩存完成,不會從上游DNS服務器查詢。
VPC、地域內部域名:在VPC、地域內DNS服務器中注冊的天翼云各產品內部服務域名,默認以.cnsp-internal.daliqc.cn結尾,這類域名通常與地域、VPC相關,由CoreDNS的上游DNS服務器負責解析,CoreDNS僅做解析請求轉發。
公網域名:在第三方DNS服務商、天翼云DNS云解析等產品注冊的權威解析,這類域名由CoreDNS的上游DNS服務器負責解析,CoreDNS僅做解析請求轉發。
業務Pod:部署在Kubernetes集群中的容器Pod,特指非Kubernetes自身系統組件的容器。
使用CoreDNS的業務Pod:容器內DNS服務器地址為CoreDNS的Service IP(查看容器/etc/resolv.conf文件得到的DNS服務器地址與CoreDNS的Service IP相同)。
使用NodeLocal DNSCache的業務Pod:集群中安裝了NodeLocal DNSCache插件后,通過自動或手動方式注入DNSConfig的業務Pod。這類Pod在解析域名時,會優先訪問本地緩存組件。在訪問本地緩存組件不通或無DNS緩存記錄時,會再次訪問CoreDNS提供的kube-dns服務。
異常診斷流程
檢查業務Pod的DNS配置
#以default命名空間的nginx容器為例
#查看nginx容器的YAML配置,并確認DNSPolicy字段是否符合預期。
kubectl get pod nginx-xxxxxxxxx-xxxxx -n default -o yaml
#當DNSPolicy符合預期時,可以進一步進入Pod容器中,查看實際生效的DNS配置。
#通過bash命令進入nginx容器,若bash不存在可使用sh代替。
kubectl exec -it nginx-xxxxxxxxx-xxxxx -n default bash
#進入容器后,可以查看DNS配置,nameserver后面為DNS服務器地址。
cat /etc/resolv.conf檢查業務Pod的DNS配置
DNS Policy示例如下所示
apiVersion: v1
kind: Pod
metadata:
name: nginx-xxxxxxxxx-xxxxx
namespace: default
spec:
containers:
- image: <container-image>
name: <container-name>
#默認場景下的DNS Policy。
dnsPolicy: ClusterFirst
#使用了NodeLocal DNSCache時的DNS Policy。
dnsPolicy: None
dnsConfig:
nameservers:
- 192.168.0.10
- 10.96.0.10
options:
- name: ndots
value: "3"
- name: timeout
value: "1"
- name: attempts
value: "2"
searches:
- default.svc.cluster.local
- svc.cluster.local
- cluster.local
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30| DNSPolicy字段值 | 使用的DNS服務器 |
| ClusterFirst | 此為DNSPolicy默認值,Pod會將CoreDNS提供的kube-dns服務IP作為DNS服務器。開啟HostNetwork的Pod,如果選擇ClusterFirst模式,效果等同于Default模式。 |
| ClusterFirstWithHostNet | 開啟HostNetwork的Pod,如果選擇ClusterFirstWithHostNet模式,效果等同于ClusterFirst。 |
| None | 配合DNSConfig字段,可用于自定義DNS服務器和參數。在NodeLocal DNSCache開啟注入時,DNSConfig會將DNS服務器指向本地緩存IP及CoreDNS提供的kube-dns服務IP。 |
| Default | 只適用于不需要訪問集群內部服務的場景。Pod創建時會從主機節點/etc/resolv.conf文件繼承DNS服務器列表。 |
檢查CoreDNS Pod運行狀態
執行以下命令,查看容器組信息
# kubectl -n kube-system get pod -o wide -l k8s-app=kube-dns
NAME READY STATUS RESTARTS AGE IP NODE
coredns-xxxxxxxxx-xxxxx 1/1 Running 0 2h 172.16.6.53 192.168.0.1執行以下命令,查看Pod的實時資源使用情況(依賴于metrics-server采集相關數據,需要事先安裝監控組件cube-metrics-server)。
# kubectl -n kube-system top pod -l k8s-app=kube-dns
NAME CPU(cores) MEMORY(bytes)
coredns-xxxxxxxxx-xxxxx 4m 20Mi如果Pod不處于Running狀態,可以通過kubectl -n kube-system describe podcoredns-xxxxxxxxx-xxxxx命令,查詢問題原因。
檢查CoreDNS運行日志
執行以下命令,輸出CoreDNS Pod最新的500行日志和對應的日志時間。
# kubectl -n kube-system logs --tail=500 --timestamps coredns-xxxxxxxxx-xxxxx檢查CoreDNS DNS查詢請求日志
DNS查詢請求日志僅會在開啟CoreDNS的log插件后,才會打印到容器日志中。
開啟log插件的具體操作如下:
通過控制臺或命令行工具編輯kube-system命名空間下的coredns configmap,增加log模塊
# kubectl edit configmap -n kube-system coredns
Corefile: |
.:53 {
errors
log
health {
lameduck 15s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
prefer_udp
}
cache 30
loop
reload
loadbalance
}檢查CoreDNS Pod的網絡連通性
登錄CoreDNS Pod所在集群節點。
執行ps aux | grep coredns,查詢CoreDNS的進程ID。
執行nsenter -t <pid> -n bash,進入CoreDNS所在容器網絡命名空間,其中pid為上一步得到的進程ID。
測試網絡連通性
運行telnet <apiserver_clusterip> 6443,測試Kubernetes API Server的連通性。其中apiserver_clusterip為default命名空間下Kubernetes服務的IP地址,默認為10.96.0.1。
運行dig <domain> @<upstream_dns_server_ip>,測試CoreDNS Pod到上游DNS服務器的連通性。其中domain為測試域名,upstream_dns_server_ip為上游DNS服務器地址。
常見問題
現象 原因 處理方案 業務Pod無法通過CoreDNS服務IP解析 機器負載高、kube-proxy沒有正常運行、安全組沒有放開UDP協議53端口等。 檢查安全組是否放開UDP 53端口,若已放開請提交工單排查。 業務Pod無法連通CoreDNS容器副本 容器網絡異常或安全組沒有放開ICMP。 檢查安全組是否放開ICMP,若已放開請提交工單排查。 業務Pod無法通過CoreDNS容器IP解析 機器負載高、安全組沒有放開UDP協議53端口等。 檢查安全組是否放開UDP 53端口,若已放開請提交工單排查。
檢查業務Pod到CoreDNS的網絡連通性
選擇以下任意一種方式,進入客戶端Pod容器網絡。
方法一(適合鏡像本身含有sh、ping等命令的Pod):
使用kubectl exec -it -n <命名空間> <PodName> /bin/sh命令進入到Pod中。
方法二(適合鏡像本身不含常用命令、且穩定運行的Pod):
登錄業務Pod所在集群節點。
執行ps aux | grep <業務進程名>命令,查詢業務容器的進程ID。
執行nsenter -t <pid> -n bash命令,進入業務Pod所在容器網絡命名空間。其中pid為上一步得到的進程ID。
方法三:(適合頻繁重啟的Pod)
如果運行時是docker:登錄業務Pod所在集群節點。
執行docker ps -a | grep <業務容器名>命令,查詢k8s_POD_ 開頭、使用鏡像為pause的沙箱容器,記錄容器ID。
執行docker inspect <沙箱容器 ID> | grep netns命令,查詢/var/run/docker/netns/xxxx的容器網絡命名空間路徑。
執行nsenter -n<netns 路徑> bash命令,進入容器網絡命名空間。(其中netns 路徑為上一步得到的路徑,且-n和<netns 路徑>之間不加空格)。
如果運行時是containerd:登錄業務Pod所在集群節點,執行crictl ps -a | grep <PodName>根據Pod名稱查看容器id。
根據查到的容器id,執行ctr -n k8s.io container ls | grep <容器id>查找完整的容器id(ctr使用的時候,必須寫全,而docker對于id的長度沒要求)
執行ctr -n k8s.io container info <完整的容器id> | grep -i pid -C 3獲取業務Pod中pause容器的pid
path里面的數字即為pause容器的pid。
執行nsenter -t <pid> -n 進入容器網絡命名空間。
進入容器網絡命名空間后,測試網絡連通性。
執行dig <domain> @<kube_dns_svc_ip>命令,測試業務Pod到CoreDNS服務kube-dns解析查詢的連通性。其中<domain>為測試域名,<kube_dns_svc_ip>為kube-system命名空間中kube-dns的服務IP。默認為10.96.0.10。
執行ping <coredns_pod_ip>命令,測試業務Pod到CoreDNS容器副本的連通性。其中<coredns_pod_ip>為kube-system命名空間中CoreDNS Pod的IP。
執行dig <domain> @<coredns_pod_ip>命令,測試業務Pod到CoreDNS容器副本解析查詢的連通性。其中<domain>為測試域名,<coredns_pod_ip>為kube-system命名空間中CoreDNS Pod的IP。
常見問題
| 現象 | 原因 | 處理方案 |
| 業務Pod無法通過CoreDNS服務IP解析 | 機器負載高、kube-proxy沒有正常運行、安全組沒有放開UDP協議53端口等。 | 檢查安全組是否放開UDP 53端口,若已放開請提交工單排查。 |
| 業務Pod無法連通CoreDNS容器副本 | 容器網絡異常或安全組沒有放開ICMP。 | 檢查安全組是否放開ICMP,若已放開請提交工單排查。 |
| 業務Pod無法通過CoreDNS容器IP解析 | 機器負載高、安全組沒有放開UDP協議53端口等。 | 檢查安全組是否放開UDP 53端口,若已放開請提交工單排查。 |
當無法定位問題時,需要抓包進行輔助診斷。在正常情況下,抓包對業務無影響,僅會增加小部分的CPU負載和磁盤寫入。
登錄出現異常的業務Pod、CoreDNS Pod所在節點。
在ECS(非容器內)執行以下命令 tcpdump -i any port 53 -C 20 -W 200 -w /tmp/client_dns.pcap ,可以將最近所有的53端口信息抓取到文件中。以上命令會對抓取到的包進行rotate,最多可以寫200個20 MB的.pcap文件。
結合業務日志的報錯定位到精準的報錯時間的報文信息。
集群外部域名解析異常
問題現象
業務Pod可以正常解析集群內部域名,但無法解析某些集群外部域名。
問題原因
上游服務器域名解析返回異常。
解決方案
修改CoreDNS配置文件corefile,開啟log模塊以打印查詢請求日志,檢查CoreDNS DNS查詢請求日志。
常見請求日志
CoreDNS接收到請求并回復客戶端后會打印一行日志,示例如下:
# 其中包含狀態碼RCODE NOERROR,代表解析結果正常返回。
[INFO] 172.20.2.25:44525 - 36259 "A IN nginx.default.svc.cluster.local. udp 56 false 512" NOERROR qr,aa,rd 110 0.000116946s常見返回碼RCODE
| 返回碼RCODE | 含義 | 原因 |
| NXDOMAIN | 域名不存在 | 容器內請求域名時,會被拼接上search后綴,若拼接的結果域名不存在,則會出現該請求碼。如果確認日志中請求的域名內容存在,則說明存在異常。 |
| SERVFAIL | 上游服務器異常 | 常見于無法連接上游DNS服務器等情況。 |
| REFUSED | 拒絕應答 | 常見于CoreDNS配置或集群節點/etc/resolv.conf文件指向的上游DNS服務器無法處理該域名的情況,請排查CoreDNS配置文件。 |
當CoreDNS DNS查詢請求日志中顯示集群外部域名返回為NXDOMAIN、SERVFAIL、REFUSED時,說明CoreDNS的上游DNS服務器返回異常。請提交工單排查。
StatefulSets Pod域名無法解析
問題現象
Headless服務無法通過Pod域名解析。
問題原因
StatefulSets Pod YAML中ServiceName必須和其暴露SVC的名字一致,否則無法訪問Pod域名(例如pod.headless-svc.ns.svc.cluster.local),只能訪問到服務域名(例如headless-svc.ns.svc.cluster.local)。
解決方案
修改StatefulSets Pod YAML中ServiceName名稱,確保和其暴露SVC的名字一致。
CoreDNS Pod負載高
問題現象
部分節點或全部節點接入CoreDNS的業務,Pod解析域名的延遲增加、概率性或持續性失敗。
檢查CoreDNS Pod運行狀態發現各副本CPU、Memory使用量接近其資源限制。
問題原因
由于CoreDNS副本數不足、業務請求量高等情況導致的CoreDNS負載高。
解決方案
考慮采用NodeLocal DNSCache緩存方案,提升DNS解析性能,降低CoreDNS負載。
適當擴充CoreDNS副本數。
常見請求日志
CoreDNS Pod負載不均
問題現象
部分接入CoreDNS的業務Pod解析域名的延遲增加、概率性或持續性失敗。
檢查CoreDNS Pod運行狀態發現各副本CPU使用量負載不均衡。CoreDNS副本數少于兩個,或多個CoreDNS副本位于同節點上。
問題原因
由于CoreDNS副本調度不均、Service親和性設置導致CoreDNS Pod負載不均衡。
解決方案
擴容并打散CoreDNS副本到不同的節點上。參考:合理分配CoreDNS副本運行的位置。
負載不均衡時,可禁用kube-dns服務的親和性屬性。參考:關閉kube-dns服務的session親和性配置。
合理分配CoreDNS副本運行的位置
建議您在部署CoreDNS副本時,應將CoreDNS副本打散在不同可用區、不同集群節點上,避免單節點、單可用區故障。CoreDNS默認配置了按節點的弱反親和性,可能會因為節點資源不足導致部分或全部副本部署在同一節點上,如果遇到這種情況,請刪除Pod重新觸發其調度來調整。
CoreDNS所運行的集群節點應避免CPU、內存用滿的情況,否則會影響域名解析的QPS和響應延遲。當集群節點條件允許時,可以考慮使將CoreDNS調度至獨立的集群節點上,以提供穩定的域名解析服務。
手動擴容副本數
當集群節點數長時間較為固定時,您可以通過以下命令擴容CoreDNS副本數,如:擴容副本數為3。
kubectl scale --replicas=3 deployment/coredns -n kube-system關閉kube-dns服務的session親和性配置
session親和性配置可能導致CoreDNS不同副本間存在較大負載差異,建議按以下步驟關閉。
控制臺操作方式
登錄云容器引擎管理控制臺。
在控制臺左側導航欄中,點擊集群。
在集群列表頁面中,點擊目標集群名稱。
在集群管理頁左側導航欄中,選擇網絡 > 服務。
在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 yamlA記錄和AAAA記錄并發解析異常
問題現象
接入CoreDNS的業務Pod解析域名概率性失敗。
從抓包或檢查CoreDNS DNS查詢請求日志可以發現,A和AAAA通常在同一時間的出現,并且請求的源端口一致。
問題原因
并發A和AAAA的DNS請求觸發Linux內核Conntrack模塊缺陷,導致UDP報文丟失。
解決方案
考慮采用NodeLocal DNSCache緩存方案,提升DNS解析性能,降低CoreDNS負載。
CentOS、Ubuntu等基礎鏡像,可以通過options timeout:2 attempts:3 rotate single-request-reopen等參數優化。
如果容器鏡像是以Alpine制作的,建議更換基礎鏡像。
PHP類應用短連接解析問題較多,如果使用的是PHP Curl的調用,可以使用CURL_IPRESOLVE_V4參數僅發送IPv4解析。
NodeLocal DNSCache未生效
問題現象
NodeLocal DNSCache沒有流量進入,所有請求仍在CoreDNS上。
問題原因
未配置DNSConfig注入,業務Pod實際仍配置了CoreDNS kube-dns服務IP作為DNS服務器地址。
業務Pod采用Alpine作為基礎鏡像,Alpine基礎鏡像會并發請求所有nameserver,包括本地緩存和CoreDNS。
解決方案
配置DNSConfig自動注入。
如果容器鏡像是以Alpine制作的,建議更換基礎鏡像。