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

栏目: IT技术 · 发布时间: 4年前

内容简介:Liveness和Readiness作为Kubernetes的探针,可以对应用进行健康探测。二者支持的探测方式相同。主要的探测方式支持http探测,执行命令探测,以及TCP探测。探测均是由kubelet执行。

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


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

转型之战

转型之战

吴晓波 / 2015-7-1

互联网时代大潮席卷而来,互联网究竟是“魔法手杖”,还是“效率金箍棒”?传统企业如何正确借助和利用互联网思维帮助自身转变思维、完成企业转型升级?本书分两篇,上篇为传统行业互联网转型极具代表性和借鉴意义的案例,下篇精选吴晓波转型大课的独 家内容,梳理了吴晓波、刘伟、刘润、金霞、刘博、赵峰、张蕴蓝、张荣耀、李嘉聪、曾玉波等各行业10位导师关于互联网思维的精华理念和观点,其中囊括各传统行业互联网转型成功的......一起来看看 《转型之战》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具