k 8 sの中のlivenseとreadinessの原理と違いを詳しく説明します.
5556 ワード
livenessとreadinessのプローブの作業方法のソースコード解析
livenseとreadinessはk 8 sのプローブとして、応用に対して健康診断を行うことができます.両者がサポートする探知方式は同じです.主な探知方式はhttp探知に対応し、命令探知を実行し、tcp探知を実行する.探測はいずれもクベルが行います.
コマンド検出を実行
http検出
tcp検出
失敗の原因を探る
コマンド検出の実行に失敗した理由は、コンテナが正常に起動されていないか、コマンドの実行に失敗したことが主です.もちろん、dockerやdocker-shimにも障害があるかもしれません.
httpとtcpはいずれもクbeletからnodeノードによって開始されたので、容器のipを検出します.そのため、検出に失敗した原因は、アプリケーション容器の問題以外に、nodeから容器ipまでのネットワークが不通だった可能性があります.
livenessとreadinessの原理の違い
探知方式が同じなら、livenseとreadinessの違いは何ですか?まず、両者が果たす役割は違っています.
readinessは主に容器が準備されているかどうかを確認します.Podの容器がすべて準備完了状態、つまりpodのconditionのReadyがtrueである場合にのみ、kubeletはこのPodが準備完了状態と認定します.podがレディ状態にあるかどうかの役割は、どのPodがserviceの後端として機能するべきかを制御することである.Podがレディ状態でない場合、それらはserviceのendpointから取り除かれる.
livenseとreadinessは最終的な役割の違い以外に、もう一つ大きな違いはそれらの初期値の違いです.
readinessの初期値は失敗です.このように、アプリケーションの起動が成功していない前に、アプリケーションにトラフィックの導入を行います.規定時間内に起動が成功したら、それを成功に設定して、流量をアプリケーションに導入します.
livenseとreadinessの2つの役割は互いに取って代わることができません.
例えば、livenseのみを配置していると、コンテナが起動し、アプリケーションが完了していない前に、その時点でpodはreadyです.流量は容器の応用に導入され、要求が失敗する可能性がある.livense検査に失敗した後、容器を再起動すると、podのreadyのconditionがfalseになります.しかし、前の方にいくつかの流量があります.エラー状態のために導入されます.
もちろんreadinessだけでは容器の再起動をトリガできません.
両者の役割は違っていますので、実際の使用では、実際の需要に応じて両者を合わせて使うことができます.
livenseとreadinessはk 8 sのプローブとして、応用に対して健康診断を行うことができます.両者がサポートする探知方式は同じです.主な探知方式はhttp探知に対応し、命令探知を実行し、tcp探知を実行する.探測はいずれもクベルが行います.
コマンド検出を実行
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
}
クベレットは、実行コマンドのログアウトコードに基づいて、検出が成功したかどうかを決定します.実行コマンドの終了コードが0の場合、実行に成功したと見なします.そうでなければ実行に失敗します.タイムアウトを実行すると、状態はアンロックです.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探査はクベルトが容器の指定を要求し、レスポンスによって判断します.戻りの状態コードが200から400(400を含まない)の間にある場合、すなわち状態コードは2 xxと3 xxであり、探知に成功したと考えられている.失敗すると思う.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はいずれもクbeletからnodeノードによって開始されたので、容器のipを検出します.そのため、検出に失敗した原因は、アプリケーション容器の問題以外に、nodeから容器ipまでのネットワークが不通だった可能性があります.
livenessとreadinessの原理の違い
探知方式が同じなら、livenseと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
}
......
livenseは主にいつ容器を再起動するかを確認するために使われます.リベンジの結果は、リベンジManagerに格納されます.kubeletは、syncPodにおいて、この容器のlivensプローブが検出に失敗した場合、起動するコンテナリストに追加し、その後の操作でこの容器を新たに作成します.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検査の結果は、SetContinerReadiness関数により、podのstatusに設定され、podのready conditionを更新します.livenseと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
}
リベンジの初期値は成功です.このように応用が成功していない前に、誤殺されることを防止します.規定時間内に起動に失敗した場合は、容器の再構築をトリガします.readinessの初期値は失敗です.このように、アプリケーションの起動が成功していない前に、アプリケーションにトラフィックの導入を行います.規定時間内に起動が成功したら、それを成功に設定して、流量をアプリケーションに導入します.
livenseとreadinessの2つの役割は互いに取って代わることができません.
例えば、livenseのみを配置していると、コンテナが起動し、アプリケーションが完了していない前に、その時点でpodはreadyです.流量は容器の応用に導入され、要求が失敗する可能性がある.livense検査に失敗した後、容器を再起動すると、podのreadyのconditionがfalseになります.しかし、前の方にいくつかの流量があります.エラー状態のために導入されます.
もちろんreadinessだけでは容器の再起動をトリガできません.
両者の役割は違っていますので、実際の使用では、実際の需要に応じて両者を合わせて使うことができます.