详解k8s中的liveness和readiness的道理和区分
2019-11-18杂谈搜奇网39°c
A+ A-liveness与readiness的探针工作体式格局源码剖析
liveness和readiness作为k8s的探针,可以对运用举行康健探测。
两者支撑的探测体式格局雷同。重要的探测体式格局支撑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是没法触发容器重启的。
由于两者的作用差别,在现实运用中,可以依据现实的需求将两者举行合营运用。