Podにおけるコンテナ再起動プロセス
5144 ワード
背景
テストの場合、通常はPodのcontainerを頻繁に殺し、再起動する必要があります.この過程でPodの状態がCrashLoopBackOffになることが多く、containerが再起動する時間が長くなります.
ぶんせき
containerが頻繁にrestartを回避するために、k 8 sはcontainer restartプロセスを制限し、back-offを使用する方法で、公式ドキュメントでは次のように説明されています.
Failed containers that are restarted by Kubelet, are restarted with an exponential back-off delay, the delay is in multiples of sync-frequency 0, 1x, 2x, 4x, 8x … capped at 5 minutes and is reset after 10 minutes of successful execution.
containerが頻繁にrestartを回避するために、k 8 sはcontainer restartプロセスを制限し、back-offを使用する方法で、公式ドキュメントでは次のように説明されています.
Failed containers that are restarted by Kubelet, are restarted with an exponential back-off delay, the delay is in multiples of sync-frequency 0, 1x, 2x, 4x, 8x … capped at 5 minutes and is reset after 10 minutes of successful execution.
ここではまず直接結論を出します.
SyncPod()
を実行する場合)、Podは自身のStatus構造を通じて現在のこのcontainer(Podに複数のcontainerがある可能性があるため)が前回終了した時間をts now() - ts < backoff
の場合、待ち時間が足りないことを示し、CrashLoopBackOff Event(次のSyncPod
のサイクルが来るまで待って、この値を再比較)4 . ステップ3でbackoffを計算する過程で、前回containerが終了したときの現在の時間距離の間隔もチェックし、
2 * MaxContainerBackOff = 10 minutes
より大きい場合、このcontainerに対応するbackoffを初期値10 sにリセットするソースの詳細
1. kubernetes/pkg/kubelet/kubelet.go
ソースコードにより、
kubernetes/pkg/kubelet/kubelet.go
ファイルには2つの定数があることがわかりました.MaxContainerBackOff = 300 * time.Second
backOffPeriod = time.Second * 10
この2つの変数を使用してBackOffオブジェクトを構築しました.これはkubeletのプロパティで、node上のすべてのpodに適用されます.
klet.backOff = flowcontrol.NewBackOff(backOffPeriod, MaxContainerBackOff)
BackOff構造は次のとおりです.
type Backoff struct {
sync.Mutex
Clock clock.Clock
defaultDuration time.Duration
maxDuration time.Duration
perItemBackoff map[string]*backoffEntry
}
そしてSyncPodメソッドでこのオブジェクトを使用します
// Call the container runtime's SyncPod callback
result := kl.containerRuntime.SyncPod(pod, apiPodStatus, podStatus, pullSecrets, kl.backOff)
2. kubernetes/pkg/kubelet/kuberuntime/kuberuntime_manager.go
SyncPodが具体的にやっていることは次のとおりです.
// SyncPod syncs the running pod into the desired pod by executing following steps:
//
// 1. Compute sandbox and container changes.
// 2. Kill pod sandbox if necessary.
// 3. Kill any containers that should not be running.
// 4. Create sandbox if necessary.
// 5. Create init containers.
// 6. Create normal containers.
func (m *kubeGenericRuntimeManager) SyncPod(pod *v1.Pod, _ v1.PodStatus, podStatus *kubecontainer.PodStatus, pullSecrets []v1.Secret, backOff *flowcontrol.Backoff) (result kubecontainer.PodSyncResult) {
同じようにこのファイルには、重要な関数があります.
// If a container is still in backoff, the function will return a brief backoff error and
// a detailed error message.
func (m *kubeGenericRuntimeManager) doBackOff(pod *v1.Pod, container *v1.Container, podStatus *kubecontainer.PodStatus, backOff *flowcontrol.Backoff) (bool, string, error) {
var cStatus *kubecontainer.ContainerStatus
for _, c := range podStatus.ContainerStatuses {
if c.Name == container.Name && c.State == kubecontainer.ContainerStateExited {
cStatus = c
break
}
}
if cStatus == nil {
return false, "", nil
}
glog.Infof("checking backoff for container %q in pod %q", container.Name, format.Pod(pod))
// Use the finished time of the latest exited container as the start point to calculate whether to do back-off.
ts := cStatus.FinishedAt
// backOff requires a unique key to identify the container.
key := getStableKey(pod, container)
if backOff.IsInBackOffSince(key, ts) {
if ref, err := kubecontainer.GenerateContainerRef(pod, container); err == nil {
m.recorder.Eventf(ref, v1.EventTypeWarning, events.BackOffStartContainer, "Back-off restarting failed container")
}
err := fmt.Errorf("Back-off %s restarting failed container=%s pod=%s", backOff.Get(key), container.Name, format.Pod(pod))
glog.Infof("%s", err.Error())
return true, err.Error(), kubecontainer.ErrCrashLoopBackOff
}
backOff.Next(key, ts)
return false, "", nil
}
ここでbackOff.次のように定義します.
// move backoff to the next mark, capping at maxDuration
func (p *Backoff) Next(id string, eventTime time.Time) {
p.Lock()
defer p.Unlock()
entry, ok := p.perItemBackoff[id]
if !ok || hasExpired(eventTime, entry.lastUpdate, p.maxDuration) {
entry = p.initEntryUnsafe(id)
} else {
delay := entry.backoff * 2 // exponential
entry.backoff = time.Duration(integer.Int64Min(int64(delay), int64(p.maxDuration)))
}
entry.lastUpdate = p.Clock.Now()
}