Kubernetes容器状态探测的艺术

在Kubernetes集群中维护容器状态更像是一种艺术,而不是科学。原文: The Art and Science of Probing a Kubernetes Container[1]

在Kubernetes集群中维护容器状态更像是一种艺术,而不是科学。

本文将带你深入理解容器探测[2],并特别关注相对较新的启动探测。在此过程中,通过文中的推荐链接,可以进一步了解相关领域,以实现文中的各种建议。

启动……不对……是在Kubernetes集群中请求启动新容器相对简单: 只需要为集群提供一个pod规范[3],尤其是封装了各种工作负载[4]资源(比如Deployment[5]Job[6])的pod模板[7]。在接收到pod规范后,kube-scheduler[8]将为pod分配一个节点,然后该节点的kubelet[9]负责启动pod中的容器。

pod遵循明确的生命周期[10],其中就允许kubelet探测pod容器,以确保始终都有响应。探测器遵循如下契约: pod容器通告端点,kubelet从端点轮询其内部不同状态。

简单来说,有三种类型的探针来表示容器的内部状态:

  • 准备就绪探针(Readiness probes): 该探针告诉kubelet容器何时准备好处理请求,是最普遍的容器探测。
  • 活跃探针(Liveness probes): 该探针在紧急情况下会触发容器中断。kubelet将终止在指定时间间隔内没有成功响应的容器,理想情况下,容器应该在意识到无法继续工作后退出,但在有bug的情况下很少能够优雅退出。
  • 启动探针(Startup probes): 意思是"我刚到这里,别管我"。它告诉kubelet何时开始对readiness和liveness进行探测。
图1: 容器探测和pod生命周期之间的关系
图1: 容器探测和pod生命周期之间的关系

Readiness probes

如果容器未能响应其readiness探测,kubelet将从服务负载均衡器中删除容器,将流量从容器中转移。在这种情况下,开发人员希望其他地方的副本可以处理流量。

readiness探测的设计比较简单,只需要考虑依赖状态和容器中的资源使用情况:

  • 依赖关系(Dependencies)。 假设容器依赖数据库服务器或另一个远程服务,在这种情况下,这些依赖项往往会提供一个端点或命令行接口来评估它们的就绪情况。如果依赖关系处于关键路径中,则在计算探测的readiness状态时需要考虑依赖关系状态。
  • 允许的最大连接数。 许多框架都有接受多少新连接的阈值,因此考虑这些限制并在超过阈值时报告readiness失败。
  • 系统资源。 这一点并不明显,但是在接近内存上限和文件系统空间不足的情况下运行会导致进程不稳定。我们希望集群在耗尽系统资源之前停止向pod发送流量,因此可以考虑在这些限制达到最大值的某个阈值时探测调用失败。我最不喜欢的资源耗尽形式之一是耗尽文件句柄,这比简单的磁盘空间不足更难发现,甚至可能阻碍最基本的故障排除任务。

要做:

  • 实现探针。 始终为运行时容器定义readiness探测。可能你觉得容器客户机可以处理容器无响应问题。尽管如此,让集群将请求路由到还没有准备好处理请求的容器,从来都不是个好选择。
  • 准备好状态。 考虑用单独的readiness线程向外部汇报远程依赖和资源利用状态。readiness探测超时时,最好立即返回清晰的故障代码,而不是冒着暂停响应的风险从所有依赖项收集输入。

不要做:

  • 不要超过liveness探针的探测时间。 如果容器也有liveness探测,不要使最大超时时间( failureThreshold * periodSeconds)超过liveness探测的最大时间。这会让集群将请求路由到可能没有希望的即将崩溃的容器。
  • 不要把反应缓慢和readiness混在一起。 缓慢的反应也是一种反应。由于依赖关系处理请求的时间比通常要长得多,可能你会觉得容器需要让调用者知道它还没有准备好。不过,监视服务性能是应用级的关注点,最好通过可观察性解决。

Liveness probes

如果容器不能连续响应此探测,kubelet将终止容器。具体是"终止"还是"重启",取决于pod的重启策略[11]

众所周知,对这些探针进行正确编码非常困难,因为探针开发人员的目标是预测意外情况,比如进程中的bug可能会使整个容器处于不可恢复状态这样的情况。

如果探测过于宽松,容器可能会处于无响应状态而不会被终止,从而减少了可以提供服务的pod副本数量。

如果探测过于严格,容器可能会一直被不必要的终止,这种情况在间歇性发生时很难察觉,当你排查问题时,pod可能看起来很健康。

要做:

  • 定义liveness探针。 没有liveness探测意味着容器可能会因为某个错误而永远无法响应,所以即使无法完全确定万无一失的liveness标准,还是要尝试定义。
  • 监控资源。 覆盖文件系统空间、文件句柄和内存等资源。这些资源在耗尽时会发生容器锁定这样臭名昭著的现象。当内存利用率超过90%时返回错误,比在达到100%后完全失去响应更明智。探测有超时值,但最好返回清晰的失败代码,而不是让kubelet从超时来推断崩溃。
  • 使用命令。 调用命令而不是tcp或http请求。这个建议可能有争议,但是调用shell命令将使用较低级别的接口,反过来又有更多机会评估容器内部状态。我遇到过一些网络服务器,即使由于内存不足而半死不活,仍然能够响应简单的ping请求。
  • 微控制面(Micro control-planes)。 如果可能的话,使用与用于服务客户流量的连接池不同的连接池,或者专门为探测设置连接,将其设想为集群中与 常规工作负载 [12]不同(但规模要小得多)的控制平面。除非liveness探针具有响应探测的专用连接,否则容器可能正在忙于服务客户流量(并通过readiness探针报告了未准备就绪状态)。在这种情况下终止容器对业务有害,因为集群最后(临时)只有更少的容器来处理业务流量。
  • 准备好状态。 类似于liveness探针一节中的建议,考虑用单独的liveness探针服务线程向外部汇报活跃状态。liveness探测超时时,最好立即返回清晰的故障代码,而不是冒着暂停响应的风险从所有依赖项收集输入。

不要做:

  • readiness不是liveness: 不要检查依赖关系的可用性,如果失败,这是readiness探针的责任,终止pod不太可能有帮助。
  • 不要重用readiness条件: 经常看到容器探测使用相同的端点,但在 failureThresholdperiodSeconds中使用不同的阈值。liveness探测的关注点不同于readiness探测的关注点。容器可能由于外部因素而无法处理流量,而liveness探测使用与readiness探测相同的端点,可能会告诉kubelet终止容器,从而加剧问题。
  • 超时时间超过readiness探测: 无论是查看 failureThresholdperiodSeconds还是考虑容器中系统资源的可用性,都要确保liveness探测的超时范围超过readiness探测的超时范围。例如,最大超时时间( initialDelaySeconds + failureThreshold * periodSeconds)比readiness探测的最大超时时间更短会造成容器在仍然为远程请求服务的情况下被过早终止。
  • 不要过于保守: 在有疑问时,宁可宽大处理,也要为 failureThresholdperiodSecondsinitialDelaySeconds设置更高的值,给容器足够的自由度来报告生存状态。一个不错的经验法则是使用比readiness探针的最大超时时间长两倍或更长的总超时时间。意外挂起进程是一种边缘情况,比响应缓慢的进程更罕见,liveness探测应该支持最常见的情况。
图2: liveness探测应该比readiness探测的时间更长。
图2: liveness探测应该比readiness探测的时间更长。

Startup probes

startup探针是容器探针中相对较新的成员,2020年底在Kubernetes 1.20[13]中达到了GA。注意,这要归功于我的同事,博学的Nathan Brophy[14],他指出这个功能在Kubernetes 1.18尽管还处于测试阶段,但已经默认可用[15]了。

startup探测在容器生命周期中为需要大量时间才能准备就绪的容器创建了一个"缓冲区"。

在过去,在没有startup探测的情况下,开发人员使用初始化容器[16],并为readiness探测和liveness探测设置较长的initialDelaySeconds值,每一种都有自己的权衡:

  • 可以等待,但不应该等待。 初始化容器允许开发人员将特定工具和安全特权与运行时容器隔离开来,但这是一种等待外部条件的笨拙方式。初始化容器是独立容器,因此将持续运行直到完成,将它们的工作结果转移到pod中的其他容器中可能会很麻烦。
  • 启动缓慢。 在readiness探测上通过 initialDelaySeconds字段设置长时间等待会在容器启动期间浪费时间,因为kubelet总是需要在将流量发送到pod之前等待这么长时间。

考虑现有liveness探测和readiness探测是否需要相对较长的时间来启动,并将较大的initialDelaySeconds值替换为等效的startup探测。

例如,下面的容器规范:

spec:
  containers:
  - name: myslowstarter
    image: ...
    ...
    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 600
      periodSeconds: 10
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 600
      periodSeconds: 20

可以通过将延迟挪到startup探测中来显著改善,如下例所示:

spec:
  containers:
  - name: myslowstarter
    image: ...
    ...
    readinessProbe:
      tcpSocket:
        port: 8080
      # i̵n̵i̵t̵i̵a̵l̵D̵e̵l̵a̵y̵S̵e̵c̵o̵n̵d̵s̵:̵ ̵6̵0̵0̵
      periodSeconds: 10
    livenessProbe:
      tcpSocket:
        port: 8080
      # i̵n̵i̵t̵i̵a̵l̵D̵e̵l̵a̵y̵S̵e̵c̵o̵n̵d̵s̵:̵ ̵6̵0̵0̵
      periodSeconds: 20
    startupProbe:
      tcpSocket:
        port: 8080
      failureThreshold: 60
      periodSeconds: 10

在第一个示例中,kubelet在评估readiness和liveness之前等待600秒。相比之下,在第二个示例中,kubelet以10秒的间隔检查最多60次,从而使容器能够在满足启动条件时立即启动。

在startup探测中频繁检查的隐藏好处是,允许开发人员为failureThresholdperiodSeconds设置较高的值,而不用担心减慢容器启动速度。相反,死板的设置initialDelaySeconds给开发人员施加了压力,忽略了边缘情况,只能通过设置较低的值才能让整个应用更快启动。根据我的经验,"边缘情况"是"我们在开发过程中没有看到的东西"的同义词,这意味着在某些生产环境中会出现不稳定的容器。

根据经验,如果readiness探测和liveness探测中的initialDelaySeconds字段超过failureThreshold * periodSeconds字段指定的总时间,则使用startup探测。另一条经验法则是,readiness探测或liveness探测中initialDelaySeconds的时间如果超过60秒,就说明应用将受益于使用startup探测。

速度就是一切

在看到本文的建议后,你可能不可避免的会问下面的问题:

"那么我应该用什么来设置探针呢?"

我们通常希望readiness探针比较敏感,并且在容器开始难以响应请求时就报告失败。另一方面,希望liveness探针稍微宽松一点,只在代码失去对有效内部状态的控制时才报告失败。

对于timeoutSeconds,我建议保持默认值(1秒)。这个建议建立在另一个建议之上,即通过用于评估响应kubelet请求的线程之外的探针的响应。使用较高的值将扩大窗口,集群会将流量路由到无法处理请求的容器。

对于periodSecondsfailureThreshold的组合,在相同间隔内进行更多检查往往比较少检查更准确。假设我们遵循了将容器状态与响应请求的线程分开评估的建议,那么更频繁的检查不会给容器增加显著的开销。

注意CPU限制

不同的集群,不同的速度。

探测(尤其是liveness探测)的一个常见问题是,假设集群总是按照要求为容器提供足够的CPU,另一个常见错误是假设集群总是能够精确观察到部分请求。

从hypervisor和承载工作节点的VM开始,一直到pod规范中的CPU限制[17],容器有无数原因可以以不同速度运行同一段代码。

以下是最容易让开发者措手不及的因素:

  • hypervisor中的cpu复用: IaaS供应商的共享虚拟机,即使硬件和网络速度相同,也会偶尔受到"邻居"的影响,从而导致CPU使用量激增。现代hypervisors非常擅长补偿这样的突发状况,甚至会采取节流措施。尽管如此,IaaS还是可能会超卖CPU,并假设不会同时出现流量突发状况。
  • 无穷小的CPU请求: 将CPU分配给容器的CPU限制设置为20ms似乎是一个负责任的、有意识的决定,因为容器很少进行任何处理。然而,在现实世界中,工作节点的vCPU并不只有完整vCPU大小的2%。工作节点试图通过在短时间内为容器提供整个vCPU来模拟这个微小的vCPU,从而导致对容器CPU分配产生碎片。因此,容器可能在短时间内运行比所请求的更多的CPU时间,然后暂停比预期更长的时间。

了解一些关于IaaS提供商的硬件特性和超卖设置的知识,可以帮助我们决定将安全乘数添加到timeoutSecondsfailureThresholdperiodSeconds等设置中。在为探针,特别是liveness探针设置时,请记住这两个因素。根据所了解的内容,还可以重新考虑CPU requests和limits的设置,以便探针有足够的处理能力及时响应请求。

图3: 由于严格的CPU限制而终止正常运行的容器
图3: 由于严格的CPU限制而终止正常运行的容器
结论

本文提供了一系列建议来提高容器探测的精度和性能,使容器能够更快启动并运行更长时间。

下一步是仔细分析容器中运行的内容,并研究在不同集群和条件下的实际运行时行为,模拟依赖关系失败或者降低系统资源可用性。使用kubectl及其格式化和过滤内容的功能,是查找重新启动多次以及探测不充分的容器的好方法,在The art and science of probing a Kubernetes container, part 2: kubectl queries[18]这篇文章中有更多相关技术内容。将PromQL与Kubernetes指标结合使用可以用各种时间序列图表进一步扩展该技术,这也是那篇文章的主题。

总之,在编写探针时牢记目标,并确保快速可靠的运行,在对kubelet的响应中以尽可能(如果有的话)精确的方式提供清晰的信息。然后,信任集群会以最佳方式处理数据,确保容器对其客户端提供最大的可用性。


你好,我是俞凡,在Motorola做过研发,现在在Mavenir做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。
微信公众号:DeepNoMind

参考资料

[1]

The Art and Science of Probing a Kubernetes Container: https://dnastacio.medium.com/the-art-and-science-of-probing-a-kubernetes-container-db1f16539080

[2]

Pod Probe: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#Probe

[3]

Pod Specification: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1

[4]

Workload Resource: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources

[5]

Deployment: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/deployment-v1

[6]

Job: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/job-v1

[7]

Pod Template: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-template-v1/#PodTemplateSpec

[8]

kube-scheduler: https://kubernetes.io/docs/reference/command-line-tools-reference/kube-scheduler

[9]

kubelet: https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet

[10]

Pod Lifecycle: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle

[11]

Pod Restart Policy: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy

[12]

Kubernetes Components: https://kubernetes.io/docs/concepts/overview/components

[13]

Kubernetes 1.20: https://kubernetes.io/blog/2020/12/08/kubernetes-1-20-release-announcement

[14]

Nathan Brophy: https://www.linkedin.com/in/nathan-brophy-905a16171

[15]

Feature Gates: https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates

[16]

Init Container: https://kubernetes.io/docs/concepts/workloads/pods/init-containers

[17]

Resource Management for Pods and Containers: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers

[18]

The art and science of probing a Kubernetes container, part 2: kubectl queries: https://sourcepatch.blogspot.com/2021/12/6-kubectl-queries-for-validating.html

- END -

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/157450.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux安装ErLang(亲测可用)

注(我这里安装完成后显示的是中文,有的是显示的英文) 1.下载er wget https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm2.安装er yum -y install epel-release截图截不全,就只截安装完成的部分了 rp…

2023年中国语言大模型行业发展趋势分析:预计未来行业将迎来高速增长[图]

自然语言处理(NLP)大模型是一种利用深度学习技术来理解、解释和生成人类语言的高参数模型。语言大模型通过编码解码的方式模仿人类处理语言的过程从而达到进行自然语言文本输出的能力。 语言大模型主要组成部分 资料来源:共研产业咨询&#…

STM32出现 Invalid Rom Table 芯片锁死解决方案

出现该现象的原因为板子外部晶振为25M,而程序软件上以8M为输入晶振频率,导致芯片超频锁死,无法连接、下载。 解决方案 断电,将芯片原来通过10k电阻接地的BOOT0引脚直接接3.3V,硬件上置1上电,连接目标板&am…

3.9-Dockerfile实战

这一节介绍怎么将python程序打包成一个image,然后运行为一个container。 首先,创建/home/python/目录 mkdir /home/python/ 然后创建app.py文件。 vim app.py app.py文件的内容如下: from flask import Flaskapp Flask(__name__)app.route(…

解决收集问卷难的方法与策略:提升数据收集效率

随着社会的发展和科技的进步,问卷调查成为了获取信息和研究数据的重要手段之一。然而,面临的一个普遍难题是如何解决收集问卷困难的问题。无论是在学术研究、市场调研还是社会调查中,都存在着一些挑战和阻碍因素。本文将从不同角度探讨如何突…

B032-服务器 Tomcat JavaWeb项目 Servlet

目录 服务器服务器的认识 Tomcat服务器Tomcat服务器的介绍Tomcat的安装Tomcat报错的情况Tomcat要启动成功的条件 JavaWeb项目Web的项目结构发布项目的第一种方式发布项目的第二种方式 Eclipse中搭建动态Web项目eclipse安装Tomcat插件servletservlet示例servlet的执行流程servle…

同为科技(TOWE)工业连接器:保障高效、可靠、安全的电气连接

国内经济快速的发展,人们生活水平的不断提高,基础设施的建设是发展的基础,完善的基础设施对加速经济的发展起到至关重要的作用。其中,基础建设中机场、港口、电力、通讯等公共设施必须配套相应的电气设施,工业用插头插…

函数模板(成长版)

与普通函数区别&#xff1a;1.多了个template<class T>;2.某些确定类型变不确定类型T 一&#xff1a;引子&#xff1a; #include<iostream> using namespace std; template<typename T> T Max(T a, T b) {return a > b ? a : b; } int main() {int x, …

Mysql数据库 17.Mysql存储引擎

Mysql体系结构分为4层&#xff1a; 1.连接层 最上层是一些客户端和连接服务&#xff0c;包括大多数基于客户端/服务端工具实现的类似于TCP/IP的通信&#xff0c;主要功能是完成一些类似于连接处理、授权认证、安全方案等&#xff0c;在该层上还引入线程池的概念&#xff0c;为…

vue实现聊天栏定位到最底部(超简单、可直接复制使用)

原理 通过watch监听聊天内容的加载&#xff0c;一旦加载完成或者数据更新触发vue的数据监听时&#xff0c;就重新修改【滚动滑钮到滚动条顶部的距离滚动条的高度】&#xff0c;从而实现定位到底部的效果。 实现 1、布局 新建一个div&#xff08;聊天框&#xff0c;如下&…

微信收款助手消息不弹窗的解决办法

最近在做微信个人收款的回调&#xff0c;主要方法是根据通知栏截取收款信息&#xff0c;然后进行回调。 其中&#xff0c;发现一个问题&#xff0c;就是微信版本某次升级后&#xff0c;发现微信收款时不弹出消息了。 于是找到了这个解决方法&#xff0c;遇到相同问题的同学们…

Qt TCP相关的一些整理:服务端常见操作 socket 通信 network

目录 前言&#xff1a; 1、相关的库和类 2、服务端常用API 核心代码呈上&#xff1a; 前言&#xff1a; 在Qt的服务端上&#xff0c;不单单会用到服务端本身的API&#xff0c;对连接上来的客户端&#xff0c;也需要进行数据交互&#xff0c;也要用到一些收发包相关的…

代码随想录刷题】Day16 二叉树03

文章目录 1.【104】二叉树的最大深度&#xff08;优先掌握递归&#xff09;1.1 前言1.2 题目描述1.3 递归法java代码实现1.4 迭代法java代码实现1.5 相关练习题【559】N叉树的最大深度 2.【111】二叉树的最小深度&#xff08;优先掌握递归&#xff09;2.1 题目描述2.2 递归法ja…

力扣每日一题-美化数组的最少删除数-2023.11.21

力扣每日一题&#xff1a;美化数组的最少删除数 开篇 今天的力扣每日一题居然写出来了&#xff0c;好开心&#xff0c;迫不及待地把题目分享出来&#xff0c;希望你也能把它狠狠拿下。 题目链接: 2216.美化数组的最少删除数 题目描述 代码思路 创建一个list集合来保存数组&a…

c语言上机作业:给函数增加防御机制

1.题目 2.思路 1.首先&#xff0c;我们可以知道&#xff0c;我们必须先要把z求出来&#xff0c;但这里需要注意的是x&#xff0c;y并不包含了全部的定义域&#xff0c;所以我们必须先判断是否输入的数据满足条件。而这&#xff0c;就是我们所需要突破的函数的防御&#xff0c;…

.nvmrc 文件使用详解

文章目录 1. 前言2. .nvmrc 是什么3. 创建 .nvmrc 文件4. 使用 .nvmrc 文件5. 终端自动切换版本 1. 前言 当开发多个项目时&#xff0c;每个项目运行环境要求的 node 版本不一样&#xff0c;那么我们就需要给每个项目指定 node 版本&#xff0c;也就是通过终端执行 nvm install…

风丘电动汽车热管理方案 为您的汽车研发保驾护航

热管理技术作为汽车节能、提高经济性和保障安全性的重要措施&#xff0c;在汽车研发过程中具有重要作用。传统燃油汽车的热管理系统主要包括发动机、变速器散热系统和汽车空调&#xff0c;而电动汽车的热管理系统在燃油汽车热管理架构的基础之上&#xff0c;又增加了电机电控热…

Android HAL学习 及 与BSP的区别

Android HAL学习 及 与BSP的区别 参考链接&#xff1a; 1、https://www.cnblogs.com/looner/articles/11579335.html 2、https://blog.csdn.net/leesan0802/article/details/124087630 3、https://zhuanlan.zhihu.com/p/336531442 在HAL的学习之前&#xff0c;我们来先了解…

SPASS-指数平滑法

基本概念及统计原理 基本概念 指数平滑法的思想来源于对移动平均预测法的改进。指数平滑法的思想是以无穷大为宽度&#xff0c;各历史值的权重随时间的推移呈指数衰减&#xff0c;这样就解决了移动平均的两个难题。 统计原理 简单模型 Holt线性趋势模型 案例 为了研究上海市…

数据结构(c语言版) 树的遍历

作业要求 以如下图为例&#xff0c;完成树的遍历&#xff1a; 1、利用孩子兄弟表示法的存储结构 2、利用先根序列创建树 3、先根遍历树 4、后根遍历树 思考 预期的结果应该为&#xff1a; 1、先根创建树时需要输入的数据为&#xff1a; A B E 0 F 0 0 C 0 D G 0 0 0 0 2、…