前几天有个朋友把他们的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的方式,重新初始化整个节点,逐步重置集群节点配置。