k8s集群排錯指南


排查集群狀態異常問題通常從 Node 和 Kubernetes 服務 的狀態出發,常見的有

  • kube-apiserver 無法啟動會導致

    • 集群不可訪問

    • 已有的 Pod 和服務正常運行(依賴於 Kubernetes API 的除外)

  • etcd 集群異常會導致

    • kube-apiserver 無法正常讀寫集群狀態,進而導致 Kubernetes API 訪問出錯

    • kubelet 無法周期性更新狀態

  • kube-controller-manager/kube-scheduler 異常會導致

    • 復制控制器、節點控制器、雲服務控制器等無法工作,從而導致 Deployment、Service 等無法工作,也無法注冊新的 Node 到集群中來

    • 新創建的 Pod 無法調度(總是 Pending 狀態)

  • Node 本身宕機或者 Kubelet 無法啟動會導致

    • Node 上面的 Pod 無法正常運行

    • 已在運行的 Pod 無法正常終止

  • 網絡分區會導致 Kubelet 等與控制平面通信異常以及 Pod 之間通信異常

查看 Node 狀態

一般來說,可以首先查看 Node 的狀態,確認 Node 本身是不是 Ready 狀態

kubectl get nodes
kubectl describe node <node-name>

 如果是 NotReady 狀態,則可以執行 kubectl describe node <node-name> 命令來查看當前 Node 的事件。這些事件通常都會有助於排查 Node 發生的問題。

SSH 登錄 Node

在排查 Kubernetes 問題時,通常需要 SSH 登錄到具體的 Node 上面查看 kubelet、docker、iptables 等的狀態和日志。在使用雲平台時,可以給相應的 VM 綁定一個公網 IP;而在物理機部署時,可以通過路由器上的端口映射來訪問。但更簡單的方法是使用 SSH Pod (不要忘記替換成你自己的 nodeName):

# cat ssh.yaml
apiVersion: v1
kind: Service
metadata:
  name: ssh
spec:
  selector:
    app: ssh
  type: LoadBalancer
  ports:
  - protocol: TCP
    port: 22
    targetPort: 22
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: ssh
  labels:
    app: ssh
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ssh
  template:
    metadata:
      labels:
        app: ssh
    spec:
      containers:
      - name: alpine
        image: alpine
        ports:
        - containerPort: 22
        stdin: true
        tty: true
      hostNetwork: true
      nodeName: <node-name>
$ kubectl create -f ssh.yaml
$ kubectl get svc ssh
NAME      TYPE           CLUSTER-IP    EXTERNAL-IP      PORT(S)        AGE
ssh       LoadBalancer   10.0.99.149   52.52.52.52   22:32008/TCP   5m

接着,就可以通過 ssh 服務的外網 IP 來登錄 Node,如 ssh user@52.52.52.52

在使用完后, 不要忘記刪除 SSH 服務 kubectl delete -f ssh.yaml

查看日志

一般來說,Kubernetes 的主要組件有兩種部署方法

  • 直接使用 systemd 等啟動控制節點的各個服務

  • 使用 Static Pod 來管理和啟動控制節點的各個服務

使用 systemd 等管理控制節點服務時,查看日志必須要首先 SSH 登錄到機器上,然后查看具體的日志文件。如

journalctl -l -u kube-apiserver
journalctl -l -u kube-controller-manager
journalctl -l -u kube-scheduler
journalctl -l -u kubelet
journalctl -l -u kube-proxy

或者直接查看日志文件

  • /var/log/kube-apiserver.log

  • /var/log/kube-scheduler.log

  • /var/log/kube-controller-manager.log

  • /var/log/kubelet.log

  • /var/log/kube-proxy.log

而對於使用 Static Pod 部署集群控制平面服務的場景,可以參考下面這些查看日志的方法。

kube-apiserver 日志

PODNAME=$(kubectl -n kube-system get pod -l component=kube-apiserver -o jsonpath='{.items[0].metadata.name}')
kubectl -n kube-system logs $PODNAME --tail 100

 kube-controller-manager 日志

PODNAME=$(kubectl -n kube-system get pod -l component=kube-controller-manager -o jsonpath='{.items[0].metadata.name}')
kubectl -n kube-system logs $PODNAME --tail 100

 kube-scheduler 日志

PODNAME=$(kubectl -n kube-system get pod -l component=kube-scheduler -o jsonpath='{.items[0].metadata.name}')
kubectl -n kube-system logs $PODNAME --tail 100

 kube-dns 日志

PODNAME=$(kubectl -n kube-system get pod -l k8s-app=kube-dns -o jsonpath='{.items[0].metadata.name}')
kubectl -n kube-system logs $PODNAME -c kubedns

 Kubelet 日志

查看 Kubelet 日志需要首先 SSH 登錄到 Node 上。

journalctl -l -u kubelet

 Kube-proxy 日志

Kube-proxy 通常以 DaemonSet 的方式部署

$ kubectl -n kube-system get pod -l component=kube-proxy
NAME               READY     STATUS    RESTARTS   AGE
kube-proxy-42zpn   1/1       Running   0          1d
kube-proxy-7gd4p   1/1       Running   0          3d
kube-proxy-87dbs   1/1       Running   0          4d
$ kubectl -n kube-system logs kube-proxy-42zpn

 

 Kube-dns/Dashboard CrashLoopBackOff

由於 Dashboard 依賴於 kube-dns,所以這個問題一般是由於 kube-dns 無法正常啟動導致的。查看 kube-dns 的日志

$ kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c kubedns
$ kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c dnsmasq
$ kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c sidecar

 可以發現如下的錯誤日志

Waiting for services and endpoints to be initialized from apiserver...
skydns: failure to forward request "read udp 10.240.0.18:47848->168.63.129.16:53: i/o timeout"
Timeout waiting for initialization

這說明 kube-dns pod 無法轉發 DNS 請求到上游 DNS 服務器。解決方法為

  • 如果使用的 Docker 版本大於 1.12,則在每個 Node 上面運行 iptables -P FORWARD ACCEPT 開啟 Docker 容器的 IP 轉發

  • 等待一段時間,如果還未恢復,則檢查 Node 網絡是否正確配置,比如是否可以正常請求上游DNS服務器、是否開啟了 IP 轉發(包括 Node 內部和公有雲上虛擬網卡等)、是否有安全組禁止了 DNS 請求等

如果錯誤日志中不是轉發 DNS 請求超時,而是訪問 kube-apiserver 超時,比如

E0122 06:56:04.774977       1 reflector.go:199] k8s.io/dns/vendor/k8s.io/client-go/tools/cache/reflector.go:94: Failed to list *v1.Endpoints: Get https://10.0.0.1:443/api/v1/endpoints?resourceVersion=0: dial tcp 10.0.0.1:443: i/o timeout
I0122 06:56:04.775358       1 dns.go:174] Waiting for services and endpoints to be initialized from apiserver...
E0122 06:56:04.775574       1 reflector.go:199] k8s.io/dns/vendor/k8s.io/client-go/tools/cache/reflector.go:94: Failed to list *v1.Service: Get https://10.0.0.1:443/api/v1/services?resourceVersion=0: dial tcp 10.0.0.1:443: i/o timeout
I0122 06:56:05.275295       1 dns.go:174] Waiting for services and endpoints to be initialized from apiserver...
I0122 06:56:05.775182       1 dns.go:174] Waiting for services and endpoints to be initialized from apiserver...
I0122 06:56:06.275288       1 dns.go:174] Waiting for services and endpoints to be initialized from apiserver...

 這說明 Pod 網絡(一般是多主機之間)訪問異常,包括 Pod->Node、Node->Pod 以及 Node-Node 等之間的往來通信異常。可能的原因比較多,具體的排錯方法可以參考

Node NotReady

Node 處於 NotReady 狀態,大部分是由於 PLEG(Pod Lifecycle Event Generator)問題導致的。社區 issue #45419 目前還處於未解決狀態。

NotReady 的原因比較多,在排查時最重要的就是執行 kubectl describe node <node name> 並查看 Kubelet 日志中的錯誤信息。常見的問題及修復方法為:

  • Kubelet 未啟動或者異常掛起:重新啟動 Kubelet。

  • CNI 網絡插件未部署:部署 CNI 插件。

  • Docker 僵死(API 不響應):重啟 Docker。

  • 磁盤空間不足:清理磁盤空間,比如鏡像、臨時文件等。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM