启动篇-01配置加载与校验

NewKebeletCommand

cmd/kubelet/app/server.go
// NewKubeletCommand 创建一个带有默认参数的 *cobra.Command 对象
func NewKubeletCommand() *cobra.Command {
    // 解析命令行标识
    cleanFlagSet := pflag.NewFlagSet(componentKubelet, pflag.ContinueOnError)
    cleanFlagSet.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
    // 创建一个带默认值的 KubeletFlags 对象
    kubeletFlags := options.NewKubeletFlags()
    // 创建一个带默认值的 KubeletConfiguration 对象
    kubeletConfig, err := options.NewKubeletConfiguration()
    // programmer error
    if err != nil {
        klog.ErrorS(err, "Failed to create a new kubelet configuration")
        os.Exit(1)
    }

    cmd := &cobra.Command{
        ...
        // kubelet 有特殊的标识解析要求来强制执行标识优先级规则,因此我们在下面的 Run 中手动执行所有解析
        // DisableFlagParsing=true 提供了传递给 kubelet 的完整标识集合,而不受 Cobra 干扰
        DisableFlagParsing: true,
        SilenceUsage:       true,
        RunE: func(cmd *cobra.Command, args []string) error {
            // 解析标识
            if err := cleanFlagSet.Parse(args); err != nil {
                return fmt.Errorf("failed to parse kubelet flag: %w", err)
            }

            // 检查是否有非法标识
            cmds := cleanFlagSet.Args()
            if len(cmds) > 0 {
                return fmt.Errorf("unknown command %+s", cmds[0])
            }

            // 遇到 help 直接打印并返回
            help, err := cleanFlagSet.GetBool("help")
            if err != nil {
                return errors.New(`"help" flag is non-bool, programmer error, please correct`)
            }
            if help {
                return cmd.Help()
            }

            // 遇到 version 直接打印并返回
            verflag.PrintAndExitIfRequested()

            // 根据配置文件设置 feature gates
            if err := utilfeature.DefaultMutableFeatureGate.SetFromMap(kubeletConfig.FeatureGates); err != nil {
                return fmt.Errorf("failed to set feature gates from initial flags-based config: %w", err)
            }

            // 验证 kubeletFlags 是否合法
            if err := options.ValidateKubeletFlags(kubeletFlags); err != nil {
                return fmt.Errorf("failed to validate kubelet flags: %w", err)
            }

            // 检查 Infra 容器是否修改,已弃用,将在 1.27 删除,需要通过 CRI 设置
            if cleanFlagSet.Changed("pod-infra-container-image") {
                klog.InfoS("--pod-infra-container-image will not be pruned by the image garbage collector in kubelet and should also be set in the remote runtime")
            }

            // 如果有 kubelet 配置文件,则加载
            if configFile := kubeletFlags.KubeletConfigFile; len(configFile) > 0 {
                kubeletConfig, err = loadConfigFile(configFile)
                if err != nil {
                    return fmt.Errorf("failed to load kubelet config file, error: %w, path: %s", err, configFile)
                }
                // 重新解析标识以设置标识优先级,详细信息查看 issue # 56171
                if err := kubeletConfigFlagPrecedence(kubeletConfig, args); err != nil {
                    return fmt.Errorf("failed to precedence kubeletConfigFlag: %w", err)
                }
                // 根据新配置更新 feature gates
                if err := utilfeature.DefaultMutableFeatureGate.SetFromMap(kubeletConfig.FeatureGates); err != nil {
                    return fmt.Errorf("failed to set feature gates from initial flags-based config: %w", err)
                }
            }

            // 配置和标识解析完成后,现在我们可以初始化 log 了
            logs.InitLogs()
            if err := logsapi.ValidateAndApplyAsField(&kubeletConfig.Logging, utilfeature.DefaultFeatureGate, field.NewPath("logging")); err != nil {
                return fmt.Errorf("initialize logging: %v", err)
            }
            cliflag.PrintFlags(cleanFlagSet)

            // 验证本地配置,也是最终配置,动态配置已在 1.22 弃用且在 1.24 中删除
            if err := kubeletconfigvalidation.ValidateKubeletConfiguration(kubeletConfig, utilfeature.DefaultFeatureGate); err != nil {
                return fmt.Errorf("failed to validate kubelet configuration, error: %w, path: %s", err, kubeletConfig)
            }

            if (kubeletConfig.KubeletCgroups != "" && kubeletConfig.KubeReservedCgroup != "") && (strings.Index(kubeletConfig.KubeletCgroups, kubeletConfig.KubeReservedCgroup) != 0) {
                klog.InfoS("unsupported configuration:KubeletCgroups is not within KubeReservedCgroup")
            }

            // 构建 kubeletServer,包括 KubeletFlags 和 KubeletConfiguration
            kubeletServer := &options.KubeletServer{
                KubeletFlags:         *kubeletFlags,
                KubeletConfiguration: *kubeletConfig,
            }

            // 构建默认 KubeletDeps
            kubeletDeps, err := UnsecuredDependencies(kubeletServer, utilfeature.DefaultFeatureGate)
            if err != nil {
                return fmt.Errorf("failed to construct kubelet dependencies: %w", err)
            }

            if err := checkPermissions(); err != nil {
                klog.ErrorS(err, "kubelet running with insufficient permissions")
            }

            // 生成 log 打印需要的 kubelet 配置
            config := kubeletServer.KubeletConfiguration.DeepCopy()
            for k := range config.StaticPodURLHeader {
                config.StaticPodURLHeader[k] = []string{"<masked>"}
            }
            // 打印 kubelet 配置用于验证
            klog.V(5).InfoS("KubeletConfiguration", "configuration", config)

            // 设置 kubelet 的 ctx,用于 kubelet 终止
            ctx := genericapiserver.SetupSignalContext()

            utilfeature.DefaultMutableFeatureGate.AddMetrics()
            // 运行 kubelet,执行 Run 方法,进入下一阶段
            return Run(ctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
        },
    }

    // 隔离 cleanFlagSet 使其不会被全局标识污染
    kubeletFlags.AddFlags(cleanFlagSet)
    options.AddKubeletConfigFlags(cleanFlagSet, kubeletConfig)
    options.AddGlobalFlags(cleanFlagSet)
    cleanFlagSet.BoolP("help", "h", false, fmt.Sprintf("help for %s", cmd.Name()))

    // ugly,但是必须这样,因为 Cobra 的默认 UsageFunc 和 HelpFunc 会污染全局标识
    const usageFmt = "Usage:\n  %s\n\nFlags:\n%s"
    cmd.SetUsageFunc(func(cmd *cobra.Command) error {
        fmt.Fprintf(cmd.OutOrStderr(), usageFmt, cmd.UseLine(), cleanFlagSet.FlagUsagesWrapped(2))
        return nil
    })
    cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
        fmt.Fprintf(cmd.OutOrStdout(), "%s\n\n"+usageFmt, cmd.Long, cmd.UseLine(), cleanFlagSet.FlagUsagesWrapped(2))
    })

    return cmd
}

NewKubeletFlags

NewKubeletConfiguration

NewSchemeAndCodecs

最后更新于

这有帮助吗?