Kubelet 源碼走讀(1)

源碼版本 v1.3.0-alpha.5


1.3.0 版本相對1.2.4版本最明顯的區別的是將各k8s 部件的二進制可執行文件合到一個文件hyperkube中。通過命令行參數,啓動不同的k8s部件。

這裏按照代碼執行順序簡單的走讀kubelet源碼。

程序入口: cmd/kubelet/kubelet.go 文件中main()  函數實例化NewKubeletServer,命令行參數處理,日誌初始化,調用cmd/kubelet/app/server.go文件中Run函數。(如果使用hyperkube啓動入口也在這)

func run(s *options.KubeletServer, kcfg *KubeletConfig) (errerror). 

在run函數中主要做的事是:

kcfg.KubeClient, err = clientset.NewForConfig(clientConfig)//創建API 客戶端

cloud, err :=cloudprovider.InitCloudProvider(s.CloudProvider, s.CloudConfigFile)//雲provider初始化,一般本地執行不涉及雲

kcfg.CAdvisorInterface, err = cadvisor.New(s.CAdvisorPort,kcfg.ContainerRuntime)

kcfg.ContainerManager, err =cm.NewContainerManager(kcfg.Mounter, kcfg.CAdvisorInterface,cm.NodeConfig{  //容器管理器

RunKubelet(kcfg)  //運行kubket

http.ListenAndServe(net.JoinHostPort(s.HealthzBindAddress,strconv.Itoa(int(s.HealthzPort))), nil)//啓動health web服務

 

對於RunKubelet(kcfg),主要完成:

eventBroadcaster := record.NewBroadcaster() 
kcfg.Recorder = eventBroadcaster.NewRecorder(api.EventSource{Component:"kubelet", Host: kcfg.NodeName}) 

builder := kcfg.Builder
if builder == nil {
   builder = CreateAndInitKubelet
}
if kcfg.OSInterface == nil {
   kcfg.OSInterface =kubecontainer.RealOS{}
}
k, podCfg, err := builder(kcfg)

 

其中CreateAndInitKubelet調用makePodSourceConfig,makePodSourceConfig主要設置pod信息的來源,pod信息可以來源ConfigFile,ManifestURL,KubeClient。一般默認信息來源是通過KubeClient定時輪詢kubernets Apiserver 獲取,獲取信息發送至通道里。(早期版本通過watchetcd 獲取,後來因爲安全問題,變爲api輪詢)。

在pkg\kubelets\config\apiserver.go中

func newSourceApiserverFromLW(lw cache.ListerWatcher,updates chan<- interface{}) {
   send := func(objs []interface{}) {
      var pods []*api.Pod
      for _, o := range objs {
         pods = append(pods,o.(*api.Pod))
      }
      updates <-kubetypes.PodUpdate{Pods: pods, Op: kubetypes.SET, Source:kubetypes.ApiserverSource}  //將pod更新信息發送至updates channel。kebelet
 會處理來自updates channel的更新

   }
   cache.NewReflector(lw, &api.Pod{},cache.NewUndeltaStore(send, cache.MetaNamespaceKeyFunc), 0).Run()  

 

在pkg/client/cache/Reflector.go中

func (r *Reflector) Run() {
   glog.V(3).Infof("Startingreflector %v (%s) from %s", r.expectedType, r.resyncPeriod, r.name)
   go wait.Until(func() {
      if err :=r.ListAndWatch(wait.NeverStop); err != nil {
        utilruntime.HandleError(err)    
      }
   }, r.period, wait.NeverStop)
}

 

回到RunKubelet(kcfg)函數,該函數調用startKubelet(k, podCfg, kcfg),

go wait.Until(func() { k.Run(podCfg.Updates()) }, 0,wait.NeverStop)// 開始kubelet處理函數

在該函數中開始pkg\kuberlet\kubelet.go 的func(kl *Kubelet) Run(updates <-chan kubetypes.PodUpdate)

     k.Run(podCfg.Updates())來自type KubeletBootstrap interface    {Run(<-chan kubetypes.PodUpdate)}

            來自pkg\kuberlet\kubelet.go的 func(kl *Kubelet) Run(updates <-chan kubetypes.PodUpdate)

              initializeModules()

                    //Step1: Promethues metrics.
                   metrics.Register(kl.runtimeCache)

                    //Step 2: Setup filesystem directories.

                    setupDataDirs()

                    //Step 3: If the container logs directory does not exist, create it.

                    os.Stat(containerLogsDir)

                    //Step 4: Start the image manager.

                    imageManager.Start()

                    //Step 5: Start container manager.

                    containerManager.Start()

                    //Step 6: Start out of memory watcher

                    oomWatcher.Start(kl.nodeRef)

                    //Step 7: Start resource analyzer

                go wait.Until(kl.syncNodeStatus,kl.nodeStatusUpdateFrequency, wait.NeverStop)

                go wait.Until(kl.syncNetworkStatus,30*time.Second, wait.NeverStop)

                go wait.Until(kl.updateRuntimeUp,5*time.Second, wait.NeverStop)

                //Start component sync loops.

               kl.statusManager.Start()

                kl.probeManager.Start()

                //Start the pod lifecycle event generator.
                kl.pleg.Start()
                kl.syncLoop(updates, kl)

                    kl.syncLoopIteration(updates,handler, syncTicker.C, housekeepingTicker.C, plegCh)

                       死循環

                       kl.syncLoopIteration(updates, handler, syncTicker.C,housekeepingTicker.C, plegCh)

                           case u, open := <-updates:

        開始kurblet對外服務

        開協程 go wait.Until(func() {k.ListenAndServe(kc.Address, kc.Port,kc.TLSOptions, kc.Auth, kc.EnableDebuggingHandlers)}, 0, wait.NeverStop)

                調用server.ListenAndServeKubeletServer(kl,kl.resourceAnalyzer, address, port, tlsOptions, auth, enableDebuggingHandlers,kl.containerRuntime)

/pkg/kubelet/server/server.go的 ListenAndServeKubeletServer

        開協程go wait.Until(func(){   k.ListenAndServeReadOnly(kc.Address,kc.ReadOnlyPort)}, 0, wait.NeverStop)

               調用server.ListenAndServeKubeletReadOnlyServer(kl, kl.resourceAnalyzer,address, port, kl.containerRuntime)

ListenAndServeKubeletReadOnlyServer

ListenAndServeKubeletServer 和ListenAndServeKubeletReadOnlyServer 都調用NewServer

NewServer 通過server.InstallDefaultHandlers() 安裝handler

        在InstallDefaultHandlers()中註冊/pods和/spec/的uri和處理程序

 

可以在kuberlet運行的節點執行下面操作獲取kuberlet的web服務

curl http://127.0.0.1:10248/healthz
curl http://127.0.0.1:10255/pods
curl http://127.0.0.1:10255/spec/

 

 



發佈了41 篇原創文章 · 獲贊 9 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章