在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探测,kubelet将从服务负载均衡器中删除容器,将流量从容器中转移。在这种情况下,开发人员希望其他地方的副本可以处理流量。
readiness探测的设计比较简单,只需要考虑依赖状态和容器中的资源使用情况:
要做:
不要做:
failureThreshold * periodSeconds
)超过liveness探测的最大时间。这会让集群将请求路由到可能没有希望的即将崩溃的容器。 如果容器不能连续响应此探测,kubelet将终止容器。具体是"终止"还是"重启",取决于pod的重启策略[11]。
众所周知,对这些探针进行正确编码非常困难,因为探针开发人员的目标是预测意外情况,比如进程中的bug可能会使整个容器处于不可恢复状态这样的情况。
如果探测过于宽松,容器可能会处于无响应状态而不会被终止,从而减少了可以提供服务的pod副本数量。
如果探测过于严格,容器可能会一直被不必要的终止,这种情况在间歇性发生时很难察觉,当你排查问题时,pod可能看起来很健康。
要做:
不要做:
failureThreshold
和 periodSeconds
中使用不同的阈值。liveness探测的关注点不同于readiness探测的关注点。容器可能由于外部因素而无法处理流量,而liveness探测使用与readiness探测相同的端点,可能会告诉kubelet终止容器,从而加剧问题。 failureThreshold
、 periodSeconds
还是考虑容器中系统资源的可用性,都要确保liveness探测的超时范围超过readiness探测的超时范围。例如,最大超时时间( initialDelaySeconds + failureThreshold * periodSeconds
)比readiness探测的最大超时时间更短会造成容器在仍然为远程请求服务的情况下被过早终止。 failureThreshold
、 periodSeconds
和 initialDelaySeconds
设置更高的值,给容器足够的自由度来报告生存状态。一个不错的经验法则是使用比readiness探针的最大超时时间长两倍或更长的总超时时间。意外挂起进程是一种边缘情况,比响应缓慢的进程更罕见,liveness探测应该支持最常见的情况。 startup探针是容器探针中相对较新的成员,2020年底在Kubernetes 1.20[13]中达到了GA。注意,这要归功于我的同事,博学的Nathan Brophy[14],他指出这个功能在Kubernetes 1.18尽管还处于测试阶段,但已经默认可用[15]了。
startup探测在容器生命周期中为需要大量时间才能准备就绪的容器创建了一个"缓冲区"。
在过去,在没有startup探测的情况下,开发人员使用初始化容器[16],并为readiness探测和liveness探测设置较长的initialDelaySeconds
值,每一种都有自己的权衡:
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探测中频繁检查的隐藏好处是,允许开发人员为failureThreshold
和periodSeconds
设置较高的值,而不用担心减慢容器启动速度。相反,死板的设置initialDelaySeconds
给开发人员施加了压力,忽略了边缘情况,只能通过设置较低的值才能让整个应用更快启动。根据我的经验,"边缘情况"是"我们在开发过程中没有看到的东西"的同义词,这意味着在某些生产环境中会出现不稳定的容器。
根据经验,如果readiness探测和liveness探测中的initialDelaySeconds
字段超过failureThreshold * periodSeconds
字段指定的总时间,则使用startup探测。另一条经验法则是,readiness探测或liveness探测中initialDelaySeconds
的时间如果超过60秒,就说明应用将受益于使用startup探测。
在看到本文的建议后,你可能不可避免的会问下面的问题:
"那么我应该用什么来设置探针呢?"
我们通常希望readiness探针比较敏感,并且在容器开始难以响应请求时就报告失败。另一方面,希望liveness探针稍微宽松一点,只在代码失去对有效内部状态的控制时才报告失败。
对于timeoutSeconds
,我建议保持默认值(1秒)。这个建议建立在另一个建议之上,即通过用于评估响应kubelet请求的线程之外的探针的响应。使用较高的值将扩大窗口,集群会将流量路由到无法处理请求的容器。
对于periodSeconds
和failureThreshold
的组合,在相同间隔内进行更多检查往往比较少检查更准确。假设我们遵循了将容器状态与响应请求的线程分开评估的建议,那么更频繁的检查不会给容器增加显著的开销。
不同的集群,不同的速度。
探测(尤其是liveness探测)的一个常见问题是,假设集群总是按照要求为容器提供足够的CPU,另一个常见错误是假设集群总是能够精确观察到部分请求。
从hypervisor和承载工作节点的VM开始,一直到pod规范中的CPU限制[17],容器有无数原因可以以不同速度运行同一段代码。
以下是最容易让开发者措手不及的因素:
了解一些关于IaaS提供商的硬件特性和超卖设置的知识,可以帮助我们决定将安全乘数添加到timeoutSeconds
、failureThreshold
和periodSeconds
等设置中。在为探针,特别是liveness探针设置时,请记住这两个因素。根据所了解的内容,还可以重新考虑CPU requests和limits的设置,以便探针有足够的处理能力及时响应请求。
本文提供了一系列建议来提高容器探测的精度和性能,使容器能够更快启动并运行更长时间。
下一步是仔细分析容器中运行的内容,并研究在不同集群和条件下的实际运行时行为,模拟依赖关系失败或者降低系统资源可用性。使用kubectl及其格式化和过滤内容的功能,是查找重新启动多次以及探测不充分的容器的好方法,在The art and science of probing a Kubernetes container, part 2: kubectl queries[18]这篇文章中有更多相关技术内容。将PromQL与Kubernetes指标结合使用可以用各种时间序列图表进一步扩展该技术,这也是那篇文章的主题。
总之,在编写探针时牢记目标,并确保快速可靠的运行,在对kubelet的响应中以尽可能(如果有的话)精确的方式提供清晰的信息。然后,信任集群会以最佳方式处理数据,确保容器对其客户端提供最大的可用性。
你好,我是俞凡,在Motorola做过研发,现在在Mavenir做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。
微信公众号:DeepNoMind
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 多平台发布