首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

TKE常见问题以及故障定位

1.长连接服务:滚动更新导致负载不均

建议: client 侧设置连接过期时间或者达到一定请求数就重连

2.高并发服务:

ipvs 下,高并发 client 导致 “no route to host”

  • client 高并发导致源端口重用,ipvs 模块匹配到旧连接(weight为0,但没真正剔除,目的是ipvs为了支持graceful termination)
  • 旧连接的后端 pod 已经销毁,导致连接异常

建议:暂时没有完美解决方案,可通过 Pod 反亲和打散 client 避免流量集中规避

大流量的边缘节点源端口耗尽

  • 边缘节点通过 NodePort 接收外界流量,发生大量 SNAT,导致源端口耗尽

连接队列溢出问题

syn 队列保存半连接状态的连接, accpet 队列保存已建立但还没有被应用处理的连接

  • ss –lnt 查看连接队列情况, Send-Q 表示 accept 队列大小, Recv-Q 表示 accept 队列中连接数量,通常为0,比 Send-Q 大 1 表示溢出;
  • 通常 somaxconn 决定 accpet 队列大小,默认为 128;
代码语言:javascript
复制
$ netstat -s | grep -E 'overflow|drop'
  • 流量过大或高负载易导致应用处理不过来(accept过慢),从而队列溢出丢包;
使用sysctls调整参数
  • 使用 K8S sysctls 特性设置 somaxconn (此特性在 k8s v1.12 beta,默认开启);
通过 initContainers 初始化容器时调整参数
  • 使用 initContainers 设置 somaxconn (特权容器);
  • nginx 在 listen() 时并没有指定 somaxconn 的值为队列大小,而是有自己的默认值:511
代码语言:javascript
复制
listen 80 default backlog=1024
  • 通过在 nginx.conf 配置 backlog 可调整队列大小

慎用alpine

  • alpine 比较精简,很多依赖库没有,或者跟其它镜像不一样,一些依赖动态链接库的程序容易报错,比如 go 的 cgo 调用;
  • 底层库是 musl libc,域名解析行为跟 glibc 有差异,在 resolv.conf 配置的很多选项不支持;
  • 没有内置 bash,运行 bash 脚本不兼容;
  • 使用 lxcfs 提升容器资源可见性对 alpine 不生效(容器内看到的还是宿主机的cpu, memory使用情况),因为 alpine 内置 busybox 用系统调用获取信息而非读取 /proc;

DNS优化

search 与 ndots:

  • 若域名中的 “.” 数量大于等于 ndots 数量,直接向 dns server 查询此域名;
  • 否则就先依次遍历 search 并拼接到域名后缀查询;
  • 默认 ndots 为 5,即便把 service 名称拼全(比如 test.default.svc.cluster.local,4个 “.”),也还是会有 4 查询,前 3 次是多余的;

优化:

  • Pod dnsConfig 配置较小的 ndots;
  • 集群内部通过 service 访问时拼全后缀(namespaces.svc.cluster.local)

DNS cache

优化:

  • 改造业务,避免每次请求都查dns,比如 java 设置 networkaddress.cache.ttl ;
  • 部署 NodeLocal DNS 作为本地 DNS 缓存

常见故障定位

1、查看状态码与详情;

代码语言:javascript
复制
$ kubectl describe pod {xxx} -n {namespaces}

使用 kubectl describe pod 查看容器上次退出状态码:

分析退出状态码:

分析退出状态码:

  • 1-128 表示进程主动退出 (只是约定),具体状态码含义取决于应用程序逻辑;有时主动退出也会是 255 状态码: 代码里使用类似 exit(-1) 时,-1 被自动转成 255,通常状态码为 1 和 255 是一般性错误,看不出具体含义,需要结合日志分析;
  • 129-255 表示进程因外界中断信号退出,最常见的是 137,表示被 SIGKILL 杀死,可能是 Cgroup OOM,系统 OOM,存活检查失败或者被其它进程杀死导致。

2、查看日志;

使用 kubectl logs 查看容器日志 (-p 可看上次退出日志):

代码语言:javascript
复制
$ kubectl logs {podname} -n {namespaces}

3、查看资源配置;

使用 -o yaml 查看资源 yaml:

代码语言:javascript
复制
# pod
$ kubectl get pod {podname} -n {namespaces} -o yaml
# deploy
$ kubectl get deploy {deplyname} -n {namespaces} -o yaml
# svc
$ kubectl get svc {svcname} -n {namespaces} -o yaml
# daemonset
$ kubectl get daemonset {daemonsetname} -n {namespaces} -o yaml

4、进入容器抓包关键思路;

  • kubectl describe pod 拿到容器 id;
  • 通过 docker 或 crictl 查看容器 id 对应的进程号;
  • 使用 nsenter –n --target 进入容器进程的 netns;
  • 使用宿主机上的抓包工具进行抓包 (tcpdump)

5、Pod 无法调度;

可能原因:

  • 节点资源不够;
  • 不满足 nodeSelector 与 affinity;
  • Node 存在 Pod 没有容忍的污点;
  • 有状态应用漂移找不到符合条件的同可用区节点;
  • scheduler 不正常 (概率低)

6、Pod无法启动;

可能原因:

  • 拉取镜像失败;
    • 镜像仓库认证失败 (imagePullSecret 没有配置或配置有误);
    • 镜像仓库协议与证书问题 (http 没有加 insecure-registry / https 自签没有加 CA) ;
    • 镜像不存在 (镜像名配置有误);
    • 镜像文件损坏;
    • 镜像拉取超时 (镜像太大或在国内拉不到国外镜像);
  • 程序启动配置不当导致进程主动退出 ;
  • limit 没配置单位,内存默认用 byte,导致一直被 kill ;
  • 依赖的 ConfigMap、Secret 或者 PVC 等不存在;
  • 被管理员配置的 LimitRange, PodSecurityPolicy 限制住了;
  • 挂载 Volume 失败;
    • 命中 bug #68211;
    • Pod 漂移没有正常解挂之前的磁盘;
  • 磁盘爆满;
  • 节点内存碎片化 ;
  • controller-manager 异常;
  • CNI 网络错误;
  • 程序启动慢被存活检查 kill;

7、Pod 发生 Crash;

可能原因:

  • cgroup OOM / 系统 OOM ;
  • DNS 故障导致解析失败,业务进程报错退出;
  • 高负载导致网络不通,业务进程报错退出;
  • 存活检查探测失败,容器被 kill;
  • 业务本身 bug;
  • 容器进程被木马进程杀死

8、Pod 无法删除;

可能原因:

  • 磁盘爆满;
  • 存在 Finalizers;
  • 资源被其它进程占用;
  • 存在 “i” 文件属性;
  • 运行时 bug;

9、Namespace 无法删除;

可能原因:

  • Namespace 上存在 Finalizers (比如安装过 KubeSphere 或 Rancher,卸载后没清理 Finalizers);
  • 注册过的 apiservice 状态异常 (比如安装过 prometheus-adapter,卸载后没清理 apiservice)

10、Service/Ingress 创建失败;

可能原因:

  • LB 数量达到最大配额;
  • 复用已有 LB 但上面存在规则或正在被其它 Service/Ingress 使用 ;
  • 复用已有 LB 但 ID 写错;
  • Secret 不正确;
  • LB 内部错误 (概率低);

11、网络不通;

可能原因:

  • 节点安全组没有放通容器网段、节点网段或者 NodePort 端口区间 (30000-32768);
  • 外部服务防火墙没有放开容器网段 (如 CDB、自建 DNS);
  • DNS 异常;
  • 高负载;
  • 进程没有监听端口;

12、节点状态异常;

可能原因:

  • 节点高负载;
  • 磁盘故障;
  • 踩内核 bug;
  • 运行时 hang 住或挂掉;
  • 系统 OOM ;
  • 节点 DNS 被修改;
  • 欠费

案例: Pod 访问另一个集群的 apiserver 有延时

  • kubectl 没有使用底层库查询域名,在 alpine 下底层库是 musl libc,但 kubectl 用的却是类似 glibc 的查询逻辑;
  • 由于 alpine 没有 /etc/nsswitch.conf 文件,所以 kubectl 先查 dns,再查 hosts;
  • 虽然 dns 解析没有用,但始终会先尝试解析 dns,当踩上内核 conntrack bug 时导致部分请求丢包,等待 5s 超时后 kubectl 继续重 试,造成 5s 延时现象;

解决方案:

  • 换基础镜像,不用 alpine;
  • 挂载 nsswitch.conf 文件 (hostPath或configMap);
举报
领券