问题诊断
Debugging Pods
任何时候,当你怀疑Pod碰到问题时,先看一下Pod的完整描述。执行如下语句可以查看到Pod最新的状态以及最近关联的事件:
kubectl describe pods ${POD_NAME}
输出结果如下所示:
Name:           nginx-deployment-5754944d6c-d8hs8
Namespace:      default
Priority:       0
Node:           demo-worker002/172.17.216.82
Start Time:     Wed, 02 Oct 2019 22:36:19 +0800
Labels:         app=nginx
                pod-template-hash=5754944d6c
Annotations:    cni.projectcalico.org/podIP: 192.168.15.129/32
Status:         Running
IP:             192.168.15.129
Controlled By:  ReplicaSet/nginx-deployment-5754944d6c
Containers:
  nginx:
    Container ID:   docker://70b70667e082d6b4cbc7ab7a5fba33c2fa93509e08794658fde9ad9ac04a0327
    Image:          nginx:1.7.9
    Image ID:       docker-pullable://nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206abac0c9d794affb40e0714846c451
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Wed, 02 Oct 2019 22:36:22 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-s6znq (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  default-token-s6znq:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-s6znq
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:          <none>
查看Pod中容器的状态:是否所有的容器都处于 Running 状态?是否近期有重启过?根据Pod/容器的状态:
Pod一直是Pending
如果 Pod 一直停留在 Pending,意味着该 Pod 不能被调度到某一个节点上。通常,这是因为集群中缺乏足够的资源或者 “合适” 的资源。在上述 kubectl describe... 命令的输出中的 Events 字段,会有对应的事件描述为什么 Pod 不能调度到节点上。可能的原因有:
- 资源不就绪:创建 Pod 时,有时候需要依赖于集群中的其他对象, ConfigMap(配置字典)、PVC(存储卷声明)等,例如
- 可能该 Pod 需要的存储卷声明尚未与存储卷绑定,Events 信息如下所示:
 
 
Type     Reason            Age        From               Message
----     ------            ----       ----               -------
Warning  FailedScheduling  <unknown>  default-scheduler  pod has unbound immediate PersistentVolumeClaims (repated 2 times)
- 缺乏足够的资源:可能集群中的CPU或内存都已经耗尽,此时,您可以尝试:
- 删除某些 Pod
 - 调整Pod的资源请求
 - 向集群中添加新的节点
 
 - 该Pod使用hostPort: 当Pod使用 hostPort 时,该Pod可以调度的地方就比较有限了。大多数情况下,是不需要使用 hostPort 的,可以尝试使用 Service 访问您的 Pod。如果您确实需要使用 hostPort 时,Deployment/ReplicationController 中 replicas 副本数不能超过集群中的节点数,因为每台机器的 80 端口只有一个,任何其他端口也只有一个。如果该端口被其他程序占用了,也将导致Pod调度不成功
 - 污点和容忍: 当您在Pod的事件中看到 Taints 或 Tolerations 这两个单词时,确保您理解了这两个概念
 
Pod一直是Wating
如果 Pod 停留在 Waiting 状态,此时该 Pod 已经被调度到某个节点上了,但是却不能运行。在上述 kubectl describe ... 命令的输出中,仍然注意 Events 字段的内容。最常见的 Pod 停留在 Waiting 状态的原因是抓取容器镜像失败。请检查:
- 容器镜像的名字是对的
 - 容器镜像已经推送到了镜像仓库中
 - 在对应的节点上手工执行 docker pull 
命令,看是否能够抓取成功
 - 检查使用的私有镜像仓库
 
Pod已经Crash或者Unhealthy
此时通常是容器中应用程序的问题,您可以查看一下容器的日志,以诊断容器中应用程序出现了何种故障:
kubectl logs ${POD_NAME} ${CONTAINER_NAME}
如果容器之前 crash,通过上述命令查不到日志,可以尝试使用下面的命令查看上一次 crash 时的日志:
kubectl logs --previous ${POD_NAME} ${CONTAINER_NAME}
或者,也可以执行容器中的命令:
kubectl exec ${POD_NAME} -c ${CONTAINER_NAME} -- ${CMD} ${ARG1} ${ARG2} ... ${ARGN}
上述命令中的 ${CONTAINER_NAME} 或者 -c ${CONTAINER_NAME} 都是可选项,当你的 Pod 中只有一个容器时,可以不填写此参数
例如,要查看 Pod Cassandra 的日志,可以执行命令:
kubectl exec cassandra -- cat /var/log/cassandra/system.log
Pod处于Running状态,但是不工作
Pod已经处于Running状态了,但是不像您期望的那样工作,此时,很有可能是您的部署描述yaml文件(例如 Pod、Deployment、StatefulSet等)出现了问题,而创建时,kubectl 忽略了该错误。例如环境变量中某一个 Key 写错了,command 拼写成了 commnd 等。如果 command 拼写成了 commnd,您仍然能够使用该 yaml 文件创建工作负载,但是容器在运行时,却不会使用您原本期望的命令,而是执行了镜像中的 EntryPoint。
- 首先,在使用 kubectl apply -f 命令之前,可以尝试为其添加 --validate 选项,例如, kubectl apply --validate -f mypod.yaml。如果您将 command 拼写成 commnd,将看到如下错误信息:
 
I0805 10:43:25.129850   46757 schema.go:126] unknown field: commnd
I0805 10:43:25.129973   46757 schema.go:129] this may be a false alarm, see https://github.com/kubernetes/kubernetes/issues/6842
pods/mypod
- 其次,请检查您已经创建的 Pod 和您预期的是一致的。执行命令 
kubectl get pods/mypod -o yaml > mypod-on-apiserver.yaml。将输出结果与您创建 Pod 时所使用的文件做一个对比。通常通过此命令从服务器端获取到的信息比创建 Pod 时所使用的文件要多几行,这是正常的。然而,如果您创建的Pod时所示用的文件中,存在从服务器上获取的信息中没有的代码行,这可能就是问题所在了。 
Debugging Deployment
Deployment(或者 DaemonSet/StatefulSet/Job等),都会比较直接,他们要么可以创建 Pod,要么不可以,此时,请按照上面的方法检查 Pod 的问题。
可以通过 kubectl describe deployment ${DEPLOYMENT_NAME} (或者statefulset / job 等)命令查看与 Deployment 相关的事件,来发现到底出了什么问题。
Debugging Service
Service 可以为一组 Pod 提供负载均衡的功能。
首先,检查Service的Endpoints。
kubectl get endpoints ${SERVICE_NAME}
输出结果如下所示:
NAME                ENDPOINTS                               AGE
web-press   192.168.144.158:80,192.168.199.135:80   70d
请确保 enpoints 的个数与您期望与该 Service 匹配的 Pod 的个数是相同的。例如,如果您使用 Deployment 部署了 web-press,副本数为 2,此时,在输出结果的 ENDPOINTS 字段,应该有两个不同的 IP 地址。
Service中没有Endpoints
如果您的Service中没有Endpoints,请尝试使用 Service 的 label selector 查询一下是否存在 Pod。假设您的 Service 如下:
...
metadata:
  name: myservice
  namespace: ns1
spec:
  - selector:
      name: nginx
      type: frontend
...
执行如下命令可以查看 Service 所匹配的 Pod:
kubectl get pods --selector=name=nginx,type=frontend -n ns1
请核对查出来的 Pod 列表是否是您期望使用的 Pod。
如果 Pod 列表是您期望的结果,但是 ENDPOINTS 还是空的,此时很可能是您没有为 Service 指定正确的端口。如果 Service 中指定的 containerPort 实际上并不存在于 Pod 中,该 Pod 不会被添加到 ENDPOINTS 列表里。请确保 Service 指定的 containerPort 在 Pod 中是可以访问的。
网络转发问题
如果您的客户端可以连接上 Service,但是连接很快就被断开了,并且 endpoints 中有合适的内容,此时,有可能是 proxy 不能转发到您的 Pod 上。
请检查:
- Pod是否正常工作?
kubectl get pods查看 Pod 的 restart count,并按照本文前面的步骤诊断一下 Pod 是否有问题 - 是否可以直接连接到 Pod ?
kubectl get pods -o wide可以获得 Pod 的IP地址,从任意一个节点上执行 ping <POD_IP> 命令,确认网络连接是否正常 - 应用程序是否正常地监听了端口?Kubernetes 不对网络端口做映射,如果您的应用程序监听 8080 端口,则您在 Service 中应该指定 containerPort 为 8080。在任意节点上执行命令 curl <POD_IP>:
可查看 Pod 中容器的端口是否正常。  
诊断集群问题
查看集群
当您怀疑集群可能有故障时,首先要做的是查看集群中的节点:
kubectl get nodes -o wide
检查是否所有的节点是否都在并且都处于 Ready 状态。对于您怀疑有问题的节点,可以查看节点上的详细信息,以及节点上的事件:
# 将 ${NODE_NAME} 替换成您实际的节点名字
kubectl describe node ${NODE_NAME}
查看日志
进一步到相关的机器上查询集群组件的日志
容器化的集群组件
执行命令 kubectl get pods -n kube-system 查看所有 kube-system 名称空间下的容器,输出结果如下所示:
NAME                                          READY   STATUS        RESTARTS   AGE
calico-kube-controllers-65b8787765-4sbhj      1/1     Running       2          51d
calico-node-fz5t5                             1/1     Running       0          7d22h
calico-node-lpd5d                             1/1     Running       1          34d
calico-node-qjfqd                             1/1     Running       1          10d
calico-node-zchvg                             1/1     Running       6          51d
coredns-67c766df46-cbhf4                      1/1     Running       1          8d
coredns-67c766df46-zthsk                      1/1     Running       0          7d23h
eip-nfs-cluster-storage-6c9c7d46f4-lmxql      1/1     Running       0          7d23h
eip-nfs-nfs-on-centos-66c4fc8fbd-rd4zh        1/1     Running       0          7d5h
etcd-demo-master-a-1                          1/1     Running       0          8d
kube-apiserver-demo-master-a-1                1/1     Running       0          8d
kube-controller-manager-demo-master-a-1       1/1     Running       1          8d
kube-proxy-4xz9h                              1/1     Running       1          8d
kube-proxy-5kljb                              1/1     Running       1          8d
kube-proxy-wmzlq                              1/1     Running       0          7d22h
kube-proxy-z55s9                              1/1     Running       1          8d
kube-scheduler-demo-master-a-1                1/1     Running       0          8d
kuboard-7d6b54b946-xmv28                      1/1     Running       0          3d3h
kuboard-897b6487d-2bbmz                       0/1     Terminating   6          13d
monitor-blackbox-exporter-7b97c74f8f-qcm4z    1/1     Running       0          7d4h
monitor-grafana-7d88f4b5d7-jxphs              1/1     Running       0          7d4h
monitor-kube-state-metrics-555b9cd949-hthlr   2/2     Running       0          7d4h
monitor-prometheus-6768d469b5-cmn9j           1/1     Running       0          7d4h
monitor-prometheus-node-exporter-dsfnl        1/1     Running       0          7d4h
monitor-prometheus-node-exporter-l5dbs        1/1     Running       0          7d4h
monitor-prometheus-node-exporter-t7d24        1/1     Running       0          7d4h
monitor-prometheus-node-exporter-z9ht5        1/1     Running       0          7d4h
其中,kube- 开头的 Pod 都是 Kubernetes 集群的系统级组件,calico- 开头是的 calico 网络插件,etcd- 开头的是 etcd,coredns- 开头的是 DNS 插件。
假设您认为 apiserver 可能有故障,则,可以执行以下命令以查看其日志
kubectl logs -f kube-apiserver-demo-master-a-1 -n kube-system
kubelet 的日志
执行命令 service kubelet status 可查看 kubelet 的运行状态,如下所示:
如果您的 kubelet 运行状态不是 active (running),那么您需要进一步查看 kubelet 的日志。
Redirecting to /bin/systemctl status kubelet.service
● kubelet.service - kubelet: The Kubernetes Node Agent
   Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
  Drop-In: /usr/lib/systemd/system/kubelet.service.d
           └─10-kubeadm.conf
   Active: active (running) since Wed 2019-10-02 22:06:37 CST; 1 weeks 1 days ago
     Docs: https://kubernetes.io/docs/
 Main PID: 633 (kubelet)
    Tasks: 18
   Memory: 213.2M
   CGroup: /system.slice/kubelet.service
           └─633 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --cgroup-driver=systemd --network-plugin=cni --...
执行命令以下命令可以查看 kubelet 的日志:
journalctl -u kubelet
集群故障的常见原因
可能的 Root causes:
- 虚拟机(或所在物理机)停机
 - 集群内部发生网络不通的情况,或者集群和用户之间网络不通
 - Kubernetes 系统组件崩溃
 - 数据丢失,或持久化存储不可用
 - 运维人员的人为错误,例如,错误地配置了 Kubernetes 或者 Kubernetes 上部署的应用程序
 
具体的故障场景有:
Apiserver 所在虚拟机 shotdown 或者 apiserver 崩溃
- 导致的结果:
- 不能创建、停止、更新 Pod、Service、Deployment等
 - 已有的 Pod 和 Service 仍然能够正常工作,除非该 Pod 或 Service 需要调用 Kubernetes 的接口,例如 Kubernetes Dashboard 和 Kuboard
 
 
Apiserver 的后端数据丢失
- 导致的结果:
- apiserver 将不能再启动
 - 已有的 Pod 和 Service 仍然能够正常工作,除非该 Pod 或 Service 需要调用 Kubernetes 的接口,例如 Kubernetes Dashboard 和 Kuboard
 - 需要手工恢复(或重建) apiserver 的数据才能启动 apiserver
 
 
其他 Master 组件崩溃
- 导致的结果和 apiserver 相同
 
个别节点(虚拟机或物理机)停机
- 导致的结果
- 该节点上的所有 Pod 不再运行
 
 
网络分片
- 导致的结果
- 区域A认为区域B中的节点已死机;区域B认为区域A中的 apiserver 已死机(假设apiserver在区域A)
 
 
kubelet 软件故障
- 导致的结果
- 已崩溃的 Kubelet 不能在该节点上再创建新的 Pod
 - kubelet 有可能错误地删除了 Pod
 - 节点被标记为 
unhealthy - Deployment/ReplicationController 在其他节点创建新的 Pod
 
 
集群管理员的人为错误
- 导致的结果
- 丢失 Pod、Service 等
 - 丢失 apiserver 的数据
 - 用户不能访问接口
 
 
应对办法
Action: 使用 IaaS 供应商提供的自动重启虚拟机的功能
- 应对问题:Apiserver 所在虚拟机停机或者 apiserver 崩溃
 - 应对问题:其他 Master 组件崩溃
 
Action: 为 apiserver + etcd 使用 IaaS 供应商提供的稳定可靠的持久化存储
- 应对问题: Apiserver 的后端数据丢失
 
Action: 使用高可用配置,参考 安装Kubernetes高可用
- 应对问题:Apiserver 所在虚拟机 shotdown 或者 apiserver 崩溃
 - 应对问题:其他 Master 组件崩溃
 - 应对问题:个别节点(虚拟机或物理机)停机
 
Action:周期性的为 apiserver 的 etcd 所使用的数据卷创建磁盘快照(Snapshot)
- 应对问题:Apiserver 的后端数据丢失
 - 应对问题:集群管理员的人为错误
 - 应对问题:kubelet 软件故障
 
Action:使用Deployment/StatefulSet/DaemonSet 等控制器,而不是直接创建 Pod
- 应对问题:个别节点(虚拟机或物理机)停机
 - 应对问题:kubelet 软件故障
 
Action:Kubernetes联邦
(避免将有风险的操作一次性应用到所有集群)
- 应对问题:上述所有问题
 
                    
                
                
            
        
浙公网安备 33010602011771号