详解Kubernetes中的Liveness和Readiness的原理和区别

标签: kubernetes liveness readiness | 发表时间:2020-03-20 23:54 | 作者:大卫
出处:http://weekly.dockone.io

Liveness与Readiness的探针工作方式源码解析

Liveness和Readiness作为Kubernetes的探针,可以对应用进行健康探测。

二者支持的探测方式相同。主要的探测方式支持http探测,执行命令探测,以及TCP探测。

探测均是由kubelet执行。

执行命令探测

func (pb *prober) runProbe(p *v1.Probe, pod *v1.Pod, status v1.PodStatus, container v1.Container, containerID kubecontainer.ContainerID) (probe.Result, string, error) {  
.....        
    command := kubecontainer.ExpandContainerCommandOnlyStatic(p.Exec.Command, container.Env)
    return pb.exec.Probe(pb.newExecInContainer(container, containerID, command, timeout))
......

func (pb *prober) newExecInContainer(container v1.Container, containerID kubecontainer.ContainerID, cmd []string, timeout time.Duration) exec.Cmd {
return execInContainer{func() ([]byte, error) {
    return pb.runner.RunInContainer(containerID, cmd, timeout)
}}
}

......
func (m *kubeGenericRuntimeManager) RunInContainer(id kubecontainer.ContainerID, cmd []string, timeout time.Duration) ([]byte, error) {
stdout, stderr, err := m.runtimeService.ExecSync(id.ID, cmd, 0)
return append(stdout, stderr...), err


由kubelet,通过CRI接口的ExecSync接口,在对应容器内执行拼装好的CMD命令。获取返回值。
func (pr execProber) Probe(e exec.Cmd) (probe.Result, string, error) {  
data, err := e.CombinedOutput()
glog.V(4).Infof("Exec probe response: %q", string(data))
if err != nil {
    exit, ok := err.(exec.ExitError)
    if ok {
        if exit.ExitStatus() == 0 {
            return probe.Success, string(data), nil
        } else {
            return probe.Failure, string(data), nil
        }
    }
    return probe.Unknown, "", err
}
return probe.Success, string(data), nil


kubelet是根据执行命令的退出码来决定是否探测成功。当执行命令的退出码为0时,认为执行成功,否则为执行失败。如果执行超时,则状态为Unknown。

HTTP探测

func DoHTTPProbe(url *url.URL, headers http.Header, client HTTPGetInterface) (probe.Result, string, error) {  
req, err := http.NewRequest("GET", url.String(), nil)
......
if res.StatusCode >= http.StatusOK && res.StatusCode < http.StatusBadRequest {
    glog.V(4).Infof("Probe succeeded for %s, Response: %v", url.String(), *res)
    return probe.Success, body, nil
}
......

HTTP探测是通过kubelet请求容器的指定url,并根据response来进行判断。

当返回的状态码在200到400(不含400)之间时,也就是状态码为2xx和3xx是,认为探测成功。否则认为失败。

TCP探测

func DoTCPProbe(addr string, timeout time.Duration) (probe.Result, string, error) {  
conn, err := net.DialTimeout("tcp", addr, timeout)
if err != nil {
    // Convert errors to failures to handle timeouts.
    return probe.Failure, err.Error(), nil
}
err = conn.Close()
if err != nil {
    glog.Errorf("Unexpected error closing TCP probe socket: %v (%#v)", err, err)
}
return probe.Success, "", nil


TCP探测是通过探测指定的端口。如果可以连接,则认为探测成功,否则认为失败。

探测失败的可能原因

执行命令探测失败的原因主要可能是容器未成功启动,或者执行命令失败。当然也可能Docker或者docker-shim存在故障。

由于HTTP和TCP都是从kubelet自Node节点上发起的,向容器的IP进行探测。

所以探测失败的原因除了应用容器的问题外,还可能是从Node到容器IP的网络不通。

Liveness与Readiness的原理区别

探测方式相同,那么Liveness与Readiness有什么区别?首先,二者能够起到的作用不同。
func (m *kubeGenericRuntimeManager) computePodContainerChanges(pod *v1.Pod, podStatus *kubecontainer.PodStatus) podContainerSpecChanges {  
    ......
    liveness, found := m.livenessManager.Get(containerStatus.ID)
    if !found || liveness == proberesults.Success {
        changes.ContainersToKeep[containerStatus.ID] = index
        continue
    }
    ......

Liveness主要用来确定何时重启容器。Liveness探测的结果会存储在LivenessManager中。

kubelet在syncPod时,发现该容器的Liveness探针检测失败时,会将其加入待启动的容器列表中,在之后的操作中会重新创建该容器。

Readiness主要来确定容器是否已经就绪。只有当Pod中的容器都处于就绪状态,也就是pod的condition里的Ready为true时,kubelet才会认定该Pod处于就绪状态。而Pod是否处于就绪状态的作用是控制哪些Pod应该作为Service的后端。如果Pod处于非就绪状态,那么它们将会被从Service的Endpoint中移除。
func (m *manager) SetContainerReadiness(podUID types.UID, containerID kubecontainer.ContainerID, ready bool) {  
    ......
    containerStatus.Ready = ready
    ......
    readyCondition := GeneratePodReadyCondition(&pod.Spec, status.ContainerStatuses, status.Phase)
    ......
    m.updateStatusInternal(pod, status, false)


Readiness检查结果会通过SetContainerReadiness函数,设置到Pod的status中,从而更新Pod的ready condition。

Liveness和Readiness除了最终的作用不同,另外一个很大的区别是它们的初始值不同。
switch probeType {  
case readiness:
    w.spec = container.ReadinessProbe
    w.resultsManager = m.readinessManager
    w.initialValue = results.Failure
case liveness:
    w.spec = container.LivenessProbe
    w.resultsManager = m.livenessManager
    w.initialValue = results.Success


Liveness的初始值为成功。这样防止在应用还没有成功启动前,就被误杀。如果在规定时间内还未成功启动,才将其设置为失败,从而触发容器重建。

而Readiness的初始值为失败。这样防止应用还没有成功启动前就向应用进行流量的导入。如果在规定时间内启动成功,才将其设置为成功,从而将流量向应用导入。

Liveness与Readiness二者作用不能相互替代。

例如只配置了Liveness,那么在容器启动,应用还没有成功就绪之前,这个时候Pod是ready的(因为容器成功启动了)。那么流量就会被引入到容器的应用中,可能会导致请求失败。虽然在Liveness检查失败后,重启容器,此时Pod的ready的condition会变为false。但是前面会有一些流量因为错误状态导入。

当然只配置了Readiness是无法触发容器重启的。

因为二者的作用不同,在实际使用中,可以根据实际的需求将二者进行配合使用。

原文链接: https://www.cnblogs.com/xuxinkun/p/11785521.html

相关 [kubernetes liveness readiness] 推荐:

详解Kubernetes中的Liveness和Readiness的原理和区别

- - DockOne.io
Liveness与Readiness的探针工作方式源码解析. Liveness和Readiness作为Kubernetes的探针,可以对应用进行健康探测. 主要的探测方式支持http探测,执行命令探测,以及TCP探测. 由kubelet,通过CRI接口的ExecSync接口,在对应容器内执行拼装好的CMD命令.

Kubernetes & Microservice

- - 午夜咖啡
这是前一段时间在一个微服务的 meetup 上的分享,整理成文章发布出来. 谈微服务之前,先澄清一下概念. 微服务这个词的准确定义很难,不同的人有不同的人的看法. 比如一个朋友是『微服务原教旨主义者』,坚持微服务一定是无状态的 http API 服务,其他的都是『邪魔歪道』,它和 SOA,RPC,分布式系统之间有明显的分界.

Kubernetes 完全教程

- - 午夜咖啡
经过一个阶段的准备,视频版本的 《Kubernetes 完全教程》出炉了. 课程一共分为七节,另外有一节 Docker 预备课,每节课大约一个多小时. 目标是让从没接触过 Kubernetes 的同学也能通过这个课程掌握 Kubernetes. 为什么要学习 Kubernetes. 在介绍课程之前,先说说为什么要学习 Kubernetes 以及什么人需要学习 Kubernetes.

喜大普奔:Spark on kubernetes

- - Zlatan Eevee
两个星期前(08/15/2017),spark社区提了一个新的SPIP(Spark Project Improvement Proposals): Spark on Kubernetes: Kubernetes as A Native Cluster Manager,即用k8s管理spark集群. 经过社区2个星期的投票,看上去很快要能合入了.

Kubernetes 日志收集方案

- - IT瘾-dev
Kubernetes 中的基本日志. Kubernetes 日志收集. 以 sidecar 容器收集日志. 用 sidecar 容器重新输出日志. 使用 sidecar 运行日志采集 agent. 前面的课程中和大家一起学习了 Kubernetes 集群中监控系统的搭建,除了对集群的监控报警之外,还有一项运维工作是非常重要的,那就是日志的收集.

Kubernetes 会不会“杀死” DevOps?

- - InfoQ推荐
DevOps 这个概念最早是在 2007 年提出的,那时云计算基础设施的概念也才刚刚提出没多久,而随着互联网的逐渐普及,应用软件的需求爆发式增长,软件开发的理念也逐渐从瀑布模型(waterfall)转向敏捷开发(agile). 传统的软件交付模式(应用开发人员专注于软件开发、IT 运维人员负责将软件部署到服务器运行),再也无法满足互联网软件快速迭代的需求.

轻量级Kubernetes k3s初探

- - InfoQ推荐
1 k3s简介–5 less than K8s. k3s [1] 是rancher®开源的一个Kubernetes发行版,从名字上就可以看出k3s相对k8s做了很多裁剪和优化,二进制程序不足50MB,占用资源更少,只需要512MB内存即可运行. 而之所以称为k3s是因为相对k8s裁剪了如下5个部分:.

kubernetes dashboard向外网提供服务

- - 学习日志
目前新版本的 kubernetes dashboard ( https://github.com/kubernetes/dashboard)安装了后,为了安全起见,默认情况下已经不向外提供服务,只能通过. http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/ 本机访问.

如何进行kubernetes问题的排障

- - Xinkun Blog
k8s的成熟度很高,伴随着整个项目的扩增,以及新功能和新流程的不断引入,也伴随这产生了一些问题. 虽然自动化测试可以排除掉大部分,但是一些复杂流程以及极端情况却很难做到bug的完全覆盖. 因此在实际的工作过程中,需要对运行的集群进行故障定位和解决. 当然,进行排障的前提是对于k8s的流程和概念进行掌握,对于源码有一定的掌握能力,才可以更好的进行.

Kubernetes 基础概念知多少

- - IT瘾-dev
kubernetes(简称k8s)是一种用于在一组主机上运行和协同容器化应用程序的管理平台,皆在提供高可用、高扩展性和可预测性的方式来管理容器应用的生命周期. 通过k8s,用户可以定义程序运行方式、部署升级策略、动态伸缩容,使得用户以一种更灵活可靠的方式来管理应用程序. 关于k8s,是一种对应用服务的打包、部署、监控等一整套生命周期的自动化管理平台,目前各大公司已在生产环境部署使用,同时k8s社区比较活跃,在未来一段时间内会越来越流行,可以说是以后服务部署的事实标准,对于Java开发者来说,你可以不直接使用它,但是不能不了解它.