k8s诊断之记一次业务pod被异常删除的分析

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
日志服务 SLS,月写入数据量 50GB 1个月
简介: 某用户反馈,头一天晚上21:05左右,某几个deployment的pod被重建了一遍,客户的pod有特殊限制,基本可以保证1个节点上就只有这一个pod独占,客户怀疑后端异常导致

背景信息:

   某用户反馈,头一天晚上21:05左右,某几个deployment的pod被重建了一遍,客户的pod有特殊限制,基本可以保证1个节点上就只有这一个pod独占,客户怀疑后端异常导致,这种问题可以先去看下元集群的信息,看看各种controller 的pod 在异常时间段有没有崩溃,重启,重建等信息,这个集群没有这个问题



排查思路&日志分析:

1,deployment下的所有pod都重建了,当时优先怀疑deployment的变更,但是根据rs的版本号对比,确认前后pod的rs版本号未变

2,有什么job cronjob删除pod,deployment controller拉起新的pod,根据日志排除掉

3,之前遇到过HPA拉pod,然后缩容时删除旧pod只保留新pod,根据hpa日志排除

HPA 相关日志:实际没有扩容的动作,日志解读就是预计需要39个副本,根据cpu的得分来看,但是最后决定不扩容

content:I110713:05:31.5818611horizontal.go:1156]Successfullyupdatedstatusfordeploy-d****ercontent:I110713:05:46.6098491horizontal.go:661]proposing39desiredreplicas(basedoncpuresourceutilization(percentageofrequest)from2022-11-0713:05:20+0000UTC)forDeployment/default/depl****rcontent:I110713:05:46.6098711horizontal.go:700]decidednottoscaleDeployment/default/ddepl****rto39(lastscaletimewas2022-11-0711:16:27+0000UTC)

4,以被删除的pod depl****rr-7b656b54b7-stwj8 为例(老pod 被抢占删除),看时间线

schedulerpodcontent:I110713:05:47.7342711capacity_scheduling.go:662]Poddefault/depl****rr-7b656b54b7-stwj8isapotentialpreemptionvictimonnodeeu-central-1.10.200.104.186.apiservercontent:I110721:05:47.8198771httplog.go:108]"HTTP"verb="DELETE"URI="/api/v1/namespaces/default/pods/depl****r-7b656b54b7-stwj8"latency="7.986746ms"userAgent="kube-scheduler/v1.20.4 (linux/amd64) kubernetes/96c418b/scheduler"srcIP="7.8.121.36:45840"resp=200contentType="application/vnd.kubernetes.protobuf"requestID="49832f6f-aa13-412a-92b4-a5e7e62aa976"stageTimestamp:2022-11-07T13:05:47.819744Zuser:{"username":"kubernetes-admin","groups":["system:masters","system:authenticated"]}userAgent:kube-scheduler/v1.20.4(linux/amd64)kubernetes/96c418b/schedulerverb:delete

我们用日志串联看出来的都是抢占先发生,删除后发生的

5,通过节点绑定这个特性反查当时抢占该pod的新pod名称depl****rr-7b656b54b7-zjmn8 为检索关键字,捋时间线

scheduler:content:I110713:05:45.0684921eventhandlers.go:172]addeventforunscheduledpoddefault/depl****r-7b656b54b7-zjmn8apiserver:content:I110721:06:03.7567671httplog.go:108]"HTTP"verb="PATCH"URI="/api/v1/namespaces/default/pods/depl****rr-7b656b54b7-zjmn8/status"latency="5.035966ms"userAgent="kube-scheduler/v1.20.4 (linux/amd64) kubernetes/96c418b/scheduler"srcIP="7.8.121.36:45840"resp=200contentType="application/vnd.kubernetes.protobuf"requestID="a0698fb2-d843-4158-b7ff-dbcc46e5f961"KCMcontent:I110713:05:45.0683931graph_builder.go:632]GraphBuilderprocessobject:v1/Pod, namespacedefault, namedepl****r-7b656b54b7-zjmn8, uid86773988-20ec-4b44-a62e-97c3cd3db054, eventtypeadd, virtual=falsestageTimestamp:2022-11-07T13:06:03.756637Zuser:{"username":"kubernetes-admin","groups":["system:masters","system:authenticated"]}userAgent:kube-scheduler/v1.20.4(linux/amd64)kubernetes/96c418b/schedulerverb:patch

 看到了新pod的不可调度事件,但是并不能说明该pod抢占了老pod

6,继续寻找pod被抢占的原因,这个时候要考虑抢占的上下文日志,sls有个上下文浏览可以看下,这里涉及一个知识点,调度器在尝试驱逐的时候是串行执行的,所以在驱逐pod A的时候,发起驱逐的pod就是这条日志超上翻的第一条Attempting to schedule pod的pod,并且在条日志后面也有postfiler的结果,返回值是0 [] nil表明抢占是成功的,2则是失败

logtail的pod尝试调度

content:I110713:05:20.7024661eventhandlers.go:172]addeventforunscheduledpodkube-system/logtail-ds-xhzgmcontent:I110713:05:47.7287971scheduling_queue.go:812]Abouttotryandschedulepodkube-system/logtail-ds-xhzgmcontent:I110713:05:47.7288091scheduler.go:460]Attemptingtoschedulepod:kube-system/logtail-ds-xhzgm

这个节点发生了潜在的抢占,scheduler日志要看上下文,所以这个时间点只有一个pod在等待调度,且发送抢占的只有1个节点,因此判定这个logtail的pod要调度的就是186这个机器

content:I110713:05:47.7341061capacity_scheduling.go:433]1potentialnodesforpreemption, first1are:[eu-central-1.10.*.*.86]

老pod被抢占的记录日志

content:I110713:05:47.7342711capacity_scheduling.go:662]Poddefault/depl****r-7b656b54b7-stwj8isapotentialpreemptionvictimonnodeeu-central-1.10.*.*.86.

然后logtail的日志记录到了抢占成功

content:I110713:05:47.8207621scheduler.go:484]StatusafterrunningPostFilterpluginsforpodkube-system/logtail-ds-xhzgm:&{0[]}

   这里的0是成功 2是失败如

     

抢占成功后实际也没调度成功,因为内存不够

content:I110713:05:47.8214001factory.go:322]"Unable to schedule pod; no fit; waiting"pod="kube-system/logtail-ds-xhzgm"err="0/2273 nodes are available: 1 Insufficient memory, 2272 node(s) didn't match Pod's node affinity."

 

     (老pod还没杀掉,新pod又被deployment controller尝试拉起,客户将内存资源占的太满了)

最终logtail的pod调度失败了,被删除的pod也被controller重新拉起了一个新的pod起来填补

一句话小结:

不要将节点的内存超卖太多或者占到几乎全部,大部分的DS类型的pod 优先级比较高,超卖率较高时容易发生抢占,设置合理的QOS类型,重要业务可以使用limit == request的QOS类型来保障不被抢占

Scheduler的扩展知识:

Scheduler的简介:

kube-scheduler是Kubernetes中的关键模块,扮演管家的角色遵从一套机制——为Pod提供调度服务,例如基于资源的公平调度、调度Pod到指定节点、或者通信频繁的Pod调度到同一节点等。容器调度本身是一件比较复杂的事,因为要确保以下几个目标:

  • 公平性:在调度Pod时需要公平的进行决策,每个节点都有被分配资源的机会,调度器需要对不同节点的使用作出平衡决策。
  • 资源高效利用:最大化群集所有资源的利用率,使有限的CPU、内存等资源服务尽可能更多的Pod。
  • 效率问题:能快速的完成对大批量Pod的调度工作,在集群规模扩增的情况下,依然保证调度过程的性能。
  • 灵活性:在实际运作中,用户往往希望Pod的调度策略是可控的,从而处理大量复杂的实际问题。因此平台要允许多个调度器并行工作,同时支持自定义调度器。

为达到上述目标,kube-scheduler通过结合Node资源、负载情况、数据位置等各种因素进行调度判断,确保在满足场景需求的同时将Pod分配到最优节点。显然,kube-scheduler影响着Kubernetes集群的可用性与性能,Pod数量越多集群的调度能力越重要,尤其达到了数千级节点数时,优秀的调度能力将显著提升容器平台性能。

Scheduler controller的组成:

下图是kube-scheduler的主要组件:

1. Policy

Scheduler 的调度策略启动配置目前支持三种方式,配置文件 / 命令行参数 / ConfigMap。调度策略可以配置指定调度主流程中要用哪些过滤器 (Predicates)、打分器 (Priorities) 、外部扩展的调度器 (Extenders),以及最新支持的 SchedulerFramwork 的自定义扩展点 (Plugins)。

2. Informer

Scheduler 在启动的时候通过 K8s 的 informer 机制以 List+Watch 从 kube-apiserver 获取调度需要的数据例如:Pods、Nodes、Persistant Volume(PV), Persistant Volume Claim(PVC) 等等,并将这些数据做一定的预处理作为调度器的的 Cache。

3.调度流水线

通过 Informer 将需要调度的 Pod 插入 Queue 中,Pipeline 会循环从 Queue Pop 等待调度的 Pod 放入 Pipeline 执行。

调度流水线 (Schedule Pipeline) 主要有三个阶段:Scheduler Thread,Wait Thread,Bind Thread。

Scheduler Thread 阶段: 从如上的架构图可以看到 Schduler Thread 会经历 Pre Filter -> Filter -> Post Filter-> Score -> Reserve,可以简单理解为 Filter -> Score -> Reserve。

Filter 阶段用于选择符合 Pod Spec 描述的 Nodes;Score 阶段用于从 Filter 过后的 Nodes 进行打分和排序;Reserve 阶段将 Pod 跟排序后的最优 Node 的 NodeCache 中,表示这个 Pod 已经分配到这个 Node 上, 让下一个等待调度的 Pod 对这个 Node 进行 Filter 和 Score 的时候能看到刚才分配的 Pod。

Wait Thread 阶段:这个阶段可以用来等待 Pod 关联的资源的 Ready 等待,例如等待 PVC 的 PV 创建成功,或者 Gang 调度中等待关联的 Pod 调度成功等等;

Bind Thread 阶段:用于将 Pod 和 Node 的关联持久化 Kube APIServer。

整个调度流水线只有在 Scheduler Thread 阶段是串行的一个 Pod 一个 Pod 的进行调度,在 Wait 和 Bind 阶段 Pod 都是异步并行执行。


调度框架的扩展点:

下图显示了一个 Pod 的调度上下文以及调度框架公开的扩展点。 在此图片中,“过滤器”等同于“断言”,“评分”相当于“优先级函数”。

一个插件可以在多个扩展点处注册,以执行更复杂或有状态的任务。

队列排序

这些插件用于对调度队列中的 Pod 进行排序。 队列排序插件本质上提供less(Pod1, Pod2)函数。 一次只能启动一个队列插件。

PreFilter

这些插件用于预处理 Pod 的相关信息,或者检查集群或 Pod 必须满足的某些条件。 如果 PreFilter 插件返回错误,则调度周期将终止。

Filter

这些插件用于过滤出不能运行该 Pod 的节点。对于每个节点, 调度器将按照其配置顺序调用这些过滤插件。如果任何过滤插件将节点标记为不可行, 则不会为该节点调用剩下的过滤插件。节点可以被同时进行评估。

PostFilter

这些插件在 Filter 阶段后调用,但仅在该 Pod 没有可行的节点时调用。 插件按其配置的顺序调用。如果任何 PostFilter 插件标记节点为“Schedulable”, 则其余的插件不会调用。典型的 PostFilter 实现是抢占,试图通过抢占其他 Pod 的资源使该 Pod 可以调度。

PreScore

这些插件用于执行 “前置评分(pre-scoring)” 工作,即生成一个可共享状态供 Score 插件使用。 如果 PreScore 插件返回错误,则调度周期将终止。

Score

这些插件用于对通过过滤阶段的节点进行排序。调度器将为每个节点调用每个评分插件。 将有一个定义明确的整数范围,代表最小和最大分数。 在标准化评分阶段之后,调度器将根据配置的插件权重 合并所有插件的节点分数

NormalizeScore

这些插件用于在调度器计算 Node 排名之前修改分数。 在此扩展点注册的插件被调用时会使用同一插件的 Score 结果。 每个插件在每个调度周期调用一次。

Reserve

Reserve 是一个信息性的扩展点。 管理运行时状态的插件(也成为“有状态插件”)应该使用此扩展点,以便 调度器在节点给指定 Pod 预留了资源时能够通知该插件。 这是在调度器真正将 Pod 绑定到节点之前发生的,并且它存在是为了防止 在调度器等待绑定成功时发生竞争情况。

这个是调度周期的最后一步。 一旦 Pod 处于保留状态,它将在绑定周期结束时触发Unreserve插件 (失败时)或PostBind插件(成功时)。

Permit

Permit插件在每个 Pod 调度周期的最后调用,用于防止或延迟 Pod 的绑定。 一个允许插件可以做以下三件事之一:

  1. 批准
    一旦所有 Permit 插件批准 Pod 后,该 Pod 将被发送以进行绑定。
  2. 拒绝
    如果任何 Permit 插件拒绝 Pod,则该 Pod 将被返回到调度队列。 这将触发
    Unreserve插件。
  3. 等待(带有超时)
    如果一个 Permit 插件返回 “等待” 结果,则 Pod 将保持在一个内部的 “等待中” 的 Pod 列表,同时该 Pod 的绑定周期启动时即直接阻塞直到得到
    批准。如果超时发生,等待变成拒绝,并且 Pod 将返回调度队列,从而触发Unreserve插件。

说明:尽管任何插件可以访问 “等待中” 状态的 Pod 列表并批准它们 (查看FrameworkHandle)。 我们期望只有允许插件可以批准处于 “等待中” 状态的预留 Pod 的绑定。 一旦 Pod 被批准了,它将发送到PreBind阶段。

PreBind

这些插件用于执行 Pod 绑定前所需的所有工作。 例如,一个 PreBind 插件可能需要制备网络卷并且在允许 Pod 运行在该节点之前 将其挂载到目标节点上。

如果任何 PreBind 插件返回错误,则 Pod 将被拒绝并且 退回到调度队列中。

Bind

Bind 插件用于将 Pod 绑定到节点上。直到所有的 PreBind 插件都完成,Bind 插件才会被调用。 各 Bind 插件按照配置顺序被调用。Bind 插件可以选择是否处理指定的 Pod。 如果某 Bind 插件选择处理某 Pod,剩余的 Bind 插件将被跳过

PostBind

这是个信息性的扩展点。 PostBind 插件在 Pod 成功绑定后被调用。这是绑定周期的结尾,可用于清理相关的资源。

Unreserve

这是个信息性的扩展点。 如果 Pod 被保留,然后在后面的阶段中被拒绝,则 Unreserve 插件将被通知。 Unreserve 插件应该清楚保留 Pod 的相关状态。


Kube-scheduler的整体逻辑大图:


参考文献:

https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/kube-scheduler/

https://www.yuque.com/baxiaoshi/tyado3/iy28fu

https://www.yuque.com/baxiaoshi/tyado3/bqs7vg

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
2月前
|
运维 Kubernetes 监控
Kubernetes详解(十九)——Kubernetes Pod控制器
Kubernetes详解(十九)——Kubernetes Pod控制器
51 3
|
1月前
|
容器 Perl Kubernetes
深入 Kubernetes 网络:实战K8s网络故障排查与诊断策略
本文介绍了Kubernetes网络的基础知识和故障排查经验,重点讨论了私有化环境中Kubernetes网络的挑战。首先,文章阐述了Kubernetes网络模型的三大核心要素:Pod网络、Service网络和CNI,并强调了其在容器通信和服务发现中的作用。接着,通过三个具体的故障案例,展示了网络冲突、主节点DNS配置更改导致的服务中断以及容器网络抖动问题的解决过程,强调了网络规划、配置管理和人员培训的重要性。最后,提到了KubeSkoop exporter工具在监控和定位网络抖动问题中的应用。通过这些案例,读者可以深入了解Kubernetes网络的复杂性,并学习到实用的故障排查方法。
146412 19
|
14天前
|
Kubernetes Java 应用服务中间件
Kubernetes 上搭建一个 Nginx 的 Pod,并确保传入的 API 请求被均匀地分发到两个 Java 业务 Pod 上
Kubernetes 上搭建一个 Nginx 的 Pod,并确保传入的 API 请求被均匀地分发到两个 Java 业务 Pod 上
11 0
|
18天前
|
Kubernetes Shell API
技术笔记:K8s中大量Pod是Evicted状态,这是咋回事?
技术笔记:K8s中大量Pod是Evicted状态,这是咋回事?
45 0
|
27天前
|
Kubernetes API 调度
Pod无法调度到可用的节点上(K8s)
完成k8s单节点部署后,创建了一个pod进行测试,后续该pod出现以下报错: Warning FailedScheduling 3h7m (x3 over 3h18m) default-scheduler 0/1 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling..
84 0
|
2月前
|
Kubernetes 算法 调度
k8s群集调度之 pod亲和 node亲和 标签指定
k8s群集调度之 pod亲和 node亲和 标签指定
|
1月前
|
Kubernetes 微服务 容器
Aspire项目发布到远程k8s集群
Aspire项目发布到远程k8s集群
406 2
Aspire项目发布到远程k8s集群
|
1月前
|
Kubernetes Cloud Native 微服务
微服务实践之使用 kube-vip 搭建高可用 Kubernetes 集群
微服务实践之使用 kube-vip 搭建高可用 Kubernetes 集群
219 3
|
6天前
|
存储 Kubernetes 监控
Kubernetes 集群的持续性能优化策略
【5月更文挑战第70天】 随着容器化技术的普及,Kubernetes 已成为管理微服务架构的首选平台。然而,在大规模部署和长期运行过程中,集群往往会遭遇性能瓶颈,影响服务的响应速度和稳定性。本文将探讨针对 Kubernetes 集群的性能优化策略,包括资源调度优化、网络延迟降低、存储效率提升及监控与日志分析等方面,旨在为运维工程师提供一套系统化的持续优化方法,确保集群性能的长期稳定。
|
17天前
|
Kubernetes 网络协议 Docker
k8s 开船记-故障公告:自建 k8s 集群在阿里云上大翻船
k8s 开船记-故障公告:自建 k8s 集群在阿里云上大翻船

推荐镜像

更多