1. 程式人生 > 其它 >kubelet監控靜態Pod

kubelet監控靜態Pod

獲取靜態Pod路徑

靜態Pod路徑預設是空。

當靜態Pod路徑是空時,路徑會被設定成/etc/kubernetes/manifests。

檢測週期

/var/lib/kubelet/config.yaml配置了FileCheckFrequency值是20s即List的間隔週期是20s。

List和Watch流程

doWatch函式的重試回退流程

主流程

pkg/kubelet/config/file_linux.go
startWatch函式

如果watch失敗,那麼看錯誤是否支援重試。
1.    支援重試,繼續watch。
2.    不支援重試,進入回退流程。
建立Backoff物件後,每隔1s呼叫doWatch函式(如果處於回退流程中,那麼需要等待,不會呼叫doWatch函式)。

const (
   // 回退最小時間 
   retryPeriod    = 1 * time.Second 
   // 回退最大時間
   maxRetryPeriod = 20 * time.Second 
)

func (s *sourceFile) startWatch() {
   // 建立Backoff物件 
   backOff := flowcontrol.NewBackOff(retryPeriod, maxRetryPeriod)
   backOffId := "watch"

   go wait.Forever(func() {
      if backOff.IsInBackOffSinceUpdate(backOffId, time.Now()) {
         return
      }

      if err := s.doWatch(); err != nil {
         klog.Errorf("Unable to read config path %q: %v", s.path, err)
         if _, retryable := err.(*retryableError); !retryable {
            backOff.Next(backOffId, time.Now())
         }
      }
   }, retryPeriod)
}

建立Backoff物件

staging/src/k8s.io/client-go/util/flowcontrol/backoff.go
NewBackOff函式

type Duration int64

type Backoff struct {
   sync.Mutex
   Clock           clock.Clock
   defaultDuration time.Duration
   maxDuration     time.Duration
   perItemBackoff  map[string]*backoffEntry
}

type backoffEntry struct {
   // 回退間隔時間 
   backoff    time.Duration
   // 回退開始時間
   lastUpdate time.Time 
}

type RealClock struct{}

// 引數值分別是1s和20s
func NewBackOff(initial, max time.Duration) *Backoff {
   return &Backoff{
      perItemBackoff:  map[string]*backoffEntry{},
      Clock:           clock.RealClock{},
      defaultDuration: initial,
      maxDuration:     max,
   }
}

判斷是否在回退流程中

staging/src/k8s.io/client-go/util/flowcontrol/backoff.go
IsInBackOffSinceUpdate函式

如果函式返回false,那麼說明還在回退流程中;否則,說明回退流程已經結束。

1.    加鎖。
2.    獲取map裡面key是“watch”對應的value,即backoffEntry。
3.    如果沒有該key,那麼返回false。
4.    如果當前時間與回退開始時間差值>2倍maxDuration,那麼返回false。(此步多餘,第5步已經覆蓋了,2倍maxDuration>backoff)
5.    如果當前時間與回退開始時間差值<回退間隔時間,那麼返回false;否則,返回true。
6.    釋放鎖。

func (p *Backoff) IsInBackOffSinceUpdate(id string, eventTime time.Time) bool {
   p.Lock()
   defer p.Unlock()
   entry, ok := p.perItemBackoff[id]
   if !ok {
      return false
   }
   if hasExpired(eventTime, entry.lastUpdate, p.maxDuration) {
      return false
   }
   return eventTime.Sub(entry.lastUpdate) < entry.backoff
}

插入或更新回退間隔時間、更新回退開始時間

staging/src/k8s.io/client-go/util/flowcontrol/backoff.go
Next函式

1.    加鎖。
2.    獲取map裡面key是“watch”對應的value,即backoffEntry。
3.    如果沒有該key或者當前時間與回退開始時間差值>2倍maxDuration,那麼初始化(插入key-“watch”對應的backoffEntry);否則,backoffEntry的回退間隔時間backoff翻倍,最大值是maxDuration即20s。
4.    更新backoffEntry裡面的lastUpdate即回退開始時間。
5.    釋放鎖。

// 當前時間與回退開始時間差值最大是2倍maxDuration。
func hasExpired(eventTime time.Time, lastUpdate time.Time, maxDuration time.Duration) bool {
   return eventTime.Sub(lastUpdate) > maxDuration*2
}

func (p *Backoff) initEntryUnsafe(id string) *backoffEntry {
   // 起始回退間隔時間是1s。 
   entry := &backoffEntry{backoff: p.defaultDuration}
   p.perItemBackoff[id] = entry
   return entry
}

func (p *Backoff) Next(id string, eventTime time.Time) {
   p.Lock()
   defer p.Unlock()
   entry, ok := p.perItemBackoff[id]
   // 只有第一次回退或者當前時間與回退開始時間差值超過2倍maxDuration即40s,才會把回退間隔時間重置成1s。
   if !ok || hasExpired(eventTime, entry.lastUpdate, p.maxDuration) {
      entry = p.initEntryUnsafe(id)
   } else {
      delay := entry.backoff * 2 // exponential
      // 確保回退間隔時間最大是20s。
      entry.backoff = time.Duration(integer.Int64Min(int64(delay), int64(p.maxDuration)))
   }
   entry.lastUpdate = p.Clock.Now()
}

回退間隔時間的變化(不是單調遞增,而是先增後保持不變)

1s

2s

4s

8s

16s

20s

...

20s

一開始,呈現2的指數級變化,直到16s。最後,一直20s。
除非當前時間與回退開始時間差值超過2倍maxDuration即40s,從而重置回退間隔時間為1s。

自己動手寫Demo

編譯並執行二進位制檔案

cd kubelet-monitor-manifests-demo
go build main.go
./main

測試資料

/root/test目錄下放入a.log和b.log,內容分別如下:

$ cat a.log
{"Namespace":"Bett", "Name":"McLaugh", "Desc":"beijing"}
$ cat b.log
{"Namespace":"abc", "Name":"McLaugh", "Desc":"xxx"}

效果

流程圖

快取1的全量資料是最新的,快取2的全量資料是舊的。
快取1和快取2對比方式:
遍歷快取1中所有的key,如果快取1中的key在快取2中沒有,那麼說明該info需要增加;如果快取1中的key在快取2中有而且value發生了變化,那麼該info需要更新。
遍歷快取2中所有的key,如果快取2中的key在快取1中沒有,那麼說明該info需要刪除。
把變化的資訊傳送到緩衝通道,交給資料處理中心。