关于k8s的两种探针,想必大家都参考过(https://kubernetes.io/docs/ta...),根据上面的解释,k8s的这两种探针都有initialDelaySeconds
属性,它的作用是决定container启动后进行第一次探测的时间,由于服务启动是需要时间的,如果这个属性设置不好,则这个服务的状态很可能就是错误的,设置时间太短可能导致探针多次探测失败从而使服务失效,设置时间太长,则k8s要花很长时间才认为服务进入“ready”状态。因此,设置initialDelaySeconds
必须慎之又慎,同时我们还经常让periodSeconds
和failureThreshold
配合其使用,例如:
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”,引起其他探针探测失败),从而引发整个服务不可用,因此,这点大家在配置时要特别注意。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。