前几天有个朋友把他们的kubernetes集群搞挂了,让我帮忙恢复一下,由于很多现场都没有了,这里提供一下解决思路。
环境问题
该环境有一个master节点,即控制面pod(etcd、scheduler等)也都只有一个pod
问题起因是他们的服务访问出了点问题,为修复该问题,他:
- 备份了etcd数据(数据是3天前的)
- 重启了docker
- 将etcd数据恢复(数据是3天前的)
然后访问服务依然不通。
问题诊断
deployment reversion不匹配
首先看到pod并非running
状态,直接删除pod,让其重建,查看pod创建过程,发现pod并没有分配到node。
问题分析
首先怀疑可能kube-scheduler出现了问题:
- 删除kube-scheduler pod发现无法重建该pod
- 最后通过将
/etc/kubernetes/manifests/kube-scheduler.yaml
文件移出再移入的方式创建出scheduler pod
此时仍然无法调度pod,因此怀疑是在scheduler之前出现了问题,查看api-server的日志,发现有很多reversion版本不匹配的错误,应该是集群中的资源版本和etcd中的资源版本不匹配导致的:
-
使用etctctl检查etcd的状态,发现etcd一切正常
shetcdctl 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:
sh
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发现如下错误:
sh
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
文件:
json
{
"name": "cni0",
"cniVersion":"0.3.1",
"plugins":[
{
...
"kubernetes": {
"kubeconfig": "/etc/cni/net.d/calico-kubeconfig"
}
},
...
]
}
而/etc/cni/net.d/calico-kubeconfig
中就定义了连接apiserver所需的地址和端口,因此只需将该地址端口换成apiserver pod的地址和端口应该就可以解决该问题:
yaml
# 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即可:
yaml
- name: KUBERNETES_SERVICE_HOST
value: <api-server-pod-ip>
- name: KUBERNETES_SERVICE_PORT
value: "6443"
至此,问题基本解决。由于错误的操作,该集群出现了大量问题,后续可以通过驱逐节点pod的方式,重新初始化整个节点,逐步重置集群节点配置。