前幾天有個朋友把他們的kubernetes叢集搞掛了,讓我幫忙恢復一下,由於很多現場都沒有了,這裡提供一下解決思路。
環境問題
該環境有一個master節點,即控制面pod(etcd、scheduler等)也都只有一個pod
問題起因是他們的服務訪問出了點問題,為修復該問題,他:
- 備份了etcd資料(資料是3天前的)
- 重啟了docker
- 將etcd資料恢復(資料是3天前的)
然後訪問服務依然不通。
問題診斷
deployment reversion不匹配
首先看到pod並非running
狀態,直接刪除pod,讓其重建,檢視pod建立過程,發現pod並沒有分配到node。
問題分析
首先懷疑可能kube-scheduler出現了問題:
- 刪除kube-scheduler 發現無法重建該pod
- 最後透過將
/etc/kubernetes/manifests/kube-scheduler.yaml
檔案移出再移入的方式建立出scheduler pod
此時仍然無法排程pod,因此懷疑是在scheduler之前出現了問題,檢視api-server的日誌,發現有很多reversion版本不匹配的錯誤,應該是叢集中的資源版本和etcd中的資源版本不匹配導致的:
-
使用etctctl檢查etcd的狀態,發現etcd一切正常
etcdctl endpoint health etcdctl endpoint status --write-out=table
-
使用
kubectl rollout history deployment/<deployment_name>
檢視etcd中儲存的的deployment的版本,然後執行kubectl rollout undo daemonset/<deployment_name> --to-revision=<version>
回滾到與etcd匹配的版本。回滾之前可以透過
kubectl rollout history daemonset/<deployment_name> --revision=<version>
對比etcd和環境中的配置區別 -
回滾之後發現pod可以正常建立出來
Iptables丟失問題
pod起來之後,服務訪問仍然不通。使用kubectl describe
命令檢視服務的service,發現沒有找到service對應的endpoints,一開始還以為是service的yaml的問題,debug了大半天發現絕大部分services都沒有endpoints。。。
問題分析
service找不到endpoints,體現在系統中就是可能沒有建立出iptables規則:
- 使用
iptables-save
命令檢視,發現果然沒有kubernetes的iptables規則 - 該環境使用的是ipvs模式,使用
ipvsadm -l -n
也發現service的cluster IP沒有對應的pod IP - 檢視kube-proxy日誌,並未發現任何異常
此時想到的方式有:
- 重新建立pod和對應的service,重新整理iptables:嘗試失敗,重建之後並未生成iptables
- 重建節點:所有節點都存在問題,無法透過
kubectl drain
遷移pod - 手動新增iptables:太過複雜,即便成功,也會汙染節點的iptables規則。
- 重新建立kube-proxy pod:重啟kube-proxy pod之後也並未建立iptables規則
最後懷疑kube-proxy也可能出現問題,需要重新初始化kube-proxy,恰好kubeadm有如下命令可以重新初始化kube-proxy:
kubeadm init phase addon kube-proxy --kubeconfig ~/.kube/config --apiserver-advertise-address <api-server-ip>
在重新初始化kube-proxy之後發現iptables規則建立成功,刪除並建立pod和service之後可以正確建立出對應的iptables規則,此時service也有了endpoints。
CNI連線錯誤
在上一步重啟pod之後,發現有一個webhook對應的pod沒有重啟成功,用kubectl describe
該pod發現如下錯誤:
networkPlugin cni failed to set up pod "webhook-1" network: Get "https://[10.233.0.1]:443/api/v1/namespaces/volcano-system": dial tcp 10.233.0.1:443: i/o timeout
該叢集使用的是calico CNI,檢視該CNI對應的daemonset,發現只有5個pod是ready的。
刪除"webhook-1" pod所在的節點的"calico-node" pod,發現該"calico-node" pod啟動失敗。
問題分析
在上述錯誤中,"10.233.0.1"為kubernetes apiserver的service cluster IP,由於"clico-node" pod使用的是hostnetwork
,因此可以直接在node上測試聯通性,使用telnet 10.233.0.1 443
測試,發現果然不通。
calico的/etc/cni/net.d/10-calico.conflist
配置檔案中定義了連線apiserver所需的kubeconfig
檔案:
{
"name": "cni0",
"cniVersion":"0.3.1",
"plugins":[
{
...
"kubernetes": {
"kubeconfig": "/etc/cni/net.d/calico-kubeconfig"
}
},
...
]
}
而/etc/cni/net.d/calico-kubeconfig
中就定義了連線apiserver所需的地址和埠,因此只需將該地址埠換成apiserver pod的地址和埠應該就可以解決該問題:
# cat /etc/cni/net.d/calico-kubeconfig
# Kubeconfig file for Calico CNI plugin.
apiVersion: v1
kind: Config
clusters:
- name: local
cluster:
server: https://[10.233.0.1]:443
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0...
users:
- name: calico
user:
token: eyJhbGciOiJSUzI1NiIsImtpZC...
contexts:
- name: calico-context
context:
cluster: local
user: calico
Calico提供瞭如下兩個環境變數用於修改生成的kubeconfig中的apiserver的地址和埠,將如下環境變數加入calico的daemonset,重新建立calico-node
pod即可:
- name: KUBERNETES_SERVICE_HOST
value: <api-server-pod-ip>
- name: KUBERNETES_SERVICE_PORT
value: <api-server-pod-port>
至此,問題基本解決。由於錯誤的操作,該叢集出現了大量問題,後續可以透過驅逐節點pod的方式,重新初始化整個節點,逐步重置叢集節點配置。