0%

K8s-应用诊断

Kubernetes 出现问题排查

诊断应用程序

Debugging Pods

查看 Pod 的完整描述

1
kubectl describe pods ${POD_NAME}

注意观察 State Restart Count Conditions Events 字段

Pod一直是Pending

如果 Pod 一直停留在 Pending,意味着该 Pod 不能被调度到某一个节点上。通常,这是因为集群中缺乏足够的资源或者 合适 的资源。在上述 kubectl describe... 命令的输出中的 Events 字段,会有对应的事件描述为什么 Pod 不能调度到节点上。可能的原因有:

  • 资源不就绪:创建 Pod 时,有时候需要依赖于集群中的其他对象, ConfigMap(配置字典)、PVC(存储卷声明)等,例如

    • 可能该 Pod 需要的存储卷声明尚未与存储卷绑定,Events 信息如下所示:

      1
      2
      3
      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的事件中看到 TaintsTolerations 这两个单词时,可以检查Pod是否存在污点或者容忍

Pod一直是Wating

如果 Pod 停留在 Waiting 状态,此时该 Pod 已经被调度到某个节点上了,但是却不能运行。

注意 Events 字段的内容。最常见的 Pod 停留在 Waiting 状态的原因是抓取容器镜像失败。请检查:

  • 容器镜像的名字是对的
  • 容器镜像已经推送到了镜像仓库中
  • 在对应的节点上手工执行 docker pull 命令,看是否能够抓取成功。

Pod已经Crash或者Unhealthy

此时通常是容器中应用程序的问题,检查容器的日志,以诊断容器中应用程序出现了何种故障:

1
kubectl logs ${POD_NAME} ${CONTAINER_NAME}

如果容器之前 crash,通过上述命令查不到日志,可以尝试使用下面的命令查看上一次 crash 时的日志:

1
kubectl logs --previous ${POD_NAME} ${CONTAINER_NAME}

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,将看到如下错误信息:
1
2
[root@k8s-master 0425]# kubectl apply --validate -f  security-context-1.yaml 
error: error validating "security-context-1.yaml": error validating data: ValidationError(Pod.spec.containers[0]): unknown field "commnd" in io.k8s.api.core.v1.Container; if you choose to ignore these errors, turn validation off with --validate=false
  • 其次,请检查已经创建的 Pod 和预期的是一致的。执行命令 kubectl get pods/mypod -o yaml > mypod-on-apiserver.yaml。将输出结果与创建 Pod 时所使用的文件做一个对比。通常通过此命令从服务器端获取到的信息比创建 Pod 时所使用的文件要多几行,这是正常的。然而,如果创建的Pod时所示用的文件中,存在从服务器上获取的信息中没有的代码行,这可能就是问题所在了。

Debugging Deployment

Deployment(或者 DaemonSet/StatefulSet/Job等),都会比较直接,要么可以创建 Pod,要么不可以。

可以通过 kubectl describe deployment ${DEPLOYMENT_NAME} (或者statefulset / job 等)命令查看与 Deployment 相关的事件,来发现到底出了什么问题。

Debugging Service

Service 可以为一组 Pod 提供负载均衡的功能。

首先,检查Service的Endpoints。

1
kubectl get endpoints ${SERVICE_NAME}

请确保 enpoints 的个数与期望与该 Service 匹配的 Pod 的个数是相同的。例如,如果使用 Deployment 部署了 web-press,副本数为 2,此时,在输出结果的 ENDPOINTS 字段,应该有两个不同的 IP 地址。

Service中没有Endpoints

如果Service中没有Endpoints,请尝试使用 Service 的 label selector 查询一下是否存在 Pod。假设 Service 如下:

1
2
3
4
5
6
7
8
9
...
metadata:
name: myservice
namespace: ns1
spec:
- selector:
name: nginx
type: frontend
...

执行如下命令可以查看 Service 所匹配的 Pod:

1
kubectl get pods --selector=name=nginx,type=frontend -n ns1

如果 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 命令,确认网络连接是否正常。
  • 应用程序是否正常地监听了端口?Kubernetes 不对网络端口做映射,如果您的应用程序监听 8080 端口,则在 Service 中应该指定 containerPort 为 8080。在任意节点上执行命令 curl : 可查看 Pod 中容器的端口是否正常。

诊断集群问题

查看集群中的节点:

1
2
kubectl get nodes -o wide
kubectl describe node ${NODE_NAME}
  • kube- 开头的 Pod 都是 Kubernetes 集群的系统级组件

  • calico- 开头是的 calico 网络插件

  • etcd- 开头的是 etcd

  • coredns- 开头的是 DNS 插件。

    假设 apiserver 可能有故障,可以执行以下命令以查看其日志

1
kubectl logs -f kube-apiserver-demo-master-a-1 -n kube-system

查看 kubelet 的日志

1
journalctl -u kubelet

集群故障的常见原因

一部分 kubernetes 集群常见的故障原因以及应对办法:

可能的 Root causes:

  • 虚拟机(或所在物理机)停机
  • 集群内部发生网络不通的情况,或者集群和用户之间网络不通
  • 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: 为 apiserver + etcd 使用 IaaS 供应商提供的稳定可靠的持久化存储
    • 应对问题: Apiserver 的后端数据丢失
  • Action: 使用高可用配置
    • 应对问题:Apiserver 所在虚拟机 shotdown 或者 apiserver 崩溃
    • 应对问题:其他 Master 组件崩溃
    • 应对问题:个别节点(虚拟机或物理机)停机
  • Action:周期性的为 apiserver 的 etcd 所使用的数据卷创建磁盘快照(Snapshot)
    • 应对问题:Apiserver 的后端数据丢失
    • 应对问题:集群管理员的人为错误
    • 应对问题:kubelet 软件故障
  • Action:使用Deployment/StatefulSet/DaemonSet 等控制器,而不是直接创建 Pod
    • 应对问题:个别节点(虚拟机或物理机)停机,或者 kubelet 软件故障