问题排查.md - O-R/kubernetes_practice GitHub Wiki

认证要求

  • Troubleshooting 问题排查 10%
    • 排查应用失败故障
    • 排查控制层(control panel)故障
    • 排查工作节点(work node)故障
    • 排查网络故障

trouble shooting

学会看termination message

容器退出时, 会往容器的/dev/termination-log写终止日志。 可以通过命令查看这个日志内容:

  kubectl get pod termination-demo -o go-template="{{range .status.containerStatuses}}{{.lastState.terminated.message}}{{end}}"

这个终止日志的路径默认是/dev/termination-log, 但是可以自定义。 比如你的应用退出时会往/tmp/my-log写终止日志。 你希望改变终止日志的路径, 就可以指定terminationMessagePath 的值。

apiVersion: v1
kind: Pod
metadata:
  name: msg-path-demo
spec:
  containers:
  - name: msg-path-demo-container
    image: debian
    terminationMessagePath: "/tmp/my-log"

参考 官方文档之Determine the Reason for Pod Failure

调试Pod, Replication Controller 和 Service

调试一个pod的第一个步骤是查看它的状态。 可以通过命令查看pod的最新的状态和最近的event。

$ kubectl describe pods ${POD_NAME}

pod的几种状态及可能原因

  • pending状态

这种情况pod没有被调度成功,一般情况下可能的原因是是资源不足(pod reqeust的的资源大于当前集群所能提供的资源), hostPort冲突

  • waiting 状态

pod已被成功调度, 但是不能成功在工作节点上启动, 最常见的原因是不能下载镜像, 需要你做如下检查: 1. 镜像名称是否正确? 2. 是否有push镜像到镜像蹭课 3. 手动运行docker pull 看是否能正常拉取镜像

  • crash状态或者unhealthy状态

$ kubectl logs ${POD_NAME} ${CONTAINER_NAME}, 通过日志查看 $ kubectl logs --previous ${POD_NAME} ${CONTAINER_NAME} 查看上次crash状态的日志 kubectl exec ${POD_NAME} -c ${CONTAINER_NAME} -- ${CMD} ${ARG1} ${ARG2} ... ${ARGN} 在运行中的pod里执行命令 比如$ kubectl exec cassandra -- cat /var/log/cassandra/system.log

replication controller

kubectl describe pods <pod_name>

service 假定别人告诉我们创建了service, 叫hostnames。有个pod要连接这个service时, 报了一个错误

u@pod$ wget -qO- hostnames
wget: bad address 'hostname'

接下来就是排障过程:

  1. service是否存在?
$ kubectl get svc hostnames
Error from server (NotFound): services "hostnames" not found

说明service不存在, 赶紧创建一个

$ kubectl expose deployment hostnames --port=80 --target-port=9376
service "hostnames" exposed

重新检查一遍

$ kubectl get svc hostnames
NAME        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
hostnames   10.0.0.226   <none>        80/TCP    5s

service已经创建了, 但是服务依然不可用 2. DNS是否能为解析这个service的名称?

# 假设service的namespace是default
# 在default namespace的pod里做dns解析
u@pod$ nslookup hostnames
Server:         10.0.0.10
Address:        10.0.0.10#53

Name:   hostnames
Address: 10.0.1.175

# 在其它 namespace的pod里做dns解析
u@pod$ nslookup hostnames.default
Server:         10.0.0.10
Address:        10.0.0.10#53

Name:   hostnames.default
Address: 10.0.1.175

# 在其它 namespace的pod里做dns解析完整域名,其中cluster.local是你的集群域名, 这个域名根据你创建集群的情况确定, 默认是cluster.local
u@pod$ nslookup hostnames.default.svc.cluster.local
Server:         10.0.0.10
Address:        10.0.0.10#53

Name:   hostnames.default.svc.cluster.local
Address: 10.0.1.175

如果dns能正常解析完整域名,但是不能解析部分域名, 那么需要你检查下kubelet的--cluster-dns和--cluster-domain两个参数的配置

如果上面的检查都失败了,接下来可以看看是否DNS能解析kubernetes的service , kubernetes master的service总是存在的

  1. 检查是否dns中有存在任何的service
u@pod$ nslookup kubernetes.default
Server:    10.0.0.10
Address 1: 10.0.0.10

Name:      kubernetes
Address 1: 10.0.0.1

如果上述失败了, 就要检查下dns或者kube-proxy

  1. service的ip是否可以正常工作 在node上发起访问
u@node$ curl 10.0.1.175:80
hostnames-0uton

u@node$ curl 10.0.1.175:80
hostnames-yp2kp

u@node$ curl 10.0.1.175:80
hostnames-bvc05

如果service正常工作, 你会得到正确的响应,如果不能正常工作, 那么需要做一堆检查了。

  1. service是否正确?
$ kubectl get service hostnames -o json
{
    "kind": "Service",
    "apiVersion": "v1",
    "metadata": {
        "name": "hostnames",
        "namespace": "default",
        "selfLink": "/api/v1/namespaces/default/services/hostnames",
        "uid": "428c8b6c-24bc-11e5-936d-42010af0a9bc",
        "resourceVersion": "347189",
        "creationTimestamp": "2015-07-07T15:24:29Z",
        "labels": {
            "app": "hostnames"
        }
    },
    "spec": {
        "ports": [
            {
                "name": "default",
                "protocol": "TCP",
                "port": 80,
                "targetPort": 9376,
                "nodePort": 0
            }
        ],
        "selector": {
            "app": "hostnames"
        },
        "clusterIP": "10.0.1.175",
        "type": "ClusterIP",
        "sessionAffinity": "None"
    },
    "status": {
        "loadBalancer": {}
    }
}

检查下spec.ports[]里的内容,比如target port是否是你要的应用实例暴露的port, 端口的协议(protocol)是否正确,是TCP, UDP, 还是HTTP

  1. service是否有对应的Endpoint?
$ kubectl get endpoints hostnames
NAME        ENDPOINTS
hostnames   10.244.0.5:9376,10.244.0.6:9376,10.244.0.7:9376

如果上述结果为空, 那么要确认下service的spec.selector和pods的metadata.labels是否能对应上

  1. Pod是否正常工作? 直接访问pod的ip + 端口
u@pod$ wget -qO- 10.244.0.5:9376
hostnames-0uton

pod $ wget -qO- 10.244.0.6:9376
hostnames-bvc05

u@pod$ wget -qO- 10.244.0.7:9376
hostnames-yp2kp

如果不能返回正确的结果, 就要用kubectl logs查看pod的日志, 或者使用kubectl exec 进到pod一探究竟

  1. kube-proxy是否正常工作 假定你的service正常运行,也有对应的endpoint, pod也正常服务。如果服务还是不能正常访问, 那么就要怀疑kube-proxy是否正常工作了。
# 先看下kube-proxy有没有在你的node里正常运行
u@node$ ps auxw | grep kube-proxy
root  4194  0.4  0.1 101864 17696 ?    Sl Jul04  25:43 /usr/local/bin/kube-proxy --master=https://kubernetes-master --kubeconfig=/var/lib/kube-proxy/kubeconfig --v=2
#  再看kube-proxy的日志是否正常
tail /var/log/kube-proxy.log 或者 journalctl -u kube-proxy
# 接着看kube-proxy是否有写入iptables规则
u@node$ iptables-save | grep hostnames
-A KUBE-SEP-57KPRZ3JQVENLNBR -s 10.244.3.6/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-57KPRZ3JQVENLNBR -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.3.6:9376
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -s 10.244.1.7/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.1.7:9376
-A KUBE-SEP-X3P2623AGDH6CDF3 -s 10.244.2.3/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-X3P2623AGDH6CDF3 -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.2.3:9376
-A KUBE-SERVICES -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames: cluster IP" -m tcp --dport 80 -j KUBE-SVC-NWV5X2332I4OT4T3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-WNBA2IHDGP2BOBGZ
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-X3P2623AGDH6CDF3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -j KUBE-SEP-57KPRZ3JQVENLNBR

正常情况下有1条KUBE-SERVICES规则,每个endpoint会有1~2条KUBE-SVC-(hash)规则, 1个 KUBE-SEP-(hash)规则, 还有若干KUBE-SEP-(hash)的
  1. 其它问题 如service没有endpoint, 网络流量没有转发, pod 的ip不能访问自己的service的vip(一般和kubelet的hairpin-mode的设置有关), 请参考官方文档

参考 官方文档之Debug Pods and Replication Controllers 官方文档之Debug Services

集群故障调试

  1. kubectl get nodes 看有多少node处于ready状态
  2. 查看日志, 使用jounalctl或者tail查看master(kube-scheduler, kube-apiserver, kube-controller-manager), node(kubelet, kube-proxy)的日志
  3. 可能导致集群故障的原因(VM故障, 集群之中或集群和用户之间的网络中断隔离故障,kubernetes的软件崩溃, 持久化存储不可用或数据丢失, 操作错误比如错误配置了kubernetes集群等 )
故障 现象 缓解措施
Apiserver VM shutdown or apiserver crashing 1. 不能停止,更新, 启动pod, service, replication controller 2. 原有的pod和service不受影响, 除非它们依赖kubernetes api 1.主机自动重启 2. 使用高可用架构部署
Apiserver backing storage lost 1. apiserver不能启动 2. kubelet不能连接到apiserver 3.在apiserver restart之前, 手动恢复和重建apiserver的状态是必须的 1. 在主机上挂载可靠的存储,用于apiserver+etcd 2. 使用高可用架构部署3.定期对apiserver的数据做快照
安装kubernetes组件的vm宕机 因为目前apiserver, controller-manager, scheduler必须部署在一起,如果部署组件的虚机宕机 ,则三个组件会同时故障。未来可能会支持独立部署, 且不保留各自的持久化状态 1. 主机自动重启2. 使用高可用架构部署
个别的node宕机 在该node的pod停止运行 1. 主机自动重启 2. 使用replication controller和service,而不是单独创建pod 3. 应用设计上允许不可预期的重启
网络分区故障(network partition) master和node互相认为对方宕掉
kubelet软件错误 1. crash掉的kubelet不能在node上启动新的pod, 2. kubelet可能会也可能不会删除pod, 3. 所在的node会被apiserver标记为unhealthy状态 4. replication controller会在别的node启动pod 1. 使用replication controller和service,而不是单独创建pod 2. 应用设计上允许不可预期的重启
集群操作错误 1. pods,service等对象丢失 2. apiserver的后端存储失联 3. 用户不能读取api 4. 其它 1.定期对apiserver的数据做快照

应用故障调试

pod的调试

  • pending: 资源不足,或者 启用了hostport导致端口冲突
  • waiting: 检查一下是否有正确的docker镜像名称, 或者仓库里有推送镜像, 可以手动在node上执行一下docker pull image 命令
  • crash / unhealthy: 查看应用的log(kubectl logs ), 或者进入到容器里检查(kubectl exec)
  • pod运行但是结果不是我想要的: 删除pod, 用kubectl create --validate -f mypod.yaml重建看看是否有报错, 或者 使用kubectl get pods/mypod -o yaml > mypod-on-apiserver.yaml ,和你的yaml做比较,看是否有重大差异

replication controller的调试, service的调试见前面的章节(调试Pod, Replicaton Controller, service)

常用工具

常见问题

参考文献

⚠️ **GitHub.com Fallback** ⚠️