【源码分析】kubelet启动流程

265 阅读6分钟

工作原理

image.png

调用栈概览

main()                                                                         // cmd/kubelet/kubelet.go
 |- app.NewKubeletCommand()                                                    // cmd/kubelet/app/server.go
 |    |- kubeletFlags.KubeletConfigFile()
 |    |- UnsecuredDependencies()
 |    |- Run()                                                                 // cmd/kubelet/app/server.go
 |       |- run()                                                              // cmd/kubelet/app/server.go
 |           |- options.ValidateKubeletServer(s)
 |           |- initConfigz(&s.KubeletConfiguration)
 |           |- cadvisor.New()
 |           |- cm.NewContainerManager()
 |           |- oomAdjuster.ApplyOOMScoreAdj()
 |           |- kubelet.PreInitRuntimeService()
 |           |- RunKubelet(s, kubeDeps, s.RunOnce)                            // cmd/kubelet/app/server.go
 |                |- createAndInitKubelet()                                   // cmd/kubelet/app/server.go
 |                     |- kubelet.NewMainKubelet()                            // pkg/kubelet/kubelet.go
 |                         |- watch k8s Nodes
 |                         |- init kubeDeps.PodConfig
 |                         |- watch k8s Services
 |                         |- klet := &Kubelet{}
 |                         |- init klet.podWorkers
 |                         |- init klet runtime
 |                         |- init klet pleg
 |                         |- setup containerGC
 |                         |- setup imageManager
 |                         |- init klet.probeManager
 |                         |- init klet.volumePluginMgr
 |                         |- setup volumeManager
 |                         |- setup eviction manager
 |                         |- setup node shutdown manager
 |                     |- k.StartGarbageCollection()
 |                |- startKubelet()                                            // cmd/kubelet/app/server.go
 |                     |- go k.Run(podCfg.Updates())                           // pkg/kubelet/kubelet.go
 |                          |- kl.initializeModules()
 |                          |- go kl.volumeManager.Run()
 |                          |- go kl.nodeLeaseController.Run()
 |                          |- kl.updateRuntimeUp
 |                          |- kl.initNetworkUtil()
 |                          |- kl.statusManager.Start()
 |                          |- kl.pleg.Start()
 |                          |- kl.syncLoop(updates, kl)
 |                     |- go k.ListenAndServe()
 |           |- http.ListenAndServe()
 |- command.Execute()

调用过程

kubelet命令行入口
// cmd/kubelet/kubelet.go
func main() {
    ...
    command := app.NewKubeletCommand()
​
    if err := command.Execute(); err != nil {
        os.Exit(1)
    }
}
​
初始化命令行参数、kubelet启动
// cmd/kubelet/app/server.go// 构建 kubelet 命令行工具入口函数
func NewKubeletCommand() *cobra.Command {
    cleanFlagSet := pflag.NewFlagSet(componentKubelet, pflag.ContinueOnError)
    cleanFlagSet.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
    kubeletFlags := options.NewKubeletFlags()
    kubeletConfig, err := options.NewKubeletConfiguration()
    ...
​
    cmd := &cobra.Command{
        ...
        Run: func(cmd *cobra.Command, args []string) {
            // initial flag parse, since we disable cobra's flag parsing
            if err := cleanFlagSet.Parse(args); err != nil {
                klog.ErrorS(err, "Failed to parse kubelet flag")
                cmd.Usage()
                os.Exit(1)
            }
​
            // check if there are non-flag arguments in the command line
            cmds := cleanFlagSet.Args()
            if len(cmds) > 0 {
                klog.ErrorS(nil, "Unknown command", "command", cmds[0])
                cmd.Usage()
                os.Exit(1)
            }
​
            ...
​
            // set feature gates from initial flags-based config
            if err := utilfeature.DefaultMutableFeatureGate.SetFromMap(kubeletConfig.FeatureGates); err != nil {
                klog.ErrorS(err, "Failed to set feature gates from initial flags-based config")
                os.Exit(1)
            }
​
            // validate the initial KubeletFlags
            if err := options.ValidateKubeletFlags(kubeletFlags); err != nil {
                klog.ErrorS(err, "Failed to validate kubelet flags")
                os.Exit(1)
            }
​
            if kubeletFlags.ContainerRuntime == "remote" && cleanFlagSet.Changed("pod-infra-container-image") {
                klog.InfoS("Warning: For remote container runtime, --pod-infra-container-image is ignored in kubelet, which should be set in that remote runtime instead")
            }
​
            // 加载 kubelet 配置文件
            if configFile := kubeletFlags.KubeletConfigFile; len(configFile) > 0 {
                kubeletConfig, err = loadConfigFile(configFile)
                ...
            }
​
            // 校验配置文件中的参数
            if err := kubeletconfigvalidation.ValidateKubeletConfiguration(kubeletConfig); err != nil {
                klog.ErrorS(err, "Failed to validate kubelet configuration", "path", kubeletConfig)
                os.Exit(1)
            }
​
            if (kubeletConfig.KubeletCgroups != "" && kubeletConfig.KubeReservedCgroup != "") && (strings.Index(kubeletConfig.KubeletCgroups, kubeletConfig.KubeReservedCgroup) != 0) {
                klog.InfoS("unsupported configuration:KubeletCgroups is not within KubeReservedCgroup")
            }
​
            ...
​
            // construct a KubeletServer from kubeletFlags and kubeletConfig
            kubeletServer := &options.KubeletServer{
                KubeletFlags:         *kubeletFlags,
                KubeletConfiguration: *kubeletConfig,
            }
​
            // 初始化 kubeletDeps, kubeletDeps 包含 kubelet 运行所必须的配置,是为了实现 dependency injection,其目的是为了把 kubelet 依赖的的组件对象作为参数传进来,达到灵活控制 kubelet 的目的
            kubeletDeps, err := UnsecuredDependencies(kubeletServer, utilfeature.DefaultFeatureGate)
            if err != nil {
                klog.ErrorS(err, "Failed to construct kubelet dependencies")
                os.Exit(1)
            }
​
            // add the kubelet config controller to kubeletDeps
            kubeletDeps.KubeletConfigController = kubeletConfigController
​
            if err := checkPermissions(); err != nil {
                klog.ErrorS(err, "kubelet running with insufficient permissions")
            }
            // set up signal context here in order to be reused by kubelet and docker shim
            ctx := genericapiserver.SetupSignalContext()
​
            // 打印启动参数
            config := kubeletServer.KubeletConfiguration.DeepCopy()
            for k := range config.StaticPodURLHeader {
                config.StaticPodURLHeader[k] = []string{"<masked>"}
            }
            klog.V(5).InfoS("KubeletConfiguration", "configuration", config)
​
            // 调用 Run 方法
            if err := Run(ctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate); err != nil {
                klog.ErrorS(err, "Failed to run kubelet")
                os.Exit(1)
            }
        },
    }
​
    ...
​
    return cmd
}
​
// 使用给定的Dependencies运行kubelet服务
func Run(ctx context.Context, s *options.KubeletServer, kubeDeps *kubelet.Dependencies, featureGate featuregate.FeatureGate) error {
    ...
    if err := run(ctx, s, kubeDeps, featureGate); err != nil {
        return fmt.Errorf("failed to run Kubelet: %w", err)
    }
    return nil
}
​
func run(ctx context.Context, s *options.KubeletServer, kubeDeps *kubelet.Dependencies, featureGate featuregate.FeatureGate) (err error) {
    // Set global feature gates based on the value on the initial KubeletServer
    err = utilfeature.DefaultMutableFeatureGate.SetFromMap(s.KubeletConfiguration.FeatureGates)
    if err != nil {
        return err
    }
    // 验证KubeletServer配置参数
    if err := options.ValidateKubeletServer(s); err != nil {
        return err
    }
​
    ...
    // 注册当前配置文件到 http server /configz URL中
    err = initConfigz(&s.KubeletConfiguration)
    if err != nil {
        klog.ErrorS(err, "Failed to register kubelet configuration with configz")
    }
​
    if len(s.ShowHiddenMetricsForVersion) > 0 {
        metrics.SetShowHidden()
    }
​
    // About to get clients and such, detect standaloneMode
    standaloneMode := true
    if len(s.KubeConfig) > 0 {
        standaloneMode = false
    }
​
    if kubeDeps == nil {
        kubeDeps, err = UnsecuredDependencies(s, featureGate)
        if err != nil {
            return err
        }
    }
​
    ...
​
    hostName, err := nodeutil.GetHostname(s.HostnameOverride)
    if err != nil {
        return err
    }
    nodeName, err := getNodeName(kubeDeps.Cloud, hostName)
    if err != nil {
        return err
    }
​
    // 检测 kubelet 是否为 standalone 模式,如果是的话设置所有 client 为 nil; 默认集群中 kubelet 为非独立模式启动
    switch {
    case standaloneMode:
        kubeDeps.KubeClient = nil
        kubeDeps.EventClient = nil
        kubeDeps.HeartbeatClient = nil
        klog.InfoS("Standalone mode, no API client")
​
    // 为 kubeDeps 初始化 KubeClient、EventClient、HeartbeatClient 模块
    case kubeDeps.KubeClient == nil, kubeDeps.EventClient == nil, kubeDeps.HeartbeatClient == nil:
        clientConfig, closeAllConns, err := buildKubeletClientConfig(ctx, s, nodeName)
        if err != nil {
            return err
        }
        if closeAllConns == nil {
            return errors.New("closeAllConns must be a valid function other than nil")
        }
        kubeDeps.OnHeartbeatFailure = closeAllConns
​
        kubeDeps.KubeClient, err = clientset.NewForConfig(clientConfig)
        if err != nil {
            return fmt.Errorf("failed to initialize kubelet client: %w", err)
        }
​
        // make a separate client for events
        eventClientConfig := *clientConfig
        eventClientConfig.QPS = float32(s.EventRecordQPS)
        eventClientConfig.Burst = int(s.EventBurst)
        kubeDeps.EventClient, err = v1core.NewForConfig(&eventClientConfig)
        if err != nil {
            return fmt.Errorf("failed to initialize kubelet event client: %w", err)
        }
​
        // make a separate client for heartbeat with throttling disabled and a timeout attached
        heartbeatClientConfig := *clientConfig
        heartbeatClientConfig.Timeout = s.KubeletConfiguration.NodeStatusUpdateFrequency.Duration
        // The timeout is the minimum of the lease duration and status update frequency
        leaseTimeout := time.Duration(s.KubeletConfiguration.NodeLeaseDurationSeconds) * time.Second
        if heartbeatClientConfig.Timeout > leaseTimeout {
            heartbeatClientConfig.Timeout = leaseTimeout
        }
​
        heartbeatClientConfig.QPS = float32(-1)
        kubeDeps.HeartbeatClient, err = clientset.NewForConfig(&heartbeatClientConfig)
        if err != nil {
            return fmt.Errorf("failed to initialize kubelet heartbeat client: %w", err)
        }
    }
​
    if kubeDeps.Auth == nil {
        auth, runAuthenticatorCAReload, err := BuildAuth(nodeName, kubeDeps.KubeClient, s.KubeletConfiguration)
        if err != nil {
            return err
        }
        kubeDeps.Auth = auth
        runAuthenticatorCAReload(ctx.Done())
    }
​
    // 初始化 cgroup 配置
    var cgroupRoots []string
    nodeAllocatableRoot := cm.NodeAllocatableRoot(s.CgroupRoot, s.CgroupsPerQOS, s.CgroupDriver)
    cgroupRoots = append(cgroupRoots, nodeAllocatableRoot)
    kubeletCgroup, err := cm.GetKubeletContainer(s.KubeletCgroups)
    if err != nil {
        klog.InfoS("Failed to get the kubelet's cgroup. Kubelet system container metrics may be missing.", "err", err)
    } else if kubeletCgroup != "" {
        cgroupRoots = append(cgroupRoots, kubeletCgroup)
    }
​
    runtimeCgroup, err := cm.GetRuntimeContainer(s.ContainerRuntime, s.RuntimeCgroups)
    if err != nil {
        klog.InfoS("Failed to get the container runtime's cgroup. Runtime system container metrics may be missing.", "err", err)
    } else if runtimeCgroup != "" {
        // RuntimeCgroups is optional, so ignore if it isn't specified
        cgroupRoots = append(cgroupRoots, runtimeCgroup)
    }
​
    if s.SystemCgroups != "" {
        // SystemCgroups is optional, so ignore if it isn't specified
        cgroupRoots = append(cgroupRoots, s.SystemCgroups)
    }
​
    // 初始化 cadvisor
    if kubeDeps.CAdvisorInterface == nil {
        imageFsInfoProvider := cadvisor.NewImageFsInfoProvider(s.ContainerRuntime, s.RemoteRuntimeEndpoint)
        kubeDeps.CAdvisorInterface, err = cadvisor.New(imageFsInfoProvider, s.RootDirectory, cgroupRoots, cadvisor.UsingLegacyCadvisorStats(s.ContainerRuntime, s.RemoteRuntimeEndpoint))
        if err != nil {
            return err
        }
    }
​
    // Setup event recorder if required.
    makeEventRecorder(kubeDeps, nodeName)
​
    // 初始化 kubeDeps.ContainerManager
    if kubeDeps.ContainerManager == nil {
        if s.CgroupsPerQOS && s.CgroupRoot == "" {
            klog.InfoS("--cgroups-per-qos enabled, but --cgroup-root was not specified.  defaulting to /")
            s.CgroupRoot = "/"
        }
​
        machineInfo, err := kubeDeps.CAdvisorInterface.MachineInfo()
        if err != nil {
            return err
        }
        reservedSystemCPUs, err := getReservedCPUs(machineInfo, s.ReservedSystemCPUs)
        if err != nil {
            return err
        }
        if reservedSystemCPUs.Size() > 0 {
            // at cmd option validation phase it is tested either --system-reserved-cgroup or --kube-reserved-cgroup is specified, so overwrite should be ok
            klog.InfoS("Option --reserved-cpus is specified, it will overwrite the cpu setting in KubeReserved and SystemReserved", "kubeReservedCPUs", s.KubeReserved, "systemReservedCPUs", s.SystemReserved)
            if s.KubeReserved != nil {
                delete(s.KubeReserved, "cpu")
            }
            if s.SystemReserved == nil {
                s.SystemReserved = make(map[string]string)
            }
            s.SystemReserved["cpu"] = strconv.Itoa(reservedSystemCPUs.Size())
            klog.InfoS("After cpu setting is overwritten", "kubeReservedCPUs", s.KubeReserved, "systemReservedCPUs", s.SystemReserved)
        }
​
        kubeReserved, err := parseResourceList(s.KubeReserved)
        if err != nil {
            return err
        }
        systemReserved, err := parseResourceList(s.SystemReserved)
        if err != nil {
            return err
        }
        var hardEvictionThresholds []evictionapi.Threshold
        // If the user requested to ignore eviction thresholds, then do not set valid values for hardEvictionThresholds here.
        if !s.ExperimentalNodeAllocatableIgnoreEvictionThreshold {
            hardEvictionThresholds, err = eviction.ParseThresholdConfig([]string{}, s.EvictionHard, nil, nil, nil)
            if err != nil {
                return err
            }
        }
        experimentalQOSReserved, err := cm.ParseQOSReserved(s.QOSReserved)
        if err != nil {
            return err
        }
​
        devicePluginEnabled := utilfeature.DefaultFeatureGate.Enabled(features.DevicePlugins)
​
        var cpuManagerPolicyOptions map[string]string
        if utilfeature.DefaultFeatureGate.Enabled(features.CPUManager) {
            if utilfeature.DefaultFeatureGate.Enabled(features.CPUManagerPolicyOptions) {
                cpuManagerPolicyOptions = s.CPUManagerPolicyOptions
            } else if s.CPUManagerPolicyOptions != nil {
                return fmt.Errorf("CPU Manager policy options %v require feature gates %q, %q enabled",
                    s.CPUManagerPolicyOptions, features.CPUManager, features.CPUManagerPolicyOptions)
            }
        }
​
        kubeDeps.ContainerManager, err = cm.NewContainerManager(
            kubeDeps.Mounter,
            kubeDeps.CAdvisorInterface,
            cm.NodeConfig{
                RuntimeCgroupsName:    s.RuntimeCgroups,
                SystemCgroupsName:     s.SystemCgroups,
                KubeletCgroupsName:    s.KubeletCgroups,
                ContainerRuntime:      s.ContainerRuntime,
                CgroupsPerQOS:         s.CgroupsPerQOS,
                CgroupRoot:            s.CgroupRoot,
                CgroupDriver:          s.CgroupDriver,
                KubeletRootDir:        s.RootDirectory,
                ProtectKernelDefaults: s.ProtectKernelDefaults,
                NodeAllocatableConfig: cm.NodeAllocatableConfig{
                    KubeReservedCgroupName:   s.KubeReservedCgroup,
                    SystemReservedCgroupName: s.SystemReservedCgroup,
                    EnforceNodeAllocatable:   sets.NewString(s.EnforceNodeAllocatable...),
                    KubeReserved:             kubeReserved,
                    SystemReserved:           systemReserved,
                    ReservedSystemCPUs:       reservedSystemCPUs,
                    HardEvictionThresholds:   hardEvictionThresholds,
                },
                QOSReserved:                             *experimentalQOSReserved,
                ExperimentalCPUManagerPolicy:            s.CPUManagerPolicy,
                ExperimentalCPUManagerPolicyOptions:     cpuManagerPolicyOptions,
                ExperimentalCPUManagerReconcilePeriod:   s.CPUManagerReconcilePeriod.Duration,
                ExperimentalMemoryManagerPolicy:         s.MemoryManagerPolicy,
                ExperimentalMemoryManagerReservedMemory: s.ReservedMemory,
                ExperimentalPodPidsLimit:                s.PodPidsLimit,
                EnforceCPULimits:                        s.CPUCFSQuota,
                CPUCFSQuotaPeriod:                       s.CPUCFSQuotaPeriod.Duration,
                ExperimentalTopologyManagerPolicy:       s.TopologyManagerPolicy,
                ExperimentalTopologyManagerScope:        s.TopologyManagerScope,
            },
            s.FailSwapOn,
            devicePluginEnabled,
            kubeDeps.Recorder)
​
        if err != nil {
            return err
        }
    }
​
    utilruntime.ReallyCrash = s.ReallyCrashForTesting
​
    // 给 kubelet 进程设置 oom 分数
    oomAdjuster := kubeDeps.OOMAdjuster
    if err := oomAdjuster.ApplyOOMScoreAdj(0, int(s.OOMScoreAdj)); err != nil {
        klog.InfoS("Failed to ApplyOOMScoreAdj", "err", err)
    }
​
    err = kubelet.PreInitRuntimeService(&s.KubeletConfiguration,
        kubeDeps, &s.ContainerRuntimeOptions,
        s.ContainerRuntime,
        s.RuntimeCgroups,
        s.RemoteRuntimeEndpoint,
        s.RemoteImageEndpoint,
        s.NonMasqueradeCIDR)
    if err != nil {
        return err
    }
​
    // 调用 RunKubelet 执行后续启动逻辑
    if err := RunKubelet(s, kubeDeps, s.RunOnce); err != nil {
        return err
    }
​
    // If the kubelet config controller is available, and dynamic config is enabled, start the config and status sync loops
    if utilfeature.DefaultFeatureGate.Enabled(features.DynamicKubeletConfig) && len(s.DynamicConfigDir.Value()) > 0 &&
        kubeDeps.KubeletConfigController != nil && !standaloneMode && !s.RunOnce {
        if err := kubeDeps.KubeletConfigController.StartSync(kubeDeps.KubeClient, kubeDeps.EventClient, string(nodeName)); err != nil {
            return err
        }
    }
​
    // 启动 Healthz http server
    if s.HealthzPort > 0 {
        mux := http.NewServeMux()
        healthz.InstallHandler(mux)
        go wait.Until(func() {
            err := http.ListenAndServe(net.JoinHostPort(s.HealthzBindAddress, strconv.Itoa(int(s.HealthzPort))), mux)
            if err != nil {
                klog.ErrorS(err, "Failed to start healthz server")
            }
        }, 5*time.Second, wait.NeverStop)
    }
​
    if s.RunOnce {
        return nil
    }
​
    // 向 systemd 发送启动信号
    go daemon.SdNotify(false, "READY=1")
​
    select {
    case <-done:
        break
    case <-ctx.Done():
        break
    }
​
    return nil
}
​
func RunKubelet(kubeServer *options.KubeletServer, kubeDeps *kubelet.Dependencies, runOnce bool) error {
    hostname, err := nodeutil.GetHostname(kubeServer.HostnameOverride)
    if err != nil {
        return err
    }
    // 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
    }
    hostnameOverridden := len(kubeServer.HostnameOverride) > 0
    // Setup event recorder if required.
    makeEventRecorder(kubeDeps, nodeName)
​
    var nodeIPs []net.IP
    if kubeServer.NodeIP != "" {
        for _, ip := range strings.Split(kubeServer.NodeIP, ",") {
            parsedNodeIP := net.ParseIP(strings.TrimSpace(ip))
            if parsedNodeIP == nil {
                klog.InfoS("Could not parse --node-ip ignoring", "IP", ip)
            } else {
                nodeIPs = append(nodeIPs, parsedNodeIP)
            }
        }
    }
    if !utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) && len(nodeIPs) > 1 {
        return fmt.Errorf("dual-stack --node-ip %q not supported in a single-stack cluster", kubeServer.NodeIP)
    } else if len(nodeIPs) > 2 || (len(nodeIPs) == 2 && utilnet.IsIPv6(nodeIPs[0]) == utilnet.IsIPv6(nodeIPs[1])) {
        return fmt.Errorf("bad --node-ip %q; must contain either a single IP or a dual-stack pair of IPs", kubeServer.NodeIP)
    } else if len(nodeIPs) == 2 && kubeServer.CloudProvider != "" {
        return fmt.Errorf("dual-stack --node-ip %q not supported when using a cloud provider", kubeServer.NodeIP)
    } else if len(nodeIPs) == 2 && (nodeIPs[0].IsUnspecified() || nodeIPs[1].IsUnspecified()) {
        return fmt.Errorf("dual-stack --node-ip %q cannot include '0.0.0.0' or '::'", kubeServer.NodeIP)
    }
​
    capabilities.Initialize(capabilities.Capabilities{
        AllowPrivileged: true,
    })
​
    credentialprovider.SetPreferredDockercfgPath(kubeServer.RootDirectory)
    klog.V(2).InfoS("Using root directory", "path", kubeServer.RootDirectory)
​
    if kubeDeps.OSInterface == nil {
        kubeDeps.OSInterface = kubecontainer.RealOS{}
    }
​
    if kubeServer.KubeletConfiguration.SeccompDefault && !utilfeature.DefaultFeatureGate.Enabled(features.SeccompDefault) {
        return fmt.Errorf("the SeccompDefault feature gate must be enabled in order to use the SeccompDefault configuration")
    }
​
    // kubelet对象初始化
    // createAndInitKubelet() --> NewMainKubelet()
    k, err := createAndInitKubelet(&kubeServer.KubeletConfiguration,
        kubeDeps,
        &kubeServer.ContainerRuntimeOptions,
        kubeServer.ContainerRuntime,
        hostname,
        hostnameOverridden,
        nodeName,
        nodeIPs,
        kubeServer.ProviderID,
        kubeServer.CloudProvider,
        kubeServer.CertDirectory,
        kubeServer.RootDirectory,
        kubeServer.ImageCredentialProviderConfigFile,
        kubeServer.ImageCredentialProviderBinDir,
        kubeServer.RegisterNode,
        kubeServer.RegisterWithTaints,
        kubeServer.AllowedUnsafeSysctls,
        kubeServer.ExperimentalMounterPath,
        kubeServer.KernelMemcgNotification,
        kubeServer.ExperimentalCheckNodeCapabilitiesBeforeMount,
        kubeServer.ExperimentalNodeAllocatableIgnoreEvictionThreshold,
        kubeServer.MinimumGCAge,
        kubeServer.MaxPerPodContainerCount,
        kubeServer.MaxContainerCount,
        kubeServer.MasterServiceNamespace,
        kubeServer.RegisterSchedulable,
        kubeServer.KeepTerminatedPodVolumes,
        kubeServer.NodeLabels,
        kubeServer.SeccompProfileRoot,
        kubeServer.NodeStatusMaxImages,
        kubeServer.KubeletFlags.SeccompDefault || kubeServer.KubeletConfiguration.SeccompDefault,
    )
    if err != nil {
        return fmt.Errorf("failed to create kubelet: %w", err)
    }
​
    // NewMainKubelet should have set up a pod source config if one didn't exist
    // when the builder was run. This is just a precaution.
    if kubeDeps.PodConfig == nil {
        return fmt.Errorf("failed to create kubelet, pod source config was nil")
    }
    podCfg := kubeDeps.PodConfig
​
    if err := rlimit.SetNumFiles(uint64(kubeServer.MaxOpenFiles)); err != nil {
        klog.ErrorS(err, "Failed to set rlimit on max file handles")
    }
​
    // process pods and exit.
    if runOnce {
        if _, err := k.RunOnce(podCfg.Updates()); err != nil {
            return fmt.Errorf("runonce failed: %w", err)
        }
        klog.InfoS("Started kubelet as runonce")
    } else {
        startKubelet(k, podCfg, &kubeServer.KubeletConfiguration, kubeDeps, kubeServer.EnableServer)
        klog.InfoS("Started kubelet")
    }
    return nil
}
kubelet核心配置初始化

初始化nodeInformer、kubeDeps.PodConfig、containerGCPolicy、daemonEndpoints、imageGCPolicy、evictionConfig、初始化serviceInformer、初始化podWorker、初始化runtime、初始化pleg、初始化imageManager、probeManager、pluginManager、volumePluginMgr、volumeManager、evictionManager、nodeLeaseController、shutdownManager等等

// cmd/kubelet/app/server.gofunc NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
    kubeDeps *Dependencies,
    crOptions *config.ContainerRuntimeOptions,
    containerRuntime string,
    hostname string,
    hostnameOverridden bool,
    nodeName types.NodeName,
    nodeIPs []net.IP,
    providerID string,
    cloudProvider string,
    certDirectory string,
    rootDirectory string,
    imageCredentialProviderConfigFile string,
    imageCredentialProviderBinDir string,
    registerNode bool,
    registerWithTaints []api.Taint,
    allowedUnsafeSysctls []string,
    experimentalMounterPath string,
    kernelMemcgNotification bool,
    experimentalCheckNodeCapabilitiesBeforeMount bool,
    experimentalNodeAllocatableIgnoreEvictionThreshold bool,
    minimumGCAge metav1.Duration,
    maxPerPodContainerCount int32,
    maxContainerCount int32,
    masterServiceNamespace string,
    registerSchedulable bool,
    keepTerminatedPodVolumes bool,
    nodeLabels map[string]string,
    seccompProfileRoot string,
    nodeStatusMaxImages int32,
    seccompDefault bool,
) (*Kubelet, error) {
    if rootDirectory == "" {
        return nil, fmt.Errorf("invalid root directory %q", rootDirectory)
    }
    if kubeCfg.SyncFrequency.Duration <= 0 {
        return nil, fmt.Errorf("invalid sync frequency %d", kubeCfg.SyncFrequency.Duration)
    }
​
    if kubeCfg.MakeIPTablesUtilChains {
        if kubeCfg.IPTablesMasqueradeBit > 31 || kubeCfg.IPTablesMasqueradeBit < 0 {
            return nil, fmt.Errorf("iptables-masquerade-bit is not valid. Must be within [0, 31]")
        }
        if kubeCfg.IPTablesDropBit > 31 || kubeCfg.IPTablesDropBit < 0 {
            return nil, fmt.Errorf("iptables-drop-bit is not valid. Must be within [0, 31]")
        }
        if kubeCfg.IPTablesDropBit == kubeCfg.IPTablesMasqueradeBit {
            return nil, fmt.Errorf("iptables-masquerade-bit and iptables-drop-bit must be different")
        }
    }
​
    if utilfeature.DefaultFeatureGate.Enabled(features.DisableCloudProviders) && cloudprovider.IsDeprecatedInternal(cloudProvider) {
        cloudprovider.DisableWarningForProvider(cloudProvider)
        return nil, fmt.Errorf("cloud provider %q was specified, but built-in cloud providers are disabled. Please set --cloud-provider=external and migrate to an external cloud provider", cloudProvider)
    }
​
    var nodeHasSynced cache.InformerSynced
    var nodeLister corelisters.NodeLister
​
    // If kubeClient == nil, we are running in standalone mode (i.e. no API servers)
    // If not nil, we are running as part of a cluster and should sync w/API
    if kubeDeps.KubeClient != nil {
        kubeInformers := informers.NewSharedInformerFactoryWithOptions(kubeDeps.KubeClient, 0, informers.WithTweakListOptions(func(options *metav1.ListOptions) {
            options.FieldSelector = fields.Set{metav1.ObjectNameField: string(nodeName)}.String()
        }))
        nodeLister = kubeInformers.Core().V1().Nodes().Lister()
        nodeHasSynced = func() bool {
            return kubeInformers.Core().V1().Nodes().Informer().HasSynced()
        }
        kubeInformers.Start(wait.NeverStop)
        klog.InfoS("Attempting to sync node with API server")
    } else {
        // we don't have a client to sync!
        nodeIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{})
        nodeLister = corelisters.NewNodeLister(nodeIndexer)
        nodeHasSynced = func() bool { return true }
        klog.InfoS("Kubelet is running in standalone mode, will skip API server sync")
    }
​
    // 初始化kubeDeps.PodConfig,用于后续kubelet syncLooop函数获取所有pod操作入口(静态文件、apiserver、http)的更新消息;
    if kubeDeps.PodConfig == nil {
        var err error
        // 从三种数据源监听pod更新,并将更新内容放入podConfig.update channel中;
        // 静态文件: 通过间歇性获取目录/文件内容 + 监听文件系统事件两种方式获取静态文件变化
        // http:间隔地从url读取pod数据
        // apiserver:listAndWatch机制
        kubeDeps.PodConfig, err = makePodSourceConfig(kubeCfg, kubeDeps, nodeName, nodeHasSynced)
        if err != nil {
            return nil, err
        }
    }
​
    containerGCPolicy := kubecontainer.GCPolicy{
        MinAge:             minimumGCAge.Duration,
        MaxPerPodContainer: int(maxPerPodContainerCount),
        MaxContainers:      int(maxContainerCount),
    }
​
    daemonEndpoints := &v1.NodeDaemonEndpoints{
        KubeletEndpoint: v1.DaemonEndpoint{Port: kubeCfg.Port},
    }
​
    imageGCPolicy := images.ImageGCPolicy{
        MinAge:               kubeCfg.ImageMinimumGCAge.Duration,
        HighThresholdPercent: int(kubeCfg.ImageGCHighThresholdPercent),
        LowThresholdPercent:  int(kubeCfg.ImageGCLowThresholdPercent),
    }
​
    enforceNodeAllocatable := kubeCfg.EnforceNodeAllocatable
    if experimentalNodeAllocatableIgnoreEvictionThreshold {
        // Do not provide kubeCfg.EnforceNodeAllocatable to eviction threshold parsing if we are not enforcing Evictions
        enforceNodeAllocatable = []string{}
    }
    thresholds, err := eviction.ParseThresholdConfig(enforceNodeAllocatable, kubeCfg.EvictionHard, kubeCfg.EvictionSoft, kubeCfg.EvictionSoftGracePeriod, kubeCfg.EvictionMinimumReclaim)
    if err != nil {
        return nil, err
    }
    evictionConfig := eviction.Config{
        PressureTransitionPeriod: kubeCfg.EvictionPressureTransitionPeriod.Duration,
        MaxPodGracePeriodSeconds: int64(kubeCfg.EvictionMaxPodGracePeriod),
        Thresholds:               thresholds,
        KernelMemcgNotification:  kernelMemcgNotification,
        PodCgroupRoot:            kubeDeps.ContainerManager.GetPodCgroupRoot(),
    }
​
    var serviceLister corelisters.ServiceLister
    var serviceHasSynced cache.InformerSynced
    if kubeDeps.KubeClient != nil {
        kubeInformers := informers.NewSharedInformerFactory(kubeDeps.KubeClient, 0)
        serviceLister = kubeInformers.Core().V1().Services().Lister()
        serviceHasSynced = kubeInformers.Core().V1().Services().Informer().HasSynced
        kubeInformers.Start(wait.NeverStop)
    } else {
        serviceIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
        serviceLister = corelisters.NewServiceLister(serviceIndexer)
        serviceHasSynced = func() bool { return true }
    }
​
    // construct a node reference used for events
    nodeRef := &v1.ObjectReference{
        Kind:      "Node",
        Name:      string(nodeName),
        UID:       types.UID(nodeName),
        Namespace: "",
    }
​
    oomWatcher, err := oomwatcher.NewWatcher(kubeDeps.Recorder)
    if err != nil {
        if libcontaineruserns.RunningInUserNS() {
            if utilfeature.DefaultFeatureGate.Enabled(features.KubeletInUserNamespace) {
                // oomwatcher.NewWatcher returns "open /dev/kmsg: operation not permitted" error,
                // when running in a user namespace with sysctl value `kernel.dmesg_restrict=1`.
                klog.V(2).InfoS("Failed to create an oomWatcher (running in UserNS, ignoring)", "err", err)
                oomWatcher = nil
            } else {
                klog.ErrorS(err, "Failed to create an oomWatcher (running in UserNS, Hint: enable KubeletInUserNamespace feature flag to ignore the error)")
                return nil, err
            }
        } else {
            return nil, err
        }
    }
​
    clusterDNS := make([]net.IP, 0, len(kubeCfg.ClusterDNS))
    for _, ipEntry := range kubeCfg.ClusterDNS {
        ip := net.ParseIP(ipEntry)
        if ip == nil {
            klog.InfoS("Invalid clusterDNS IP", "IP", ipEntry)
        } else {
            clusterDNS = append(clusterDNS, ip)
        }
    }
    httpClient := &http.Client{}
​
    klet := &Kubelet{
        hostname:                                hostname,
        hostnameOverridden:                      hostnameOverridden,
        nodeName:                                nodeName,
        kubeClient:                              kubeDeps.KubeClient,
        heartbeatClient:                         kubeDeps.HeartbeatClient,
        onRepeatedHeartbeatFailure:              kubeDeps.OnHeartbeatFailure,
        rootDirectory:                           rootDirectory,
        resyncInterval:                          kubeCfg.SyncFrequency.Duration,
        sourcesReady:                            config.NewSourcesReady(kubeDeps.PodConfig.SeenAllSources),
        registerNode:                            registerNode,
        registerWithTaints:                      registerWithTaints,
        registerSchedulable:                     registerSchedulable,
        dnsConfigurer:                           dns.NewConfigurer(kubeDeps.Recorder, nodeRef, nodeIPs, clusterDNS, kubeCfg.ClusterDomain, kubeCfg.ResolverConfig),
        serviceLister:                           serviceLister,
        serviceHasSynced:                        serviceHasSynced,
        nodeLister:                              nodeLister,
        nodeHasSynced:                           nodeHasSynced,
        masterServiceNamespace:                  masterServiceNamespace,
        streamingConnectionIdleTimeout:          kubeCfg.StreamingConnectionIdleTimeout.Duration,
        recorder:                                kubeDeps.Recorder,
        cadvisor:                                kubeDeps.CAdvisorInterface,
        cloud:                                   kubeDeps.Cloud,
        externalCloudProvider:                   cloudprovider.IsExternal(cloudProvider),
        providerID:                              providerID,
        nodeRef:                                 nodeRef,
        nodeLabels:                              nodeLabels,
        nodeStatusUpdateFrequency:               kubeCfg.NodeStatusUpdateFrequency.Duration,
        nodeStatusReportFrequency:               kubeCfg.NodeStatusReportFrequency.Duration,
        os:                                      kubeDeps.OSInterface,
        oomWatcher:                              oomWatcher,
        cgroupsPerQOS:                           kubeCfg.CgroupsPerQOS,
        cgroupRoot:                              kubeCfg.CgroupRoot,
        mounter:                                 kubeDeps.Mounter,
        hostutil:                                kubeDeps.HostUtil,
        subpather:                               kubeDeps.Subpather,
        maxPods:                                 int(kubeCfg.MaxPods),
        podsPerCore:                             int(kubeCfg.PodsPerCore),
        syncLoopMonitor:                         atomic.Value{},
        daemonEndpoints:                         daemonEndpoints,
        containerManager:                        kubeDeps.ContainerManager,
        containerRuntimeName:                    containerRuntime,
        nodeIPs:                                 nodeIPs,
        nodeIPValidator:                         validateNodeIP,
        clock:                                   clock.RealClock{},
        enableControllerAttachDetach:            kubeCfg.EnableControllerAttachDetach,
        makeIPTablesUtilChains:                  kubeCfg.MakeIPTablesUtilChains,
        iptablesMasqueradeBit:                   int(kubeCfg.IPTablesMasqueradeBit),
        iptablesDropBit:                         int(kubeCfg.IPTablesDropBit),
        experimentalHostUserNamespaceDefaulting: utilfeature.DefaultFeatureGate.Enabled(features.ExperimentalHostUserNamespaceDefaultingGate),
        keepTerminatedPodVolumes:                keepTerminatedPodVolumes,
        nodeStatusMaxImages:                     nodeStatusMaxImages,
        lastContainerStartedTime:                newTimeCache(),
    }
​
    if klet.cloud != nil {
        klet.cloudResourceSyncManager = cloudresource.NewSyncManager(klet.cloud, nodeName, klet.nodeStatusUpdateFrequency)
    }
​
    var secretManager secret.Manager
    var configMapManager configmap.Manager
    switch kubeCfg.ConfigMapAndSecretChangeDetectionStrategy {
    case kubeletconfiginternal.WatchChangeDetectionStrategy:
        secretManager = secret.NewWatchingSecretManager(kubeDeps.KubeClient, klet.resyncInterval)
        configMapManager = configmap.NewWatchingConfigMapManager(kubeDeps.KubeClient, klet.resyncInterval)
    case kubeletconfiginternal.TTLCacheChangeDetectionStrategy:
        secretManager = secret.NewCachingSecretManager(
            kubeDeps.KubeClient, manager.GetObjectTTLFromNodeFunc(klet.GetNode))
        configMapManager = configmap.NewCachingConfigMapManager(
            kubeDeps.KubeClient, manager.GetObjectTTLFromNodeFunc(klet.GetNode))
    case kubeletconfiginternal.GetChangeDetectionStrategy:
        secretManager = secret.NewSimpleSecretManager(kubeDeps.KubeClient)
        configMapManager = configmap.NewSimpleConfigMapManager(kubeDeps.KubeClient)
    default:
        return nil, fmt.Errorf("unknown configmap and secret manager mode: %v", kubeCfg.ConfigMapAndSecretChangeDetectionStrategy)
    }
​
    klet.secretManager = secretManager
    klet.configMapManager = configMapManager
​
    if klet.experimentalHostUserNamespaceDefaulting {
        klog.InfoS("Experimental host user namespace defaulting is enabled")
    }
​
    machineInfo, err := klet.cadvisor.MachineInfo()
    if err != nil {
        return nil, err
    }
    // Avoid collector collects it as a timestamped metric
    // See PR #95210 and #97006 for more details.
    machineInfo.Timestamp = time.Time{}
    klet.setCachedMachineInfo(machineInfo)
​
    imageBackOff := flowcontrol.NewBackOff(backOffPeriod, MaxContainerBackOff)
​
    klet.livenessManager = proberesults.NewManager()
    klet.readinessManager = proberesults.NewManager()
    klet.startupManager = proberesults.NewManager()
    klet.podCache = kubecontainer.NewCache()
​
    // podManager is also responsible for keeping secretManager and configMapManager contents up-to-date.
    mirrorPodClient := kubepod.NewBasicMirrorClient(klet.kubeClient, string(nodeName), nodeLister)
    klet.podManager = kubepod.NewBasicPodManager(mirrorPodClient, secretManager, configMapManager)
​
    klet.statusManager = status.NewManager(klet.kubeClient, klet.podManager, klet)
​
    klet.resourceAnalyzer = serverstats.NewResourceAnalyzer(klet, kubeCfg.VolumeStatsAggPeriod.Duration, kubeDeps.Recorder)
​
    klet.dockerLegacyService = kubeDeps.dockerLegacyService
    klet.runtimeService = kubeDeps.RemoteRuntimeService
​
    if kubeDeps.KubeClient != nil {
        klet.runtimeClassManager = runtimeclass.NewManager(kubeDeps.KubeClient)
    }
​
    if containerRuntime == kubetypes.RemoteContainerRuntime {
        // setup containerLogManager for CRI container runtime
        containerLogManager, err := logs.NewContainerLogManager(
            klet.runtimeService,
            kubeDeps.OSInterface,
            kubeCfg.ContainerLogMaxSize,
            int(kubeCfg.ContainerLogMaxFiles),
        )
        if err != nil {
            return nil, fmt.Errorf("failed to initialize container log manager: %v", err)
        }
        klet.containerLogManager = containerLogManager
    } else {
        klet.containerLogManager = logs.NewStubContainerLogManager()
    }
​
    klet.reasonCache = NewReasonCache()
    klet.workQueue = queue.NewBasicWorkQueue(klet.clock)
    klet.podWorkers = newPodWorkers(
        klet.syncPod,
        klet.syncTerminatingPod,
        klet.syncTerminatedPod,
​
        kubeDeps.Recorder,
        klet.workQueue,
        klet.resyncInterval,
        backOffPeriod,
        klet.podCache,
    )
​
    runtime, err := kuberuntime.NewKubeGenericRuntimeManager(
        kubecontainer.FilterEventRecorder(kubeDeps.Recorder),
        klet.livenessManager,
        klet.readinessManager,
        klet.startupManager,
        seccompProfileRoot,
        machineInfo,
        klet.podWorkers,
        kubeDeps.OSInterface,
        klet,
        httpClient,
        imageBackOff,
        kubeCfg.SerializeImagePulls,
        float32(kubeCfg.RegistryPullQPS),
        int(kubeCfg.RegistryBurst),
        imageCredentialProviderConfigFile,
        imageCredentialProviderBinDir,
        kubeCfg.CPUCFSQuota,
        kubeCfg.CPUCFSQuotaPeriod,
        kubeDeps.RemoteRuntimeService,
        kubeDeps.RemoteImageService,
        kubeDeps.ContainerManager.InternalContainerLifecycle(),
        kubeDeps.dockerLegacyService,
        klet.containerLogManager,
        klet.runtimeClassManager,
        seccompDefault,
        kubeCfg.MemorySwap.SwapBehavior,
        kubeDeps.ContainerManager.GetNodeAllocatableAbsolute,
        *kubeCfg.MemoryThrottlingFactor,
    )
    if err != nil {
        return nil, err
    }
    klet.containerRuntime = runtime
    klet.streamingRuntime = runtime
    klet.runner = runtime
​
    runtimeCache, err := kubecontainer.NewRuntimeCache(klet.containerRuntime)
    if err != nil {
        return nil, err
    }
    klet.runtimeCache = runtimeCache
​
    // common provider to get host file system usage associated with a pod managed by kubelet
    hostStatsProvider := stats.NewHostStatsProvider(kubecontainer.RealOS{}, func(podUID types.UID) (string, bool) {
        return getEtcHostsPath(klet.getPodDir(podUID)), klet.containerRuntime.SupportsSingleFileMapping()
    })
    if kubeDeps.useLegacyCadvisorStats {
        klet.StatsProvider = stats.NewCadvisorStatsProvider(
            klet.cadvisor,
            klet.resourceAnalyzer,
            klet.podManager,
            klet.runtimeCache,
            klet.containerRuntime,
            klet.statusManager,
            hostStatsProvider)
    } else {
        klet.StatsProvider = stats.NewCRIStatsProvider(
            klet.cadvisor,
            klet.resourceAnalyzer,
            klet.podManager,
            klet.runtimeCache,
            kubeDeps.RemoteRuntimeService,
            kubeDeps.RemoteImageService,
            hostStatsProvider,
            utilfeature.DefaultFeatureGate.Enabled(features.DisableAcceleratorUsageMetrics))
    }
​
    // 初始化pleg,并将pleg.Healthy函数注入到runtimeState作为健康检查函数
    klet.pleg = pleg.NewGenericPLEG(klet.containerRuntime, plegChannelCapacity, plegRelistPeriod, klet.podCache, clock.RealClock{})
    klet.runtimeState = newRuntimeState(maxWaitForContainerRuntime)
    klet.runtimeState.addHealthCheck("PLEG", klet.pleg.Healthy)
    if _, err := klet.updatePodCIDR(kubeCfg.PodCIDR); err != nil {
        klog.ErrorS(err, "Pod CIDR update failed")
    }
​
    // setup containerGC
    containerGC, err := kubecontainer.NewContainerGC(klet.containerRuntime, containerGCPolicy, klet.sourcesReady)
    if err != nil {
        return nil, err
    }
    klet.containerGC = containerGC
    klet.containerDeletor = newPodContainerDeletor(klet.containerRuntime, integer.IntMax(containerGCPolicy.MaxPerPodContainer, minDeadContainerInPod))
​
    // setup imageManager
    imageManager, err := images.NewImageGCManager(klet.containerRuntime, klet.StatsProvider, kubeDeps.Recorder, nodeRef, imageGCPolicy, crOptions.PodSandboxImage)
    if err != nil {
        return nil, fmt.Errorf("failed to initialize image manager: %v", err)
    }
    klet.imageManager = imageManager
​
    if kubeCfg.ServerTLSBootstrap && kubeDeps.TLSOptions != nil && utilfeature.DefaultFeatureGate.Enabled(features.RotateKubeletServerCertificate) {
        klet.serverCertificateManager, err = kubeletcertificate.NewKubeletServerCertificateManager(klet.kubeClient, kubeCfg, klet.nodeName, klet.getLastObservedNodeAddresses, certDirectory)
        if err != nil {
            return nil, fmt.Errorf("failed to initialize certificate manager: %v", err)
        }
        kubeDeps.TLSOptions.Config.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
            cert := klet.serverCertificateManager.Current()
            if cert == nil {
                return nil, fmt.Errorf("no serving certificate available for the kubelet")
            }
            return cert, nil
        }
    }
​
    klet.probeManager = prober.NewManager(
        klet.statusManager,
        klet.livenessManager,
        klet.readinessManager,
        klet.startupManager,
        klet.runner,
        kubeDeps.Recorder)
​
    tokenManager := token.NewManager(kubeDeps.KubeClient)
​
    // NewInitializedVolumePluginMgr initializes some storageErrors on the Kubelet runtimeState (in csi_plugin.go init)
    // which affects node ready status. This function must be called before Kubelet is initialized so that the Node
    // ReadyState is accurate with the storage state.
    klet.volumePluginMgr, err =
        NewInitializedVolumePluginMgr(klet, secretManager, configMapManager, tokenManager, kubeDeps.VolumePlugins, kubeDeps.DynamicPluginProber)
    if err != nil {
        return nil, err
    }
    klet.pluginManager = pluginmanager.NewPluginManager(
        klet.getPluginsRegistrationDir(), /* sockDir */
        kubeDeps.Recorder,
    )
​
    // If the experimentalMounterPathFlag is set, we do not want to
    // check node capabilities since the mount path is not the default
    if len(experimentalMounterPath) != 0 {
        experimentalCheckNodeCapabilitiesBeforeMount = false
        // Replace the nameserver in containerized-mounter's rootfs/etc/resolve.conf with kubelet.ClusterDNS
        // so that service name could be resolved
        klet.dnsConfigurer.SetupDNSinContainerizedMounter(experimentalMounterPath)
    }
​
    // setup volumeManager
    klet.volumeManager = volumemanager.NewVolumeManager(
        kubeCfg.EnableControllerAttachDetach,
        nodeName,
        klet.podManager,
        klet.podWorkers,
        klet.kubeClient,
        klet.volumePluginMgr,
        klet.containerRuntime,
        kubeDeps.Mounter,
        kubeDeps.HostUtil,
        klet.getPodsDir(),
        kubeDeps.Recorder,
        experimentalCheckNodeCapabilitiesBeforeMount,
        keepTerminatedPodVolumes,
        volumepathhandler.NewBlockVolumePathHandler())
​
    klet.backOff = flowcontrol.NewBackOff(backOffPeriod, MaxContainerBackOff)
​
    // setup eviction manager
    evictionManager, evictionAdmitHandler := eviction.NewManager(klet.resourceAnalyzer, evictionConfig, killPodNow(klet.podWorkers, kubeDeps.Recorder), klet.podManager.GetMirrorPodByPod, klet.imageManager, klet.containerGC, kubeDeps.Recorder, nodeRef, klet.clock)
​
    klet.evictionManager = evictionManager
    klet.admitHandlers.AddPodAdmitHandler(evictionAdmitHandler)
​
    // Safe, whitelisted sysctls can always be used as unsafe sysctls in the spec.
    // Hence, we concatenate those two lists.
    safeAndUnsafeSysctls := append(sysctlwhitelist.SafeSysctlWhitelist(), allowedUnsafeSysctls...)
    sysctlsWhitelist, err := sysctl.NewWhitelist(safeAndUnsafeSysctls)
    if err != nil {
        return nil, err
    }
    klet.admitHandlers.AddPodAdmitHandler(sysctlsWhitelist)
​
    // enable active deadline handler
    activeDeadlineHandler, err := newActiveDeadlineHandler(klet.statusManager, kubeDeps.Recorder, klet.clock)
    if err != nil {
        return nil, err
    }
    klet.AddPodSyncLoopHandler(activeDeadlineHandler)
    klet.AddPodSyncHandler(activeDeadlineHandler)
​
    klet.admitHandlers.AddPodAdmitHandler(klet.containerManager.GetAllocateResourcesPodAdmitHandler())
​
    criticalPodAdmissionHandler := preemption.NewCriticalPodAdmissionHandler(klet.GetActivePods, killPodNow(klet.podWorkers, kubeDeps.Recorder), kubeDeps.Recorder)
    klet.admitHandlers.AddPodAdmitHandler(lifecycle.NewPredicateAdmitHandler(klet.getNodeAnyWay, criticalPodAdmissionHandler, klet.containerManager.UpdatePluginResources))
    // apply functional Option's
    for _, opt := range kubeDeps.Options {
        opt(klet)
    }
​
    if sysruntime.GOOS == "linux" {
        // AppArmor is a Linux kernel security module and it does not support other operating systems.
        klet.appArmorValidator = apparmor.NewValidator(containerRuntime)
        klet.softAdmitHandlers.AddPodAdmitHandler(lifecycle.NewAppArmorAdmitHandler(klet.appArmorValidator))
    }
    klet.softAdmitHandlers.AddPodAdmitHandler(lifecycle.NewNoNewPrivsAdmitHandler(klet.containerRuntime))
    klet.softAdmitHandlers.AddPodAdmitHandler(lifecycle.NewProcMountAdmitHandler(klet.containerRuntime))
​
    leaseDuration := time.Duration(kubeCfg.NodeLeaseDurationSeconds) * time.Second
    renewInterval := time.Duration(float64(leaseDuration) * nodeLeaseRenewIntervalFraction)
    klet.nodeLeaseController = lease.NewController(
        klet.clock,
        klet.heartbeatClient,
        string(klet.nodeName),
        kubeCfg.NodeLeaseDurationSeconds,
        klet.onRepeatedHeartbeatFailure,
        renewInterval,
        v1.NamespaceNodeLease,
        util.SetNodeOwnerFunc(klet.heartbeatClient, string(klet.nodeName)))
​
    // setup node shutdown manager
    shutdownManager, shutdownAdmitHandler := nodeshutdown.NewManager(klet.GetActivePods, killPodNow(klet.podWorkers, kubeDeps.Recorder), klet.syncNodeStatus, kubeCfg.ShutdownGracePeriod.Duration, kubeCfg.ShutdownGracePeriodCriticalPods.Duration)
​
    klet.shutdownManager = shutdownManager
    klet.admitHandlers.AddPodAdmitHandler(shutdownAdmitHandler)
​
    // Finally, put the most recent version of the config on the Kubelet, so
    // people can see how it was configured.
    klet.kubeletConfiguration = *kubeCfg
​
    // Generating the status funcs should be the last thing we do,
    // since this relies on the rest of the Kubelet having been constructed.
    klet.setNodeStatusFuncs = klet.defaultNodeStatusFuncs()
​
    return klet, nil
}
kubelet配置已经基本初始化,后续进入相关组件启动逻辑
// cmd/kubelet/app/server.go
// 启动kubelet && kubelet server
func startKubelet(k kubelet.Bootstrap, podCfg *config.PodConfig, kubeCfg *kubeletconfiginternal.KubeletConfiguration, kubeDeps *kubelet.Dependencies, enableServer bool) {
    // start the kubelet
    go k.Run(podCfg.Updates())
​
    // start the kubelet server
    if enableServer {
        go k.ListenAndServe(kubeCfg, kubeDeps.TLSOptions, kubeDeps.Auth)
    }
    if kubeCfg.ReadOnlyPort > 0 {
        go k.ListenAndServeReadOnly(net.ParseIP(kubeCfg.Address), uint(kubeCfg.ReadOnlyPort))
    }
    if utilfeature.DefaultFeatureGate.Enabled(features.KubeletPodResources) {
        go k.ListenAndServePodResources()
    }
}
// pkg/kubelet/kubelet.go
func (kl *Kubelet) Run(updates <-chan kubetypes.PodUpdate) {
    if kl.logServer == nil {
        kl.logServer = http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log/")))
    }
    if kl.kubeClient == nil {
        klog.InfoS("No API server defined - no node status update will be sent")
    }
​
    // Start the cloud provider sync manager
    if kl.cloudResourceSyncManager != nil {
        go kl.cloudResourceSyncManager.Run(wait.NeverStop)
    }
​
    if err := kl.initializeModules(); err != nil {
        kl.recorder.Eventf(kl.nodeRef, v1.EventTypeWarning, events.KubeletSetupFailed, err.Error())
        klog.ErrorS(err, "Failed to initialize internal modules")
        os.Exit(1)
    }
​
    // 启动卷管理器:启动CSIDriver Informer、...、启动卷管理器处理所有pod使用的卷使其达到预期的状态(卸载、挂载attach、卸载detach卷)
    go kl.volumeManager.Run(kl.sourcesReady, wait.NeverStop)
​
    if kl.kubeClient != nil {
        // Start syncing node status immediately, this may set up things the runtime needs to run.
        go wait.Until(kl.syncNodeStatus, kl.nodeStatusUpdateFrequency, wait.NeverStop)
        go kl.fastStatusUpdateOnce()
​
        // start syncing lease
        go kl.nodeLeaseController.Run(wait.NeverStop)
    }
    go wait.Until(kl.updateRuntimeUp, 5*time.Second, wait.NeverStop)
​
    // 初始化iptables配置
    if kl.makeIPTablesUtilChains {
        kl.initNetworkUtil()
    }
​
    // Start component sync loops.
    kl.statusManager.Start()
​
    // Start syncing RuntimeClasses if enabled.
    if kl.runtimeClassManager != nil {
        kl.runtimeClassManager.Start(wait.NeverStop)
    }
​
    // 启动pleg;定期不间断的执行relist方法请求运行时来list并对比pod中containers的状态,然后对应的生成事件
    kl.pleg.Start()
    // 启动kubelet主同步循环:监听多个channel(configCh: 配置变更的pod,plegCh: runtime cache变更,syncCh: 所有等待sync的pod,housekeepingCh: 等待清理的pod,health manager: pod或者pod中的container健康检查失败)然后分派对应的handler函数处理
    kl.syncLoop(updates, kl)
}