容器服务常见故障处理(持续更新...)
容器服务常见故障处理一、pod状态异常查看方法1.查看Pod状态2.常见Pod状态3.输出Pod的yaml文件4.查看Pod详细信息5.查看Pod里对应容器的日志二、Pod几种异常状态问题分析1.详细解释Pod常见异常状态一、pod状态异常查看方法1.查看Pod状态#使用--all-namespaces查看所有命名空间下的podkubectl get pod -n <namespace>
容器服务常见故障处理
一、pod状态异常查看方法
1.查看Pod状态
#使用--all-namespaces查看所有命名空间下的pod
kubectl get pod -n <namespace> -o wide
2.常见Pod状态
状态 | 解释 |
---|---|
Running | 运行中 |
Pending | 等待被调度 |
Waiting | 等待启动 |
CrashLoopBackOff | 容器退出,kubelet 正在将它重启 |
Error | 启动过程中发生错误 |
Unknown | 所在节点失联或其它未知异常 |
Evicted | 容器被驱逐 |
Terminating | 正在被销毁 |
ContainerCreating | 容器正在被创建 |
ImageInspectError | 无法校验镜像 |
InvalidImageName | 无法解析镜像名称 |
ErrImageNeverPull | 策略禁止拉取镜像 |
ErrImagePull | 通用的拉取镜像出错 |
CreateContainerConfigError | 不能创建 kubelet 使用的容器配置 |
CreateContainerError | 创建容器失败 |
RunContainerError | 启动容器失败 |
3.输出Pod的yaml文件
# -o可以指定文件输出格式如yaml、josn等
kubectl get pod <pod-name> -n <namespace> -o yam
#修改yaml文件可用edit
kubectl edit <控制器类型> pod <pod-name> -n <namespace> -o yaml
4.查看Pod详细信息
kubectl describe pod <pod-name> -n <namespace>
5.查看Pod里对应容器的日志
#使用logs -f参数可以实时跟踪日志
kubectl logs <pod-name> -c <container-name> -n <namespace>
二、Pod几种异常状态问题分析
1.详细解释Pod常见异常状态
1.pending状态
Pending是挂起状态: 表示创建的Pod找不到可以运行它的物理节点, 不能调度到相应的节点上运行,我门可以从两个层面分析问题:
物理层面:
查看节点资源使用情况: 如free -m查看内存、 top查看CPU使用率、 df – h查看磁盘使用情况, 这样就可以快速定位节点资源情况, 判断是不是节点有问题
查看节点污点: kubectl describe nodes master1(控制节点名字),如果节点定义了污点, 那么Pod不能容忍污点, 就会导致调度失败, 如下: Taints: node-role.kubernetes.io/master:NoSchedule 这个看到的是控制节点的污点, 表示不允许Pod调度(如果Pod定义容忍度, 则可以实现调度)
HostPort被占用
pod本身分析:
在定义pod时, 如果指定了nodeName是不存在的, 那也会调度失败
在定义Pod时, 如果定义的资源请求比较大, 导致物理节点资源不够也是不会调度的
2.ImagePullBackOff状态
拉取镜像时间长导致超时
配置的镜像有错误: 如镜像名字不存在等
配置的镜像无法访问: 如网络限制无法访问hub上的镜像
配置的私有镜像仓库参数错误: 如imagePullSecret没有配置或者配置错误
dockerfile打包的镜像不可用
3.CrashLoopBackOff状态
容器内应用一直在崩溃,健康检查失败
yaml文件中对pod的一些字段配置有误
k8s集群的部署有问题
4.Error/Terminating/Unknow状态
Error:依赖的ConfigMap、 Secret、 PV、 StorageClass等不存在;
请求的资源超过了管理员设置的限制, 比如超过了limits等;
无法操作集群内的资源, 比如开启RBAC后, 需要为ServiceAccount配置权限。
违反集群的安全策略,比如违反了 PodSecurityPolicy 等
Terminating:pod未被正确回收
Unknow:kubelet未启动 kubelet节点与apiserver通信异常
5.Waiting /ContainerCreating/Evicted
Waiting /ContainerCreating:
镜像拉取失败,比如配置了镜像错误、Kubelet 无法访问镜像、私有镜像的密钥配置错误、镜像太大,拉取超时等
CNI 网络错误,一般需要检查 CNI 网络插件的配置,比如无法配置 Pod 、无法分配 IP 地址
容器无法启动,需要检查是否打包了正确的镜像或者是否配置了正确的容器参数
Evicted:多见于系统内存或硬盘资源不足
三、故障排查案例
案例1.镜像拉取失败案例分析
问题现象:济南节点coredns镜像拉取失败
问题分析:
Pod imagepullbackoff常见情况
拉取镜像时间长导致超时
配置的镜像有错误: 如镜像名字不存在等
配置的镜像无法访问: 如网络限制无法访问hub上的镜像
配置的私有镜像仓库参数错误: 如imagePullSecret没有配置或者配置错误
dockerfile打包的镜像不可用
问题分析:Telent 仓库ip :80 不通
排查结果:镜像仓库策略问题,复制本地正常镜像到故障机器,重新reload下,恢复正常。
案例2.Pid占用导致docker无法启动
问题现象:通过查看节点信息可以看到node状态处于Notready导致caclico异常。
#查看节点详细信息
kubectl get node -o wide
#查看calico的网卡信息
calicoctl node status
#在线下载calicoctl的方法
Curl方法:
curl -O https://github.com/projectcalico/calicoctl/releases/download/v3.5.4/calicoctl
Wget方法:
wget https://github.com/projectcalico/calicoctl/releases/download/v3.5.4/calicoctl -O /usr/bin/calicoctl
问题分析:通过journalctl -u kubelet命令查看kubelet日志发现kubelet启动失败。这里尝试重启还是失败。那么我们就需要看下docker的状态的了。
#通过时间去查找当天的日志信息
journalctl -u <服务名> -S '2021-12-29'
#实时跟踪产生的日志
journalctl -xefu <服务名>
问题分析:这里我们查看了docker状态,发现是failed,尝试systemctl start docker直接退出。
问题分析:这个时候需要我们看一下docker的日志。
#实时跟踪kubelet日志
journalctl -u docker -f
问题分析:我这里没有看到docker日志,所以那就看下service文件有没有配置错误的参数。(如果docker有日志,就查看docker的报错信息。)
问题分析:确定service文件没错之后,我们用启动命令debug一下。不加参数启动成功。看来问题是出现在参数部分。
#启动dockerd服务
/usr/bin/dockerd
问题分析:因为之前的docker服务退出异常,pid还在被占用。备份将这个pid移走。再次启动服务即可。
docker pid被占用,导致docker启动失败。备份将这个pid移走。再次启动服务。
案例3.calico指定多网卡导致无法解析service服务
问题现象:目前有3个节点,只有运行在本地的svc机器才能解析,其他节点无法解析。
#域名解析
nslookup <域名/IP地址>
问题分析:首先我们查看calico相关pod是否健康。calico状态为0/1该pod不健康。
#查看kube-system命名空间下的pod
#kubectl get pod -n kube-system
问题分析:接下来需要看下calico的状态,calico的网段为多个,没有指定统一地址,导致calico没有建立连接关系。
#calico网卡信息
calicoctl node status
问题分析:调整网卡统一地址,calico恢复正常。
#集群统一ip地址(不需要调整网卡,可以不操作这步)
kubectl set env daemonset/calico-node -n kube-system IP_AUTODETECTION_METHOD=interface=bond0.409(网卡)
#将集群的节点与master节点的calico网络互通(前提是ip可以互通),在master节点执行
kubectl set env daemonset/calico-node -n kube-system IP_AUTODETECTION_METHOD=can-reach=(指定ip)
排查结果:集群内指定多网卡会造成calico无法建立连接关系,导致依赖网络的服务都无法正常运行。需指定统一网卡建立calico连接。
案例4.集群节点无法连接到master
问题现象:节点系统组件都正常,但是节点没有就绪。
#查看节点信息加(-o wide可以查看集群详细信息)
#kubectl get node
问题分析:先看下最近产生的日志。可以看到这个33352这个端口无法连接到6443端口,也就是master的ApiServer的端口号。
#查看系统日志
journalctl -f
问题分析:根据日志提供的命名空间我们去看下该命名空间下的pod,可以看到有个异常的pod,这时就要考虑到是不是这个删除中的pod的随机端口33352已经不在了,所以导致无法连接到apiserver,所以尝试重启异常节点的kubelet,让其重新生成一个端口。
#查看pod状态
kubectl get pod -n <namespaces>
问题分析:异常节点重启kubelet,节点恢复正常。
#重启kubelet
systemctl restart kubelet
排查结果:删除失败的容器端口号已不存在,导致无法连接到集群,重启kubelet重新生成一个新的端口,节点恢复正常。
案例5.Docker启动后频繁down
问题现象:docker启动后短时间频繁down。导致该节点无法正常工作。
#查看集群节点信息
kubectl get node -o wide
问题分析:我们知道容器是通过docker起的,如果docker挂了,那容器的状态肯定也是不正常的。而docker除了可以通过自己去创建容器外还可以调用containterd去创建和运行容器。
问题分析:我们再次尝试重启docker,可以看到给我们的提示大概是说docker被其他任务卡住了。
#重启docker
systemctl restart docker -l
排查结果:docker被其他任务卡住了那么我们可以重启containterd ,去加载守护进程,然后在重启docker。
#加载守护进程
systemctl daemon-reexec
systemctl restart docker
案例6.caclio-node启动失败注册ip冲突
问题现象: 1. 一个calico-node一致在crash。 2. calicoctl get node 显示node仍为主机修改hostname之前主机名。
问题分析:vm-2节点加入不了集群,排查vm-2和vm-1发现ipv6地址存在冲突。发现是vm-1的ipv6地址配置错误。修改vm-1的地址,vm-2再次加入集群依旧报错
问题分析:可以看到vm-2的ipv6地址还是被占用了。怀疑是vm-1脏数据。检查一下vm-1的calico node信息
问题分析:发现calico node中ipv6address还是修改之前的地址,删除vm-1这个节点让他以正确的ip注册.也可以编辑yaml文件修改后再次检查vm-1的calico node信息
#ip注册
calicoctl delete node vm-1
#导出yaml编辑
calicoctl get node vm-1 -o yaml >vm-1.yaml
#运行yaml
cat vm-1.yaml|calicoctl apply -f -
问题分析:vm-1的ipv6address被成功更新,再次注册vm-2,这次可以成功注册进来了。不过发现vm-1的calico node的nodename还是以vm-1修改主机名之前的主机名注册的,get node内的信息为正确的信息,虽然不影响使用。还是想改成一致的。因为刚才修改ipv6时已经重新注册过了。nodename还是老的。应该是哪里有固化的脏数据。首先怀疑etcd。尝试把这个节点的calico记录在etcd里删除
问题分析:删除后重新注册,发现还是以老的主机名注册的
查询官方文档calico node的nodename由以下几个优先级
问题分析:由于没有NODENAME,检查节点/var/lib/calico/nodename
排查结果:果然是这个地方还是老的nodename。删除这个文件。重新注册上去,这次calicoctl get node显示的节点名称正常了
案例7.containerd退出导致pod异常
失败的业务pod都处于ContainerCreating状态。登陆集群,将非Running 的pod筛选出来
redis-xxx开头的是业务pod,通过图上我们发现处于ContainerCreating状态的pod都在同一台节点上,大概率是该节点的相关组件有问题,ContainerCreating状态是已经经过了k8s调度,分配了对应的节点,处于在节点上创建容器的阶段。根据这几个信息,可以将故障原因缩小到该节点kubelet或者kubelet往下的组件。
登陆节点,查看kubelet日志
发现/run/containerd/containerd.sock连不上,顺便也看下docker的日志
报错内容一致,都是/run/containerd/containerd.sock连接拒绝。检查containerd服务
查看cotainerd日志,有个go的指针报错导致了containerd退出
重启containerd,可以正常启动。检查docker和kubelet日志,日志恢复正常。节点上pod也恢复正常,问题解决
案例8.mysql k8s集群异常
执行kubectl命令报Error from server (Timeout): the server was unable to return a response in the time allotted, but may still be processing the request (get pods), 一会儿又报The connection to the server 10.193.149.2:6443 was refused - did you specify the right host or port?
这个说明kube-apiserver在不断的重启
查看kube-apiserver日志,显示去etcd集群获取资源耗时非常长。甚至有十几秒的报错。显示etcdserver: too many requests。从这边可以判断出是后端etcd的集群出现了故障。
etcd集群健康查看
在集群master执行,查看输出HEALTH是否都为true,正常应该都为true
#!/bin/bash
etcd_servers=$(sudo /apps/bin/kubectl get pod -n kube-system -o wide|grep etcd|awk '{printf "https://"$6":2379,"}'|sed 's/.$//')
sudo /apps/bin/kubectl -n kube-system exec $(sudo /apps/bin/kubectl get pod -n kube-system |grep etcd|awk 'NR==1{print $1}') -- etcdctl --endpoints=${etcd_servers} \
--cert=/apps/conf/kubernetes/ssl/etcd/server.crt \
--key=/apps/conf/kubernetes/ssl/etcd/server.key \
--cacert=/apps/conf/kubernetes/ssl/etcd/ca.crt \
endpoint health -w table
在集群master执行,查看输出是否都为healthy
#!/bin/bash
etcd_servers=$(sudo /apps/bin/kubectl get pod -n kube-system -o wide|grep kube-apiserver|awk '{printf "https://"$6":2379,"}'|sed 's/.$//')
sudo /apps/bin/etcdctl --endpoints=${etcd_servers} \
--cert-file /apps/conf/etcd/ssl/member-`hostname`.pem \
--key-file /apps/conf/etcd/ssl/member-`hostname`-key.pem \
--ca-file /apps/conf/etcd/ssl/ca.pem \
cluster-health
通过输出发现,03节点的etcd连接有问题,登录03节点,由于现网etcd是docker启动的。尝试docker看下日志。发现docker logs命令卡住,使用docker ps命令检查docker响应,发现docker ps也无法成功执行。可以初步判定docker状态异常。etcd 进程虽然还在但是已经无法正常提供服务了。etcd没有完全down导致另外两个节点被拖垮,尝试再03节点上停掉kubelet,docker和etcd服务。让03节点etcd不再对集群的造成影响.
停完03节点的etcd和docker后集群恢复正常,kubectl命令也正常执行。
异常时发现03节点上bcs的watch资源占用比较大,短短33天crash了2700次,甚至造成了dockerd的内存泄露。先把bcs-watch的deployments缩容为0.重启节点docker和kubelet。等待docker启动完毕后,重启etcd。再次检查。etcd集群恢复。至此问题解决
更多推荐
所有评论(0)