kubelet
这是k8s中的一种服务,每个节点上都会运行kubelet服务进程,默认监听10250端口,接收并执行master发来的指令,管理pod和pod中的容器。定期向master节点汇报资源使用情况。
一、kubelet启动流程
kubelet是作为一个cmd命令运行,因此接口源码也就是main入口,肯定在cmd文件夹中。
cmd/kubelet/kubelet.go
func main() { rand.Seed(time.Now().UTC().UnixNano()) command := app.NewKubeletCommand(server.SetupSignalHandler()) logs.InitLogs() defer logs.FlushLogs() if err := command.Execute(); err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) } }
使能一个新的kubelet命令,并设置处理句柄。最为重要。
然后log,日志初始化。
然后调用Execute方法,表示开始进行该命令。
NewKubeletCommand方法实现:
/cmd/kubelet/app/server.go
func NewKubeletCommand(stopCh <-chan struct{}) *cobra.Command { cleanFlagSet := pflag.NewFlagSet(componentKubelet, pflag.ContinueOnError) cleanFlagSet.SetNormalizeFunc(flag.WordSepNormalizeFunc) kubeletFlags := options.NewKubeletFlags() kubeletConfig, err := options.NewKubeletConfiguration() // programmer error if err != nil { glog.Fatal(err) }
.......
// run the kubelet glog.V(5).Infof("KubeletConfiguration: %#v", kubeletServer.KubeletConfiguration) if err := Run(kubeletServer, kubeletDeps, stopCh); err != nil { glog.Fatal(err) } },
在该函数中,对命令进行一些设置,然后调用了Run接口,该接口很关键:
Run:/cmd/kubelet/app/server.go
func Run(s *options.KubeletServer, kubeDeps *kubelet.Dependencies, stopCh <-chan struct{}) error { // To help debugging, immediately log version glog.Infof("Version: %+v", version.Get()) if err := initForOS(s.KubeletFlags.WindowsService); err != nil { return fmt.Errorf("failed OS init: %v", err) } if err := run(s, kubeDeps, stopCh); err != nil { return fmt.Errorf("failed to run Kubelet: %v", err) } return nil }
调用了run函数,该函数与上面的Run函数在同一文件:
run:/cmd/kubelet/app/server.go
func run(s *options.KubeletServer, kubeDeps *kubelet.Dependencies, stopCh <-chan struct{}) (err error) { // Set global feature gates based on the value on the initial KubeletServer err = utilfeature.DefaultFeatureGate.SetFromMap(s.KubeletConfiguration.FeatureGates) if err != nil { return err } // validate the initial KubeletServer (we set feature gates first, because this validation depends on feature gates) if err := options.ValidateKubeletServer(s); err != nil { return err } // Obtain Kubelet Lock File if s.ExitOnLockContention && s.LockFilePath == "" { return errors.New("cannot exit on lock file contention: no lock file specified") }
......
if err := RunKubelet(&s.KubeletFlags, &s.KubeletConfiguration, kubeDeps, s.RunOnce, stopCh); err != nil { return err }
整个过程都是一个前期的准备工作,比如一些参数的准备。然后会调用RunKubelet函数,该函数非常重要,是启动kubelet的关节接口。
RunKubelet:/cmd/kubelet/app/server.go
// RunKubelet is responsible for setting up and running a kubelet. It is used in three different applications: // 1 Integration tests // 2 Kubelet binary // 3 Standalone 'kubernetes' binary // Eventually, #2 will be replaced with instances of #3 func RunKubelet(kubeFlags *options.KubeletFlags, kubeCfg *kubeletconfiginternal.KubeletConfiguration, kubeDeps *kubelet.Dependencies, runOnce bool, stopCh <-chan struct{}) error { hostname := nodeutil.GetHostname(kubeFlags.HostnameOverride) // Query the cloud provider for our node name, default to hostname if kubeDeps.Cloud == nil nodeName, err := getNodeName(kubeDeps.Cloud, hostname) if err != nil { return err } // Setup event recorder if required. makeEventRecorder(kubeDeps, nodeName)
......
// process pods and exit. if runOnce { if _, err := k.RunOnce(podCfg.Updates()); err != nil { return fmt.Errorf("runonce failed: %v", err) } glog.Infof("Started kubelet as runonce") } else { startKubelet(k, podCfg, kubeCfg, kubeDeps, kubeFlags.EnableServer) glog.Infof("Started kubelet") } return nil
最终该函数会先调用RunOnce函数进入主循环,执行入口一个管道,会实时地发送过来 pod 最新的配置信息是。最后调用startKubelet函数。
RunOnce函数:/pkg/kubelet/runonce.go
// RunOnce polls from one configuration update and run the associated pods. func (kl *Kubelet) RunOnce(updates <-chan kubetypes.PodUpdate) ([]RunPodResult, error) { // Setup filesystem directories. if err := kl.setupDataDirs(); err != nil { return nil, err } // If the container logs directory does not exist, create it. if _, err := os.Stat(ContainerLogsDir); err != nil { if err := kl.os.MkdirAll(ContainerLogsDir, 0755); err != nil { glog.Errorf("Failed to create directory %q: %v", ContainerLogsDir, err) } } select { case u := <-updates: glog.Infof("processing manifest with %d pods", len(u.Pods)) result, err := kl.runOnce(u.Pods, runOnceRetryDelay) glog.Infof("finished processing %d pods", len(u.Pods)) return result, err case <-time.After(runOnceManifestDelay): return nil, fmt.Errorf("no pod manifest update after %v", runOnceManifestDelay) } }
可以看出该函数的作用就是创建pod并周期性更新pod信息。创建pod的功能主要由其中的runOnce函数实现,该函数也在此文件中:
runOnce:/pkg/kubelet/runonce.go
// runOnce runs a given set of pods and returns their status. func (kl *Kubelet) runOnce(pods []*v1.Pod, retryDelay time.Duration) (results []RunPodResult, err error) { ch := make(chan RunPodResult) admitted := []*v1.Pod{} for _, pod := range pods { // Check if we can admit the pod. if ok, reason, message := kl.canAdmitPod(admitted, pod); !ok { kl.rejectPod(pod, reason, message) results = append(results, RunPodResult{pod, nil}) continue } admitted = append(admitted, pod) go func(pod *v1.Pod) { err := kl.runPod(pod, retryDelay) ch <- RunPodResult{pod, err} }(pod) } glog.Infof("Waiting for %d pods", len(admitted)) failedPods := []string{} for i := 0; i < len(admitted); i++ { res := <-ch results = append(results, res) if res.Err != nil { faliedContainerName, err := kl.getFailedContainers(res.Pod) if err != nil { glog.Infof("unable to get failed containers' names for pod %q, error:%v", format.Pod(res.Pod), err) } else { glog.Infof("unable to start pod %q because container:%v failed", format.Pod(res.Pod), faliedContainerName) } failedPods = append(failedPods, format.Pod(res.Pod)) } else { glog.Infof("started pod %q", format.Pod(res.Pod)) } } if len(failedPods) > 0 { return results, fmt.Errorf("error running pods: %v", failedPods) } glog.Infof("%d pods started", len(pods)) return results, err }
再回到RunKubelet函数中,执行完RunOnce函数后,执行startKubelet函数。
startKubelet:/cmd/kubelet/app/server.go
func startKubelet(k kubelet.Bootstrap, podCfg *config.PodConfig, kubeCfg *kubeletconfiginternal.KubeletConfiguration, kubeDeps *kubelet.Dependencies, enableServer bool) { wg := sync.WaitGroup{} // start the kubelet wg.Add(1) go wait.Until(func() { wg.Done() k.Run(podCfg.Updates()) }, 0, wait.NeverStop) // start the kubelet server if enableServer { wg.Add(1) go wait.Until(func() { wg.Done() k.ListenAndServe(net.ParseIP(kubeCfg.Address), uint(kubeCfg.Port), kubeDeps.TLSOptions, kubeDeps.Auth, kubeCfg.EnableDebuggingHandlers, kubeCfg.EnableContentionProfiling) }, 0, wait.NeverStop) } if kubeCfg.ReadOnlyPort > 0 { wg.Add(1) go wait.Until(func() { wg.Done() k.ListenAndServeReadOnly(net.ParseIP(kubeCfg.Address), uint(kubeCfg.ReadOnlyPort)) }, 0, wait.NeverStop) } wg.Wait() }完成kubelet的启动。