乐趣区

关于Kubernetes探针第一次探测的问题

关于 k8s 的两种探针,想必大家都参考过(https://kubernetes.io/docs/ta…),根据上面的解释,k8s 的这两种探针都有 initialDelaySeconds 属性,它的作用是决定 container 启动后进行第一次探测的时间,由于服务启动是需要时间的,如果这个属性设置不好,则这个服务的状态很可能就是错误的,设置时间太短可能导致探针多次探测失败从而使服务失效,设置时间太长,则 k8s 要花很长时间才认为服务进入“ready”状态。因此,设置 initialDelaySeconds 必须慎之又慎,同时我们还经常让 periodSecondsfailureThreshold配合其使用,例如:

readinessProbe:
  exec:
    command:
    - cat
    - /tmp/healthy
  initialDelaySeconds: 5
  periodSeconds: 5
  failureThreshold: 3

上面的配置好理解,探针在容器启动 5s 后开始探测,并且之后每 5s 检测一次,如果检测失败的次数大于 3,则放弃,认为服务“Unready”(对于 liveness 探针,则会在放弃后重新启动 pod)。
这个配置在 periodSeconds 较小时,是比较符合预期的,但是当你将 periodSeconds 配置较大数值时,会发现,初次探针探测的时间也变长了,不是原有的 5s,很有可能几分钟之后才进行第一次探测,这对于有的服务来说是不可接受的:明明我几秒就启动成功了,可以提供服务了,为什么 k8s 要几分钟后才认为我 ready 呢?有关这个问题的讨论,可以参考 https://github.com/kubernetes…,最终通过查看 k8s 源码(https://github.com/kubernetes…),你会发现下面这段代码:

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

    // If kubelet restarted the probes could be started in rapid succession.
    // Let the worker wait for a random portion of tickerPeriod before probing.
    time.Sleep(time.Duration(rand.Float64() * float64(probeTickerPeriod)))

    probeTicker := time.NewTicker(probeTickerPeriod)

    defer func() {
        // Clean up.
        probeTicker.Stop()
        if !w.containerID.IsEmpty() {w.resultsManager.Remove(w.containerID)
        }

        w.probeManager.removeWorker(w.pod.UID, w.container.Name, w.probeType)
        ProberResults.Delete(w.proberResultsMetricLabels)
    }()

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

请特别注意 time.Sleep() 那段,正是由于那段代码,第一次探针进行探测的时间是 initialDelaySeconds + random(periodSeconds),因此periodSeconds 的值设得越大,探针第一次探测的时间就越长,服务处于“unready”的状态就越长,如果你要一次性重新部署多个服务,并且依赖于其他服务的话,这一个看似小小的隐患很有可能造成一连串所依赖的服务探针检测失败(因为有的探针是要对其他服务做 healthcheck,其他服务由于重新部署,导致 k8s 第一次去检测状态是否 ready 的时间拖延太久,而此期间服务可能早已经 ready,但 k8s 由于还没进行第一次检测,所以认为服务“unready”,引起其他探针探测失败),从而引发整个服务不可用,因此,这点大家在配置时要特别注意。

退出移动版