最近在公司的线上服务器上发现了一个现象: 将某个node的kubelet短暂的停掉之后,其上的pod马上会被驱逐,这让笔者大吃一惊,印象之中,停掉kubelet后,该node会变为NotReady状态,随后controller-manger会经过一段时间才开始驱逐其上的pod。还有个参数专门来控制这个时间:

--pod-eviction-timeout The grace period for deleting pods on failed nodes. (default 5m0s)`

该参数默认值为5min, 也就是说当node NotReady之后,最少也得五分钟之后其上的pod才会被驱逐。但是现实情况明显不符合预期啊,这样就有点奇怪了。
鉴于该问题影响巨大,笔者果断开启了debug之旅。

首先我们从直接原因下手,需要了解一下当node NotReady之后,controller-manager是如何判断并驱逐其上的pod的,这部分工作是由node lifecycel controller模块负责。

node lifecycle controller 主要负责对node生命周期进行检查,判断node是否存活,如果长时间检测不到node心跳则驱逐其上的pod。在目前的版本(v1.16)中,默认开启了TaintBasedEvictions, TaintNodesByCondition这两个feature gate,则所有node生命周期管理都是通过condition + taint的方式进行管理。其主要逻辑由三部分组成:

  1. 不断地检查所有node状态,设置对应的condition
  2. 不断地根据node condition 设置对应的taint
  3. 不断地根据taint驱逐node上面的pod

想要详细了解node lifecycle controller工作机制的同学可以翻阅笔者上一篇文章: kubernetes中node心跳处理逻辑分析

查看代码发现--pod-eviction-timeout并未起作用,原来在v1.13版本之前TaintBasedEvictions功能还未开启,此时node not-ready之后,controller直接判断not-ready时间是否超过了--pod-eviction-timeout,超过就进行删除。而v1.13,TaintBasedEvictions功能开启之后就不会使用了该参数,转而使用了上面描述的condition+taint方案。也就是说node NotReady之后,pod的驱逐时间完全由每个pod toleration中 tolerationSecond决定,而不是由controller-manager的参数--pod-eviction-timeout统一决定。这样想想也合情合理,每个pod对于故障的容忍时间不同,tolerationSecond可以更加灵活地为每个pod指定不同的驱逐时间。

这样说来,所有的pod都需要设置一个toleration才对,查阅相关资料后发现,社区已经有了一个DefaultTolerationSeconds admisson controller自动地帮助我们设置toleration,每次创建更新pod, 在请求发送到apiserver之后会自动设置5min的默认toleration。

This admission controller sets the default forgiveness toleration for pods to tolerate the taints notready:NoExecute and unreachable:NoExecute for 5 minutes, if the pods don’t already have toleration for taints node.kubernetes.io/not-ready:NoExecute or node.alpha.kubernetes.io/unreachable:NoExecute.

文档上显示该admission controller默认开启,但是为什么我司的环境上面没有生效,仔细看了一下文档,是因为自己使用了一个deprecated的参数:--admission-control,使用这个参数的话必须显式指定所有要开启的admisson controller plugin列表。该参数在v1.10被废弃,由两个新的参数--enable-admission-plugins--disable-admission-plugins替换,这两个参数如果不指定的话会有默认值,其中DefaultTolerationSeconds就属于--enable-admission-plugins参数的默认值之一,也就是会默认开启该plugin。又是一个升级导致的坑! 正确修改了该参数之后,新创建的pod就会默认带上了toleration,DefaultTolerationSeconds adminssion controller plugin总算生效了。 

新创建的pod总算没有问题了,但是对于集群中已经存在的pod还没有toleration该怎么办? 显然社区对这种情况未做处理,DefaultTolerationSeconds是社区很早就开发的一个feature,但是TaintBasedEvictions是v1.13才默认开启,估计社区在开发时前后没有做好兼容。翻了下DefaultTolerationSecondsadminssion plugin源码,发现该plugin对于pod create, update操作都会设置toleration, 所以一般情况下, 我们升级集群的时候,总是能触发pod发生update,该toleration会自动添加上,无需过多操作,大可不必担心,心里知道有这个事情并检查一下就行。但是笔者的环境已经升级完成了,只能手动触发pod update了,思来想去,想要触发pod update又不能影响业务,给pod打label是一个比较好的方式,于是笔者写了一个脚本将集群中所有的pod都打了一个无关紧要的label, 触发uodate后就自动添加了toleration。

至此整个修复工作全部完成,回过头来仔细想想,kubernetes版本间升级挑战还是挺大的,兼容性问题防不胜防,很可能两个小版本间完全兼容,没任何问题,但是当一步步从低版本升级上来的时候问题就出现了,而且在兼容性测试的时候难以覆盖到每种情况,很可能需要很久问题才能暴露出来。对于这种情况,唯有掌握内部机理,熟读源码才能快速诊断,修复。

记一次kubernetes驱逐踩坑的更多相关文章

  1. Kubernetes探针踩坑记

    1. 荒腔走板 最近一两个月生产K8s集群频繁出现短时503 Service Temporarily Unavailable,还不能主动复现,相当郁闷,压力山大. HTTP 5xx响应状态码用于定义服 ...

  2. 记一次FTP下载踩坑的故(shi)事(gu)

    下班前领导忽然要求我将客户的日志服务器上一些日志拷贝到测试服务器中,不过领导只提供给我FTP的连接方式,很明显就是要我用FTP方式去做啦 一般来说FTP批量下载也就上网随便找个脚本的事,但是却成了我疯 ...

  3. Mac上使用Docker Desktop启动Kubernetes,踩坑后终于搞掂

    1 前言 Kubernetes又简称k8s,是Google开源的容器集群管理系统,最近也是火热.闲来无事(为了发文),捣鼓了一下,在Mac上搭建Kubernetes,遇到一些坑,也记录一下. 另外,D ...

  4. 记一次pm2的踩坑

    1.问题: 公司采用了自动发布平台,最近突然发现一个问题,上线完成后服务是能正常访问的,但是有一个节点访问的时候每两次中总是有一次404,通过nginx的access日志分析发现第一次正常访问有一次g ...

  5. Kubernetes实践踩坑系列(一).应用管理的难题

    应用管理的两大难题  今天我们主要讨论这两个方面的挑战: 对应用研发而言,K8s API 针对简单应用过于复杂,针对复杂应用难以上手: 对应用运维而言,K8s 的扩展能力难以管理:K8s 原生的 AP ...

  6. IdentityServer 部署踩坑记

    IdentityServer 部署踩坑记 Intro 周末终于部署了 IdentityServer 以及 IdentityServerAdmin 项目,踩了几个坑,在此记录分享一下. 部署架构 项目是 ...

  7. Spark踩坑记——Spark Streaming+Kafka

    [TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...

  8. Spark踩坑记——数据库(Hbase+Mysql)

    [TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...

  9. 记jQuery.fn.show的一次踩坑和问题排查

    最近很少已经很少用jQuery,因为主攻移动端,常用Zepto,其实很多细节和jQuery并不一样.最近又无意中接触到了PC的需求和IE6, 使用了jQuery,刚好踩坑了,特意记录一下. 本文内容如 ...

随机推荐

  1. GB国标编码的程序出现乱码

  2. P4550 收集邮票

    P4550 收集邮票 题目描述 有n种不同的邮票,皮皮想收集所有种类的邮票.唯一的收集方法是到同学凡凡那里购买,每次只能买一张,并且买到的邮票究竟是n种邮票中的哪一种是等概率的,概率均为1/n.但是由 ...

  3. 谈谈Java的Collection接口

    目录 谈谈Collection 前言 Collection 方法 1.boolean add(E) 2.void clear() 3.boolean contains(Object o) 4.bool ...

  4. fill 的用法

    博客 : http://blog.csdn.net/liuchuo/article/details/52296646 fill函数的作用是:将一个区间的元素都赋予val值.函数参数:fill(vec. ...

  5. 如何用好Go的测试黑科技

    测试是每一个开发人员都需要掌握的技能,尽管你不需要像测试人员那么专业,但你也应该尽可能的做到那么专业,据我了解到我身边的一些Go开发人员,他们对Go的测试仅仅局限于写一个_test.go 测试文件,对 ...

  6. 关于爬虫的日常复习(16)—— pyspider的初高级用法

  7. (分块)GukiZ and GukiZiana CodeForces - 551E

    题意: 给你一段序列,并且有两种操作 操作①:将序列中从l-r每个元素加上x 操作②:在序列中找到ai=aj=y,j-i的最大值,如果找不到则输出-1 思路: 直接分块暴力即可 对于区间加,普通标记加 ...

  8. 【Java并发基础】使用“等待—通知”机制优化死锁中占用且等待解决方案

    前言 在前篇介绍死锁的文章中,我们破坏等待占用且等待条件时,用了一个死循环来获取两个账本对象. // 一次性申请转出账户和转入账户,直到成功 while(!actr.apply(this, targe ...

  9. C语言进阶——编译预处理指令

    编译预处理指令 • #开头的是编译预处理指令 • 它们不是C语⾔的成分,但是C语⾔程序离不开它们 • #define⽤来定义⼀个宏 #define • #define <名字> <值 ...

  10. NOI2.5 8783:单词接龙

    描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的"龙"(每个单词都最多在"龙"中 ...