探究kubernetes 探针参数periodSeconds和timeoutSeconds

kubernetes,periodseconds,timeoutseconds · 浏览次数 : 13

小编点评

在Kubernetes中,探针(probe)是用于检测容器或节点健康状况的机制。探针分为三种类型:liveness探针、readiness探针和startup探针。它们分别用于检测容器是否正在运行、是否准备就绪以及是否已启动。 periodSeconds和timeoutSeconds是探针配置中的两个重要参数,它们的作用如下: 1. periodSeconds:这个参数表示探针执行的周期,即在一段时间内应该执行的探针次数。默认值为10秒。最小值为1秒。 2. timeoutSeconds:这个参数表示探针超时的时间。当探针在periodSeconds内没有返回有效结果时,探针将认为容器或节点不可用。默认值为1秒。最小值为1秒。 关于periodSeconds和timeoutSeconds之间的关系,文档中并没有明确说明。实际上,它们之间并没有直接的关系。探针会周期性地执行,每次执行的时间可能超过periodSeconds,但这并不意味着探针会在periodSeconds后立即超时。 如果timeoutSeconds大于periodSeconds,那么在periodSeconds时间内,探针最多只能执行一次。如果在periodSeconds时间内探针未能成功执行,那么探针将认为容器或节点不可用,并触发失败事件。 在实际应用中,通常建议将timeoutSeconds设置为小于periodSeconds的合理值。这样可以避免因过度频繁的执行探针而导致不必要的资源浪费。同时,根据实际情况调整failureThreshold和successThreshold,以便更好地控制探针的执行策略。

正文

探究kubernetes 探针参数 periodSecondstimeoutSeconds

问题起源

kubernetes probes的配置中有两个容易混淆的参数,periodSecondstimeoutSeconds,其配置方式如下:

apiVersion: v1
kind: Pod
metadata:
  name: darwin-app
spec:
  containers:
  - name: darwin-container
    image: darwin-image
    livenessProbe:
      httpGet:
        path: /darwin-path
        port: 8080
      initialDelaySeconds: 60
      periodSeconds: 10
      timeoutSeconds: 5
      failureThreshold: 3

官方对这两个参数的解释如下:

  • periodSeconds: How often (in seconds) to perform the probe. Default to 10 seconds. The minimum value is 1.
  • timeoutSeconds: Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1.

意思是说periodSeconds表示执行探针的周期,而timeoutSeconds表示执行探针的超时时间。

网上有不少针对这两个参数的讨论(如下),其中涉及到一个问题,如果timeoutSeconds > periodSeconds 会怎么样?

  1. What is the role of timeoutSeconds in kubernetes liveness/readiness probes?
  2. Kubernetes Health Check: timeoutSeconds exceeds periodSeconds
  3. Does periodSeconds in Kubernetes probe configuration count from the last probe time or the last response/failure time?

其中在上面的第3篇中对timeoutSeconds>periodSeconds的情况有如下描述,即在这种情况下,如果探针超时,则探针周期等于timeoutSeconds。那么这种说法是否正确呢?

If you had the opposite (timeoutSeconds=10, periodSeconds=5), then the probes would look as follows:

0s: liveness probe initiated
10s: liveness probe times out
10s: liveness probe initiated again

源码探究

鉴于网上众说纷纭,我们通过源码来一探究竟。

kubernetes的探针机制是由kubelet执行的,目前支持execgrpchttpGettcpSocket这4种探针方式。

探针的代码逻辑并不复杂,以v1.30.2的代码为例,其入口函数如下,可以看到它会启动一个周期为w.spec.PeriodSeconds(即探针中定义的periodSeconds)定时器,周期性地执行探针。

// run periodically probes the container.
func (w *worker) run() {
	ctx := context.Background()
	probeTickerPeriod := time.Duration(w.spec.PeriodSeconds) * time.Second
	...

	probeTicker := time.NewTicker(probeTickerPeriod)
	...
probeLoop:
	for w.doProbe(ctx) {
		// Wait for next probe tick.
		select {
		case <-w.stopCh:
			break probeLoop
		case <-probeTicker.C:
		case <-w.manualTriggerCh:
			// continue
		}
	}
}

现在已经找到periodSeconds的用途,下一步需要找到timeoutSeconds

  1. 首先进入doProbe函数,它调用了w.probeManager.prober.probe

    // doProbe probes the container once and records the result.
    // Returns whether the worker should continue.
    func (w *worker) doProbe(ctx context.Context) (keepGoing bool) {
    	...
    	// Note, exec probe does NOT have access to pod environment variables or downward API
    	result, err := w.probeManager.prober.probe(ctx, w.probeType, w.pod, status, w.container, w.containerID)
    	if err != nil {
    		// Prober error, throw away the result.
    		return true
    	}
    	...
    }
    
  2. 下面的probe函数用于执行一个特定的探针。需要注意的是,它调用了pb.runProbeWithRetries,其中maxProbeRetries值为3,说明在一个周期(periodSeconds)中最多可以执行3次探针命令

    // probe probes the container.
    func (pb *prober) probe(ctx context.Context, probeType probeType, pod *v1.Pod, status v1.PodStatus, container v1.Container, containerID kubecontainer.ContainerID) (results.Result, error) {
    	var probeSpec *v1.Probe
    	switch probeType {
    	case readiness:
    		probeSpec = container.ReadinessProbe
    	case liveness:
    		probeSpec = container.LivenessProbe
    	case startup:
    		probeSpec = container.StartupProbe
    	default:
    		return results.Failure, fmt.Errorf("unknown probe type: %q", probeType)
    	}
    	...
    	result, output, err := pb.runProbeWithRetries(ctx, probeType, probeSpec, pod, status, container, containerID, maxProbeRetries)
    	...
    }
    
  3. runProbeWithRetries的注释说明,可能会执行多次探针,直到探针返回成功或全部尝试失败:

    // runProbeWithRetries tries to probe the container in a finite loop, it returns the last result
    // if it never succeeds.
    func (pb *prober) runProbeWithRetries(ctx context.Context, probeType probeType, p *v1.Probe, pod *v1.Pod, status v1.PodStatus, container v1.Container, containerID kubecontainer.ContainerID, retries int) (probe.Result, string, error) {
    	...
    	for i := 0; i < retries; i++ {
    		result, output, err = pb.runProbe(ctx, probeType, p, pod, status, container, containerID)
    	  ...
    	}
    	...
    }
    
  4. runProbe函数中,最终找到了timeoutSeconds对应的参数p.TimeoutSeconds,其作为各个探针命令的超时参数,如在httpGet类型的探针中,它作为了httpClient的请求超时时间:

    
    func (pb *prober) runProbe(ctx context.Context, probeType probeType, p *v1.Probe, pod *v1.Pod, status v1.PodStatus, container v1.Container, containerID kubecontainer.ContainerID) (probe.Result, string, error) {
    
      timeout := time.Duration(p.TimeoutSeconds) * time.Second
      
    	if p.Exec != nil {
    		command := kubecontainer.ExpandContainerCommandOnlyStatic(p.Exec.Command, container.Env)
    		return pb.exec.Probe(pb.newExecInContainer(ctx, container, containerID, command, timeout))
    	}
      
    	if p.HTTPGet != nil {
    		req, err := httpprobe.NewRequestForHTTPGetAction(p.HTTPGet, &container, status.PodIP, "probe")
    		...
    		return pb.http.Probe(req, timeout)
    	}
      
    	if p.TCPSocket != nil {
    		port, err := probe.ResolveContainerPort(p.TCPSocket.Port, &container)
    		...
    		host := p.TCPSocket.Host
    		if host == "" {
    			host = status.PodIP
    		}
    		return pb.tcp.Probe(host, port, timeout)
    	}
    
    	if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.GRPCContainerProbe) && p.GRPC != nil {
    		host := status.PodIP
    		service := ""
    		if p.GRPC.Service != nil {
    			service = *p.GRPC.Service
    		}
    		return pb.grpc.Probe(host, service, int(p.GRPC.Port), timeout)
    	}
    	...
    }
    

至此我们可以拼接出periodSecondstimeoutSeconds的关系,其逻辑关系与如下代码类似。

probeTicker := time.NewTicker(periodSeconds)

for {
	select {
	case <-probeTicker.C:
    for i := 0; i < 3; i++ {
      if ok:=probe(timeoutSeconds);ok{
        return
      }
    }
}

总结

  • periodSeconds用于启动一个周期性调用探针命令的定时器,而timeoutSeconds作为探针命令的超时参数
  • timeoutSecondsperiodSeconds之间并没有明确的关系。如果timeoutSeconds=10s,periodSeconds=5s,则本次探针周期可能为[5s, 30s)之内的任意值,并不是该文中说的periodSeconds=timeoutSeconds(由于本文写于3年前,经查阅v1.19.10版本代码,逻辑上与现有版本代码相同。)
  • 由于健康检查的逻辑大部分都不会很复杂,如检查某个文件是否存在,检查服务的/hleathz http endpoint是否可以访问等,因此建议将timeoutSeconds设置为一个小于periodSeconds的合理的值。

failureThreshold/successThresholdmaxProbeRetries的关系

  • maxProbeRetries用于定义一次探针周期内探针命令执行的最大尝试次数;
  • 如果在一个探针周期内,探针命令返回成功,则successThreshold 加1,反之failureThreshold加1;

与探究kubernetes 探针参数periodSeconds和timeoutSeconds相似的内容:

探究kubernetes 探针参数periodSeconds和timeoutSeconds

探究kubernetes 探针参数 periodSeconds和timeoutSeconds 问题起源 kubernetes probes的配置中有两个容易混淆的参数,periodSeconds和timeoutSeconds,其配置方式如下: apiVersion: v1 kind: Pod met

Kubernetes:kubelet 源码分析之探针

0. 前言 kubernetes 提供三种探针,配置探针(Liveness),就绪探针(Readiness)和启动(Startup)探针判断容器健康状态。其中,存活探针确定什么时候重启容器,就绪探针确定容器何时准备好接受流量请求,启动探针判断应用容器何时启动。 本文通过分析 kubelet 源码了解

Kubernetes 数据存储:从理论到实践的全面指南

本文深入解析 Kubernetes (K8S) 数据存储机制,探讨其架构、管理策略及最佳实践。文章详细介绍了 K8S 数据存储的基础、架构组成、存储卷管理技巧,并通过具体案例阐述如何高效、安全地管理数据存储,同时展望了未来技术趋势。 关注【TechLeadCloud】,分享互联网架构、云服务技术的全

K8s 多集群实践思考和探索

本文主要讲述了一些对于k8s多集群管理的思考,包括为什么需要多集群、多集群的优势以及现有的一些基于Kubernetes衍生出的多集群管理架构实践。

探究:普通人都是怎么入门编程

前景提要 很多人想要入门编程语言,但是,费了九牛二虎之力为什么还是学不会,最终导致从入门到放弃,不过是一瞬间,其实,入门的关键是选择对了核心要学习的知识,而不是盲目的那本书,然后,开始看天书一样的费劲破解这本书,书上的内容就像谜语一样,而你掌握的线索不足以让你识别书上的谜语,这样的结果就是你永远无法

探究:初学者编程语言的选择

| 日期 | 修改人 | 修改内容 | | | | | | 2023年2月12日 | 北极的大企鹅 |添加了C语言的新比喻 | 前景提要 很多初学者面临的最多的问题就是编程语言的选择问题,一旦你接触编程,无论任何人都会给你提到一个问题,说你要选择一门编程语言学习,才能在后续的计算机学习中取得成绩,但

探究: 编程和英语试卷的奇妙关系

* 很多时候,专业的计算机人士在讨论计算机问题的时候,总在讨论这个实现的原理是什么,这个如何实现,如何更好地实现,如果榨干计算机硬件的性能来实现某个功能活着需求,但是,对于跨学科,跨领域的问题,却很少讨论和涉及,如果你问他们,他们多半会敷衍的回答,没有这样的需求,没有这样的场景. * 其实计算机本身

探究Presto SQL引擎(4)-统计计数

本篇文章介绍了统计计数的基本原理以及Presto的实现思路,精确统计和近似统计的细节及各种优缺点,并给出了统计计数在具体业务使用的建议。

【.NET深呼吸】用代码写WPF控件模板

这一次咱们来探究一下怎么用纯代码写 WPF 模板。模板有个共同基类 FrameworkTemplate,数据模板、控件模板等是从此类派生的,因此,该类已定义了一些通用成员。 用代码构建模板,重要的成员是 VisualTree 属性,它的类型是 FrameworkElementFactory。可见,模

Clickhouse表引擎探究-ReplacingMergeTree

作者:耿宏宇 1 表引擎简述 1.1 官方描述 MergeTree 系列的引擎被设计用于插入极大量的数据到一张表当中。数据可以以数据片段的形式一个接着一个的快速写入,数据片段在后台按照一定的规则进行合并。相比在插入时不断修改(重写)已存储的数据,这种策略会高效很多。 ReplacingMergeTr