探究kubernetes 探针参数periodSeconds和timeoutSeconds

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 探究kubernetes 探针参数periodSeconds和timeoutSeconds

问题起源

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
  }
  ...
}
  1. 下面的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)
  ...
}
  1. 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)
    ...
  }
  ...
}
  1. 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;
相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
4月前
|
Prometheus Kubernetes 监控
容器服务ACK常见问题之pod设置securityContext调整参数失败如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
4月前
|
Kubernetes 调度 容器
K8S 性能优化 -K8S Node 参数调优
K8S 性能优化 -K8S Node 参数调优
|
4月前
|
运维 Kubernetes Cloud Native
k8s学习-Pod(生命周期、探针、模板、创建、删除等)
k8s学习-Pod(生命周期、探针、模板、创建、删除等)
98 0
|
27天前
|
Kubernetes 负载均衡 网络协议
在K8S中,Pod的探针有哪些及用途?
在K8S中,Pod的探针有哪些及用途?
|
1月前
|
Kubernetes 网络协议 Python
运维开发.Kubernetes探针与应用
运维开发.Kubernetes探针与应用
72 2
|
27天前
|
Kubernetes 监控 网络协议
在K8S中,Pod有几种探针?
在K8S中,Pod有几种探针?
|
1月前
|
Kubernetes 网络协议 容器
在k8S中,Pod中的LivenessProbe探针常见方式有哪些?
在k8S中,Pod中的LivenessProbe探针常见方式有哪些?
|
1月前
|
Kubernetes 监控 网络协议
在K8S中,Pod不同探针有何区别?
在K8S中,Pod不同探针有何区别?
|
4月前
|
运维 Kubernetes 网络协议
Kubernetes详解(十八)——Pod就绪性探针实战
Kubernetes详解(十八)——Pod就绪性探针实战
99 5
|
4月前
|
Kubernetes 网络协议 应用服务中间件
Kubernetes详解(十七)——Pod存活性探针应用实战
Kubernetes详解(十七)——Pod存活性探针应用实战
89 4