Kubernetes Apiserver介绍一启动流程

167 阅读2分钟
  • apiserver 启动流程
  • CreateServerChain创建3个server
    • CreateKubeAPIServer创建 kubeAPIServer代表 API核心服务,包括常见的Pod/Deployment/Service
    • createAPIExtensionsServer创建 apiExtensionsServer 代表API扩展服务,主要针对CRD
    • createAggregatorServer创建aggregatorServer 代表 处理metrics的服务

apiserver 启动流程

入口地址

  • 位置 cmd\kube-apiserver\apiserver.go
  • 初始化apiserver的cmd并执行
package main

import (
   "os"
   _ "time/tzdata" // for timeZone support in CronJob

   "k8s.io/component-base/cli"
   _ "k8s.io/component-base/logs/json/register"          // for JSON log format registration
   _ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugins
   _ "k8s.io/component-base/metrics/prometheus/version"  // for version metric registration
   "k8s.io/kubernetes/cmd/kube-apiserver/app"
)

func main() {
   command := app.NewAPIServerCommand()
   code := cli.Run(command)
   os.Exit(code)
}

newCmd执行流程

  • 之前我们说过cobra的几个func执行顺序
	// The *Run functions are executed in the following order:
	//   * PersistentPreRun()
	//   * PreRun()
	//   * Run()
	//   * PostRun()
	//   * PersistentPostRun()
	// All functions get the same args, the arguments after the command name.
	//

PersistentPreRunE 准备

  • 设置WarningHandler
		PersistentPreRunE: func(*cobra.Command, []string) error {
			// silence client-go warnings.
			// kube-apiserver loopback clients should not log self-issued warnings.
			rest.SetDefaultWarningHandler(rest.NoWarnings{})
			return nil
		},

runE解析 准备工作

  • 打印版本信息
verflag.PrintAndExitIfRequested()
...
func PrintAndExitIfRequested() {
	if *versionFlag == VersionRaw {
		fmt.Printf("%#v\n", version.Get())
		os.Exit(0)
	} else if *versionFlag == VersionTrue {
		fmt.Printf("%s %s\n", programName, version.Get())
		os.Exit(0)
	}
}

  • 打印命令行参数
			fs := cmd.Flags()
			cliflag.PrintFlags(fs)
// PrintFlags logs the flags in the flagset
func PrintFlags(flags *pflag.FlagSet) {
	flags.VisitAll(func(flag *pflag.Flag) {
		klog.V(1).Infof("FLAG: --%s=%q", flag.Name, flag.Value)
	})
}

  • 检查不安全的端口
err := checkNonZeroInsecurePort(fs)

// TODO: delete this check after insecure flags removed in v1.24
func checkNonZeroInsecurePort(fs *pflag.FlagSet) error {
	for _, name := range options.InsecurePortFlags {
		val, err := fs.GetInt(name)
		if err != nil {
			return err
		}
		if val != 0 {
			return fmt.Errorf("invalid port value %d: only zero is allowed", val)
		}
	}
	return nil
}
  • Complete设置默认值
completedOptions, err := Complete(s)
  • 检查命令行参数
			if errs := completedOptions.Validate(); len(errs) != 0 {
				return utilerrors.NewAggregate(errs)
			}
// D:\go_path\src\github.com\kubernetes\kubernetes\cmd\kube-apiserver\app\options\validation.go


// Validate checks ServerRunOptions and return a slice of found errs.
func (s *ServerRunOptions) Validate() []error {
	var errs []error
	if s.MasterCount <= 0 {
		errs = append(errs, fmt.Errorf("--apiserver-count should be a positive number, but value '%d' provided", s.MasterCount))
	}
	errs = append(errs, s.Etcd.Validate()...)
	errs = append(errs, validateClusterIPFlags(s)...)
	errs = append(errs, validateServiceNodePort(s)...)
	errs = append(errs, validateAPIPriorityAndFairness(s)...)
	errs = append(errs, s.SecureServing.Validate()...)
	errs = append(errs, s.Authentication.Validate()...)
	errs = append(errs, s.Authorization.Validate()...)
	errs = append(errs, s.Audit.Validate()...)
	errs = append(errs, s.Admission.Validate()...)
	errs = append(errs, s.APIEnablement.Validate(legacyscheme.Scheme, apiextensionsapiserver.Scheme, aggregatorscheme.Scheme)...)
	errs = append(errs, validateTokenRequest(s)...)
	errs = append(errs, s.Metrics.Validate()...)
	errs = append(errs, s.Logs.Validate()...)
	errs = append(errs, validateAPIServerIdentity(s)...)

	return errs
}

  • 举一个例子,比如这个校验etcd的 src\k8s.io\apiserver\pkg\server\options\etcd.go
func (s *EtcdOptions) Validate() []error {
	if s == nil {
		return nil
	}

	allErrors := []error{}
    // 校验 etcd-serversdizhi 
	if len(s.StorageConfig.Transport.ServerList) == 0 {
		allErrors = append(allErrors, fmt.Errorf("--etcd-servers must be specified"))
	}

	if s.StorageConfig.Type != storagebackend.StorageTypeUnset && !storageTypes.Has(s.StorageConfig.Type) {
		allErrors = append(allErrors, fmt.Errorf("--storage-backend invalid, allowed values: %s. If not specified, it will default to 'etcd3'", strings.Join(storageTypes.List(), ", ")))
	}

	for _, override := range s.EtcdServersOverrides {
		tokens := strings.Split(override, "#")
		if len(tokens) != 2 {
			allErrors = append(allErrors, fmt.Errorf("--etcd-servers-overrides invalid, must be of format: group/resource#servers, where servers are URLs, semicolon separated"))
			continue
		}

		apiresource := strings.Split(tokens[0], "/")
		if len(apiresource) != 2 {
			allErrors = append(allErrors, fmt.Errorf("--etcd-servers-overrides invalid, must be of format: group/resource#servers, where servers are URLs, semicolon separated"))
			continue
		}

	}

	return allErrors
}