- Troubleshooting 问题排查 10%
- 排查应用失败故障
- 排查控制层(control panel)故障
- 排查工作节点(work node)故障
- 排查网络故障
容器退出时, 会往容器的/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"
调试一个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'
接下来就是排障过程:
- 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总是存在的
- 检查是否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
- 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正常工作, 你会得到正确的响应,如果不能正常工作, 那么需要做一堆检查了。
- 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
- 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是否能对应上
- 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一探究竟
- 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)的
- 其它问题 如service没有endpoint, 网络流量没有转发, pod 的ip不能访问自己的service的vip(一般和kubelet的hairpin-mode的设置有关), 请参考官方文档
参考 官方文档之Debug Pods and Replication Controllers 官方文档之Debug Services
- kubectl get nodes 看有多少node处于ready状态
- 查看日志, 使用jounalctl或者tail查看master(kube-scheduler, kube-apiserver, kube-controller-manager), node(kubelet, kube-proxy)的日志
- 可能导致集群故障的原因(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)