# Kubernetes 应用故障的一些定位方法

## 常备工作

### 准备一个工具镜像

其中包含 nslookup, ping, curl, 甚至是 ab、siege 等常用工具以及一个顺手的 Shell。一言不合就可以用静态 Pod 的方式将其运行到 Kubernetes 之中进行内部诊断。

### sysctl -a | grep forwarding

你猜这是干啥的？

### 服务状态查询

各个 Kubernetes 组件的状态检查。可以使用 Ansible 之类的工具进行快速查询。

## Service 不通

> 这里我们首先假设 Pod 工作正常

目前我们的应用均采用的是 NodePort 模式对外提供服务：

- **逻辑**：Service 将 **符合其选择器的 Pod 暴露的端口** 从 **各个 Node** 的同一端口暴露出来对外进行监听。

- **技术**：**Kube-proxy** 通过网络插件，一般利用 Iptables vxLan 等乌七八糟的蜜汁技术，完成对外服务负载均衡，并分发给各个 Pod 的内部 IP 的相应端口。

前面我们假设 Pod 是正常工作的，因此，这里只考虑 Service 的情况。

通过上面的陈述我们能看到大致的一些要素，下面从内向外进行列表：

### Pod 能够正常工作

见后文

### Service 的选择器能够正确的找到 Pod

这里我们可以使用`kubectl describe svc panic-service`命令，查看输出内容的`endpoint`一节内容，如果其中有 Pod 地址，也就说明选择器和 Pod 的标签是匹配的。如果为空，则需要对服务或者 Pod Controller 的定义进行排查。

### Proxy 的工作状态

- 首先可以使用`systemctl -l Kube-proxy`来查看服务状况。
- 还可以使用其他 Node 的同一端口测试访问，看是否单一节点的故障。

### DNS 工作状态

Kubectl 查看 DNS 各个 Pod 的存活状态。

利用上面提到的工具 Pod 尝试解析服务。失败了其实也没啥办法，删 DNS Pod 重启吧。

### 端口是否定义正确

看 Pod 的端口是否能够正确侦听，是否符合服务定义。例如 Service 定义了到 Pod 8080 端口的访问，而 Pod 开放的却是 80，这样的情况跟标签无法匹配一样，是很常见的问题。

## 说完了服务，我们来说说 Pod

### 两个顺手的命令：

 `kubectl get po -o wide | grep -v Running`
 `kubectl describe po unhealthy`

一般来说，一个行为端正的 Pod，应该是以 Running 状态持续运行的。在进入 Running 之前，大致有调度、创建、初始化等几个环节，如果正常运行之后出了故障，会发生重启。如果在启动容器内进程时出现问题，则会进入 CrashLoopBackOff 的状态。

### 除了 Running/Complet 以及 CrashLoopBackOff：

这几种情况其实不同，不过随性写到这，就不深究了，首先是 describe 一下。

Pod 启动有几个条件：

- 有符合要求的节点供其运行
  - Taint 隔离的节点，要求 Pod 有显式声明对该种 Taint 的容错能力，才可以在其上运行。  
  - 节点和 Pod 的亲和性定义
  - Node Selector 的定义
- 符合其需求的资源
  - CPU 和 内存的 request limit 定义
  - 可能存在的第三方资源需求定义
  - 加载卷（nfs gluster ceph 等）/Secret/Configmap 的定义
- 镜像必须存在，可 Pull

调度部分一般来说查看 Pod 定义，和节点的 Describe 进行匹配即可，Describe 内容中也会明确说出无合适 Pod。

资源部分 CPU 和内存的 Describe 结果也会很明显。

存储部分，往往就需要更复杂的排查：

- 首先看看是不是每个 Node 都如此。
- 是否安装了对应的客户端驱动。
- 对分布式存储的访问网络是否可用。
- 存储服务容量是否足够分配。
- 是否能够成功的手工 Mount。

至于对 ConfigMap 和 Secret 的依赖，很简单，Kubectl 查询即可。

### CrashLoopBackOff 以及 Restart 大于 1

这种情况一般来说属于业务内部的问题，可以通过 `kubectl logs -f ...`
命令进行查看，目前经验比较多的非业务情况是：

- 对于 Kubernetes API 进行访问的应用，经常会是因为 RBAC 权限不足导致无法启动
- 依赖的 Service 无法访问。
