豆荚中容器重启流程

  

背景

  

测试的时候,通常需要将豆荚中容器的频繁地杀死,重启。在这个过程中,Pod的状态经常会出现CrashLoopBackOff,而且容器重启的时间越来越长。

  

分析

  

为了避免集装箱频繁地重启,k8对容器重启过程做了限制,使用退下的方法,官方文档中的说法是:

  

容器由Kubelet重启失败,重新启动了一个指数退下延迟,延迟的倍数sync-frequency 0, 1, 2 x, 4 x 8 x…限制在5分钟,10分钟后重置成功执行。

  
      <李> https://kubernetes - v1 - 4. github.io/docs/user guide/pod states/李   
  

这里先直接给出结论:

  
      <李>在豆荚中重启容器的时候(具体时机是,周期性执行SyncPod()的时候),豆荚会通过自身的状态结构找到当前这个容器(因为豆荚中可能有多个容器)上一次退出的时间,记为ts李   <李>如果是第一次重启,那么直接重启容器,并且在Kubelet的补偿。perItemBackoff(一个地图结构,关键是根据集装箱和所在pod对象计算出来的id)中记录下次倒扣的时间(初始值为10,然后按照指数增长,最大5分钟)   <李>如果不是第一次重启,即Kubelet的补偿。perItemBackoff中已经有这个容器的倒扣记录,计为倒扣,那么   
        <李>如果现在()- ts & lt;倒扣,表明等待的时间还不够,抛出CrashLoopBackOff事件(然后等到下一个SyncPod的周期到的时候,重新比较这个值)   <李>否则说,明已经等待倒扣时间了,可以重启了,此时执行backOff.Next(),将该容器对应的倒扣翻倍,然后执行重启操作李   李
      <李>在步骤3中计算倒扣的过程中,还会去检查当前时间距离上一次容器退出时的间隔,如果大于2 * MaxContainerBackOff=10分钟,那么会将这个容器对应的倒扣重置为初始值10 s   
  

源码细节

  
      <李>   

    kubernetes/pkg/kubelet kubelet.go
    通过源码发现,kubernetes/pkg/kubelet/kubelet。去文件中有两个常量:

      
     <代码> MaxContainerBackOff=300 * time.Second
      backOffPeriod=5诙? 10  
      李   
  

使用这两个变量构造了一个倒扣对象,这个是kubelet的属性,对该节点上所有豆荚都适用

  
 <代码> klet。倒扣=flowcontrol。NewBackOff (backOffPeriod MaxContainerBackOff)  
  

倒扣结构如下

  
 <代码>类型倒扣结构{
  sync.Mutex
  时钟clock.Clock
  defaultDuration time.Duration
  maxDuration time.Duration
  perItemBackoff map [string] * backoffEntry
  } 
  

然后在SyncPod方法中使用这个对象

  
 <代码>//调用容器运行时的SyncPod回调
  结果:=kl.containerRuntime。SyncPod (pod、apiPodStatus podStatus、pullSecrets kl.backOff)  
     <李> kubernetes/pkg/kubelet/kuberuntime/kuberuntime_manager.go李      

SyncPod具体做的事有:

  
 <代码>//SyncPod同步运行舱所需的pod通过执行以下步骤:////1。计算沙箱和容器的变化。//2。必要时杀了pod沙箱。//3。杀死任何不应该运行的容器。//4。在必要时创建沙箱。//5。创建初始化容器。//6。建立正常的容器。
  func (m * kubeGenericRuntimeManager) SyncPod (pod * v1。豆荚,_ v1。PodStatus PodStatus * kubecontainer。PodStatus, pullSecrets [] v1。秘密,倒扣* flowcontrol.Backoff)(结果kubecontainer.PodSyncResult){ 
  

同样在这个文件中,有一个关键的函数

  
 <代码>//如果一个容器仍在倒扣,函数将返回一个简短的错误和补偿//详细的错误消息。
  func (m * kubeGenericRuntimeManager) doBackOff (pod * v1。豆荚,容器* v1。容器,podStatus * kubecontainer。PodStatus,倒扣* flowcontrol.Backoff) (bool、字符串错误){
  var cStatus * kubecontainer.ContainerStatus
  _,c:=podStatus范围。ContainerStatuses {
  如果c。名字==容器。的名字,,c。==kubecontainer状态。ContainerStateExited {
  cStatus=c
  打破
  }
  }
  
  如果cStatus==nil {
  返回false”、“零
  }
  
  蒟蒻阁。Infof(“检查为容器倒扣在豆荚% % q q ",容器。名字,format.Pod (pod))//使用最新的完成时间退出容器为起点计算是否退下。
  ts:=cStatus.FinishedAt//确定容器倒扣需要一个独特的关键。
  关键:=getStableKey (pod、容器)
  如果补偿。IsInBackOffSince(关键、ts) {
  如果裁判,犯错:=kubecontainer。GenerateContainerRef (pod、容器);呃==nil {
  m.recorder。Eventf (ref, v1。EventTypeWarning,事件。BackOffStartContainer”,关闭后重新启动失败的容器”)
  }
  错:=fmt。Errorf(“退下% s重新启动失败的容器=% s pod=% s”, backOff.Get(关键),容器。名字,format.Pod (pod))
  蒟蒻阁。Infof (“% s”, err.Error ())
  kubecontainer.ErrCrashLoopBackOff返回true, err.Error ()
  }
  
  倒扣。下一个(键,ts)
  返回false”、“零
  }

豆荚中容器重启流程