Kubernetes 源码分析 -- API Server 系统启动

API Server的服务

在进入代码分析之前,这里首先把API Server的服务理清,这样将会对后面的代码的分析有更好的理解,API Server中的服务架构图如下所示:

apiserver infrastructure.png

整个程序的基本过程为:

  • 命令行参数解析,参数存储在ServerRunOptions
  • 基于ServerRunOptions构建genericapiserver.Config
  • 构建master.Config
  • 构建apiextensionserver.Config,并创建API Extension Server
  • 构建Master(API Server),把API Extension Server作为代理服务,这样它会融合API Extension Server的服务
  • 构建Aggregator,把Master作为代理服务
  • 启动http非安全服务
  • 执行Aggregator的Run,启动Https安全服务

进程启动过程

kubernetes 1.10代码的启动都是采用了cobra框架,下面代码是为API Server创建一个cobra.Command。

func NewAPIServerCommand() *cobra.Command {
    s := options.NewServerRunOptions()
    cmd := &cobra.Command{
        Use: "kube-apiserver",
        Long: `The Kubernetes API server validates and configures data
for the api objects which include pods, services, replicationcontrollers, and
others. The API Server services REST operations and provides the frontend to the
cluster's shared state through which all other components interact.`,
        Run: func(cmd *cobra.Command, args []string) {
            verflag.PrintAndExitIfRequested()

            stopCh := server.SetupSignalHandler()
            if err := Run(s, stopCh); err != nil {
                fmt.Fprintf(os.Stderr, "%v\n", err)
                os.Exit(1)
            }
        },
    }
    s.AddFlags(cmd.Flags())

    return cmd
}

APIServer的启动参数存储在ServerRunOptions中,启动参数基于命令行参数进行解析。
cobra框架会自动分析命令行参数,命令行参数的解析是由s.AddFlag(cmd.Flags())中预先定义好的。在AddFlags方法中。

// AddFlags adds flags for a specific APIServer to the specified FlagSet
func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
    // Add the generic flags.
    s.GenericServerRunOptions.AddUniversalFlags(fs)
    s.Etcd.AddFlags(fs)
    s.SecureServing.AddFlags(fs)
    s.InsecureServing.AddFlags(fs)
    s.InsecureServing.AddDeprecatedFlags(fs)
    s.Audit.AddFlags(fs)
    s.Features.AddFlags(fs)
    s.Authentication.AddFlags(fs)
    s.Authorization.AddFlags(fs)
    s.CloudProvider.AddFlags(fs)
    s.StorageSerialization.AddFlags(fs)
    s.APIEnablement.AddFlags(fs)
    s.Admission.AddFlags(fs)

       ......   
    fs.BoolVar(&s.EnableAggregatorRouting, "enable-aggregator-routing", s.EnableAggregatorRouting,
        "Turns on aggregator routing requests to endoints IP rather than cluster IP.")

}

我们先来看看都有哪些常用的命令行参数被传递给了APISrever对象,下面是运行Master节点的kube-apiserver进程的命令行信息:

kube-apiserver --admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota --apiserver-count=3 --insecure-port=8080 --secure-port=6443 --insecure-bind-address=127.0.0.1 --tls-cert-file=/data/k8s/ssl/kubernetes.pem --tls-private-key-file=/data/k8s/ssl/kubernetes-key.pem --client-ca-file=/data/k8s/ssl/ca.pem --service-account-key-file=/data/k8s/ssl/kubernetes-key.pem --storage-backend=etcd3 --enable-swagger-ui --etcd-cafile=/data/k8s/ssl/ca.pem --etcd-certfile=/data/k8s/ssl/kubernetes.pem --etcd-keyfile=/data/k8s/ssl/kubernetes-key.pem --etcd-servers=https://221.228.106.151:2379,https://61.160.36.43:2379,https://58.215.170.46:2379 --kubelet-certificate-authority=/data/k8s/ssl/ca.pem --kubelet-client-certificate=/data/k8s/ssl/kubelet.pem --kubelet-client-key=/data/k8s/ssl/kubelet-key.pem --runtime-config=settings.k8s.io/v1alpha1=true --enable-bootstrap-token-auth=true --token-auth-file=/data/k8s/ssl/token.csv --allow-privileged=true --service-cluster-ip-range=10.254.0.0/16 --audit-policy-file=/data/k8s/ssl/audit-policy.yaml --audit-log-maxage=30 --audit-log-maxbackup=3 --audit-log-maxsize=100 --audit-log-path=/data/yy/log/kubeapiserver/audit.log --logtostderr=false --log-dir=/data/yy/log/kubeapiserver --v=2 --kubelet-preferred-address-types=InternalIP,ExternalIP,InternalDNS,ExternalDNS,Hostname

  • etcd相关的参数
    storage-backend、etcd-prefix、etcd-cafile、etcd-certfile、etcd-keyfile、etcd-servers
  • BuildinAuthenticationOptions相关参数
    enable-bootstrap-token-auth、token-auth-file、service-account-key-file(用于验证ServiceAccount tokens。如果没有指定,则使用tls-private-key-file)
  • AdmissionOptions相关参数
    admission-control
  • InsecureServingOptions相关参数
    insecure-port、insecure-bind-address
  • AuditOptions相关参数
    audit-policy-file、audit-log-path、audit-log-maxsize、audit-log-maxbackup、audit-log-format
  • SecureServingOptions相关参数
    bind-address、secure-port、tls-private-key-file、tls-cert-file、
  • ClientCertAuthenticationOptions相关参数
    client-ca-file
  • 公共参数
    kubelet-preferred-address-types、
    kubelet-certificate-authority、kubelet-client-key、kubelet-certificate-authority、

最终,我们会执行Command.Execute方法启动程序,它会首先解析参数,然后执行Run方法。

// Run runs the specified APIServer.  This should never exit.
func Run(runOptions *options.ServerRunOptions, stopCh <-chan struct{}) error {
    // To help debugging, immediately log version
    glog.Infof("Version: %+v", version.Get())

    server, err := CreateServerChain(runOptions, stopCh)
    if err != nil {
        return err
    }

    return server.PrepareRun().Run(stopCh)
}

构建服务器调用链

在上面的Run方法中,CreateServerChain负责构建服务器链,最终返回genericapiserver.GenericAPIServer实例,代码如下所示:

经过前面的架构分析,API Server主要工作都在CreateServerChain中完成的。

// CreateServerChain creates the apiservers connected via delegation.
func CreateServerChain(runOptions *options.ServerRunOptions, stopCh <-chan struct{}) (*genericapiserver.GenericAPIServer, error) {
       // 如果指定了SSHUser参数,CreateNodeDialer用于创建连接本机节点的相关传输方法和网络建立方法
       // 所以与本机是通过SSH隧道交互的。通常情况下,我们是没有设置SSHUser参数的。
    nodeTunneler, proxyTransport, err := CreateNodeDialer(runOptions)
    if err != nil {
        return nil, err
    }

    kubeAPIServerConfig, sharedInformers, versionedInformers, insecureServingOptions, serviceResolver, err := CreateKubeAPIServerConfig(runOptions, nodeTunneler, proxyTransport)
    if err != nil {
        return nil, err
    }

    // TPRs are enabled and not yet beta, since this these are the successor, they fall under the same enablement rule
    // If additional API servers are added, they should be gated.
    apiExtensionsConfig, err := createAPIExtensionsConfig(*kubeAPIServerConfig.GenericConfig, versionedInformers, runOptions)
    if err != nil {
        return nil, err
    }
    // API ExtensionsServer是代理用
    apiExtensionsServer, err := createAPIExtensionsServer(apiExtensionsConfig, genericapiserver.EmptyDelegate)
    if err != nil {
        return nil, err
    }

    kubeAPIServer, err := CreateKubeAPIServer(kubeAPIServerConfig, apiExtensionsServer.GenericAPIServer, sharedInformers, versionedInformers)
    if err != nil {
        return nil, err
    }

    // if we're starting up a hacked up version of this API server for a weird test case,
    // just start the API server as is because clients don't get built correctly when you do this
    if len(os.Getenv("KUBE_API_VERSIONS")) > 0 {
        if insecureServingOptions != nil {
            insecureHandlerChain := kubeserver.BuildInsecureHandlerChain(kubeAPIServer.GenericAPIServer.UnprotectedHandler(), kubeAPIServerConfig.GenericConfig)
            if err := kubeserver.NonBlockingRun(insecureServingOptions, insecureHandlerChain, kubeAPIServerConfig.GenericConfig.RequestTimeout, stopCh); err != nil {
                return nil, err
            }
        }

        return kubeAPIServer.GenericAPIServer, nil
    }

    // otherwise go down the normal path of standing the aggregator up in front of the API server
    // this wires up openapi
    kubeAPIServer.GenericAPIServer.PrepareRun()

    // This will wire up openapi for extension api server
    apiExtensionsServer.GenericAPIServer.PrepareRun()

    // aggregator comes last in the chain
    aggregatorConfig, err := createAggregatorConfig(*kubeAPIServerConfig.GenericConfig, runOptions, versionedInformers, serviceResolver, proxyTransport)
    if err != nil {
        return nil, err
    }
    aggregatorConfig.ExtraConfig.ProxyTransport = proxyTransport
    aggregatorConfig.ExtraConfig.ServiceResolver = serviceResolver
    aggregatorServer, err := createAggregatorServer(aggregatorConfig, kubeAPIServer.GenericAPIServer, apiExtensionsServer.Informers)
    if err != nil {
        // we don't need special handling for innerStopCh because the aggregator server doesn't create any go routines
        return nil, err
    }

    if insecureServingOptions != nil {
        insecureHandlerChain := kubeserver.BuildInsecureHandlerChain(aggregatorServer.GenericAPIServer.UnprotectedHandler(), kubeAPIServerConfig.GenericConfig)
        if err := kubeserver.NonBlockingRun(insecureServingOptions, insecureHandlerChain, kubeAPIServerConfig.GenericConfig.RequestTimeout, stopCh); err != nil {
            return nil, err
        }
    }

    return aggregatorServer.GenericAPIServer, nil
}

CreateServerChain完成了主要的流程,里面有几个步骤比较特殊,这里分别讲解

CreateKubeAPIServerConfig

CreateKubeAPIServerConfig负责创建Master Server的配置、以及相关的资源。

func BuildGenericConfig(s *options.ServerRunOptions, proxyTransport *http.Transport) (*genericapiserver.Config, informers.SharedInformerFactory, clientgoinformers.SharedInformerFactory, *kubeserver.InsecureServingInfo, aggregatorapiserver.ServiceResolver, error) {
    genericConfig := genericapiserver.NewConfig(legacyscheme.Codecs)        // 构建通用配置实例
        if err := s.GenericServerRunOptions.ApplyTo(genericConfig); err != nil {    // 运行参数->通用参数
        return nil, nil, nil, nil, nil, err
    }

    insecureServingOptions, err := s.InsecureServing.ApplyTo(genericConfig)     // 非安全服务属性 -> 通用参数
    if err != nil {
        return nil, nil, nil, nil, nil, err
    }
    if err := s.SecureServing.ApplyTo(genericConfig); err != nil {      // 安全服务属性 -> 通用参数
        return nil, nil, nil, nil, nil, err
    }
    if err := s.Authentication.ApplyTo(genericConfig); err != nil {     // 认证信息 -> 通用参数
        return nil, nil, nil, nil, nil, err
    }
    if err := s.Audit.ApplyTo(genericConfig); err != nil {              // 审计信息 -> 通用参数
        return nil, nil, nil, nil, nil, err
    }
    if err := s.Features.ApplyTo(genericConfig); err != nil {           // Features -> 通用参数(EnableProfiling、EnableContentionProfiling、EnableSwaggerUI)
        return nil, nil, nil, nil, nil, err
    }
    if err := s.APIEnablement.ApplyTo(genericConfig, master.DefaultAPIResourceConfigSource(), legacyscheme.Registry); err != nil {  // 启动API的资源信息,格式为  --runtime-config=api/all=false,api/v1=true
        return nil, nil, nil, nil, nil, err
    }

    // OpenAPI配置
    genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(generatedopenapi.GetOpenAPIDefinitions, legacyscheme.Scheme)
    genericConfig.OpenAPIConfig.PostProcessSpec = postProcessOpenAPISpecForBackwardCompatibility
    genericConfig.OpenAPIConfig.Info.Title = "Kubernetes"
    genericConfig.SwaggerConfig = genericapiserver.DefaultSwaggerConfig()
    genericConfig.EnableMetrics = true
    genericConfig.LongRunningFunc = filters.BasicLongRunningRequestCheck(
        sets.NewString("watch", "proxy"),
        sets.NewString("attach", "exec", "proxy", "log", "portforward"),
    )

    kubeVersion := version.Get()
    genericConfig.Version = &kubeVersion

    // 构建存储工厂实例,指定的参数中:
    // 1. s: 提供基本的Etcd的配置信息
    // 2. genericConfig.MergedResourceConfig:指定了Enable的API Resource
    storageFactory, err := BuildStorageFactory(s, genericConfig.MergedResourceConfig)
    if err != nil {
        return nil, nil, nil, nil, nil, err
    }
    // 把存储工厂实例封装存放到genericConfig.RESTOptionsGetter 变量(同时添加Etcd的健康检查方法)
    if err := s.Etcd.ApplyWithStorageFactoryTo(storageFactory, genericConfig); err != nil {
        return nil, nil, nil, nil, nil, err
    }

    // 使用protobufs用来内部交互,(外部的看来都是application/json)
    // 看来是基于Loopback的ip和端口来访问自己?????
    // Use protobufs for self-communication.
    // Since not every generic apiserver has to support protobufs, we
    // cannot default to it in generic apiserver and need to explicitly
    // set it in kube-apiserver.
    genericConfig.LoopbackClientConfig.ContentConfig.ContentType = "application/vnd.kubernetes.protobuf"

    // 生成API 客户端
    client, err := internalclientset.NewForConfig(genericConfig.LoopbackClientConfig)
    if err != nil {
        kubeAPIVersions := os.Getenv("KUBE_API_VERSIONS")
        if len(kubeAPIVersions) == 0 {
            return nil, nil, nil, nil, nil, fmt.Errorf("failed to create clientset: %v", err)
        }

        // KUBE_API_VERSIONS is used in test-update-storage-objects.sh, disabling a number of API
        // groups. This leads to a nil client above and undefined behaviour further down.
        //
        // TODO: get rid of KUBE_API_VERSIONS or define sane behaviour if set
        glog.Errorf("Failed to create clientset with KUBE_API_VERSIONS=%q. KUBE_API_VERSIONS is only for testing. Things will break.", kubeAPIVersions)
    }

    kubeClientConfig := genericConfig.LoopbackClientConfig
    // 原来创建到自己的连接的目的在这里,实现共享通知功能,这个在出了API Server的其他模块都在大量使用。
    // 资源的变化,都能够通过该功能进行通知。从而可以依据它来做出必要的响应。
    sharedInformers := informers.NewSharedInformerFactory(client, 10*time.Minute)

    // 这里生成了另外一个Client
    // TODO:需要了解一下clientgoclientset 与 internelclientset的区别在哪里
    clientgoExternalClient, err := clientgoclientset.NewForConfig(kubeClientConfig)
    if err != nil {
        return nil, nil, nil, nil, nil, fmt.Errorf("failed to create real external clientset: %v", err)
    }
    versionedInformers := clientgoinformers.NewSharedInformerFactory(clientgoExternalClient, 10*time.Minute)

    var serviceResolver aggregatorapiserver.ServiceResolver // ServiceResolver让我们找到Srevice的URI
    if s.EnableAggregatorRouting {  // EnableAggregatorRouting似乎是让所有的Service,都基于Endpoint Ip来访问,而不基于Cluster Ip
        serviceResolver = aggregatorapiserver.NewEndpointServiceResolver(
            versionedInformers.Core().V1().Services().Lister(),
            versionedInformers.Core().V1().Endpoints().Lister(),
        )
    } else {
        serviceResolver = aggregatorapiserver.NewClusterIPServiceResolver(
            versionedInformers.Core().V1().Services().Lister(),
        )
    }

    // 创建认证实例
    // 注意:可能有多种认证,最终会合并成一个对象(合并方法:在union包中,func union.New(authRequestHandlers ...authenticator.Request) authenticator.Request)
    // 支持的认证:
    // 1. 请求Header认证
    // 2. Auth文件认证
    // 3. KeyStone认证,应该是KMS吧。
    // 4. CA认证认证(也就是常用的双向认证) 【 一般的使用方式 】
    // 5. Token文件认证
    // 6. ServiceAccount认证
    // 7. Bootstrap认证。。。。。          【一般使用,生成客户端证书】
    genericConfig.Authenticator, genericConfig.OpenAPIConfig.SecurityDefinitions, err = BuildAuthenticator(s, storageFactory, client, sharedInformers)
    if err != nil {
        return nil, nil, nil, nil, nil, fmt.Errorf("invalid authentication config: %v", err)
    }

    // 创建授权实例,这块用的不多,先不折腾
    genericConfig.Authorizer, genericConfig.RuleResolver, err = BuildAuthorizer(s, sharedInformers, versionedInformers)
    if err != nil {
        return nil, nil, nil, nil, nil, fmt.Errorf("invalid authorization config: %v", err)
    }
    if !sets.NewString(s.Authorization.Modes()...).Has(modes.ModeRBAC) {
        genericConfig.DisabledPostStartHooks.Insert(rbacrest.PostStartHookName)
    }

    webhookAuthResolverWrapper := func(delegate webhookconfig.AuthenticationInfoResolver) webhookconfig.AuthenticationInfoResolver {
        return &webhookconfig.AuthenticationInfoResolverDelegator{
            ClientConfigForFunc: func(server string) (*rest.Config, error) {
                if server == "kubernetes.default.svc" {
                    return genericConfig.LoopbackClientConfig, nil
                }
                return delegate.ClientConfigFor(server)
            },
            ClientConfigForServiceFunc: func(serviceName, serviceNamespace string) (*rest.Config, error) {
                if serviceName == "kubernetes" && serviceNamespace == "default" {
                    return genericConfig.LoopbackClientConfig, nil
                }
                ret, err := delegate.ClientConfigForService(serviceName, serviceNamespace)
                if err != nil {
                    return nil, err
                }
                if proxyTransport != nil && proxyTransport.Dial != nil {
                    ret.Dial = proxyTransport.Dial
                }
                return ret, err
            },
        }
    }
    // 准入插件初始化,CloudProvider???
    // 暂时没有研究,用的少,有必要时在研究。
    pluginInitializers, err := BuildAdmissionPluginInitializers(
        s,
        client,
        sharedInformers,
        serviceResolver,
        webhookAuthResolverWrapper,
    )
    if err != nil {
        return nil, nil, nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %v", err)
    }

    err = s.Admission.ApplyTo(
        genericConfig,
        versionedInformers,
        kubeClientConfig,
        legacyscheme.Scheme,
        pluginInitializers...)
    if err != nil {
        return nil, nil, nil, nil, nil, fmt.Errorf("failed to initialize admission: %v", err)
    }

    return genericConfig, sharedInformers, versionedInformers, insecureServingOptions, serviceResolver, nil
}

BuildGenericConfig

构建Generic Config的过程,这块提供了通用配置,这块配置会被多个服务共同使用。

首先基于legacyscheme.Codecs创建一个缺省的GenericConfig实例,并把ServerRunOptions中的参数引用到GenrericConfig中,在这里构建了启动服务的基本要素:

    1. genericConfig
    1. sharedInformer: 内部版本的共享数据缓存通知器
    1. versionedInformers:基于clientgoclientset的共享缓存通知器
    1. insecureServingOptions
    1. servideResolve:服务(service资源)解析器,根据是否启用enable-aggrator-routing,来确定是基于cluster ip还是endpoint ip的解析方式
func BuildGenericConfig(s *options.ServerRunOptions, proxyTransport *http.Transport) (*genericapiserver.Config, informers.SharedInformerFactory, clientgoinformers.SharedInformerFactory, *kubeserver.InsecureServingInfo, aggregatorapiserver.ServiceResolver, error) {
    genericConfig := genericapiserver.NewConfig(legacyscheme.Codecs)        // 构建通用配置实例
        if err := s.GenericServerRunOptions.ApplyTo(genericConfig); err != nil {    // 运行参数->通用参数
        return nil, nil, nil, nil, nil, err
    }

    insecureServingOptions, err := s.InsecureServing.ApplyTo(genericConfig)     // 非安全服务属性 -> 通用参数
    if err != nil {
        return nil, nil, nil, nil, nil, err
    }
    if err := s.SecureServing.ApplyTo(genericConfig); err != nil {      // 安全服务属性 -> 通用参数
        return nil, nil, nil, nil, nil, err
    }
    if err := s.Authentication.ApplyTo(genericConfig); err != nil {     // 认证信息 -> 通用参数
        return nil, nil, nil, nil, nil, err
    }
    if err := s.Audit.ApplyTo(genericConfig); err != nil {              // 审计信息 -> 通用参数
        return nil, nil, nil, nil, nil, err
    }
    if err := s.Features.ApplyTo(genericConfig); err != nil {           // Features -> 通用参数(EnableProfiling、EnableContentionProfiling、EnableSwaggerUI)
        return nil, nil, nil, nil, nil, err
    }
    if err := s.APIEnablement.ApplyTo(genericConfig, master.DefaultAPIResourceConfigSource(), legacyscheme.Registry); err != nil {  // 启动API的资源信息,格式为  --runtime-config=api/all=false,api/v1=true
        return nil, nil, nil, nil, nil, err
    }

    // OpenAPI配置
    genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(generatedopenapi.GetOpenAPIDefinitions, legacyscheme.Scheme)
    genericConfig.OpenAPIConfig.PostProcessSpec = postProcessOpenAPISpecForBackwardCompatibility
    genericConfig.OpenAPIConfig.Info.Title = "Kubernetes"
    genericConfig.SwaggerConfig = genericapiserver.DefaultSwaggerConfig()
    genericConfig.EnableMetrics = true
    genericConfig.LongRunningFunc = filters.BasicLongRunningRequestCheck(
        sets.NewString("watch", "proxy"),
        sets.NewString("attach", "exec", "proxy", "log", "portforward"),
    )

    kubeVersion := version.Get()
    genericConfig.Version = &kubeVersion

    // 构建存储工厂实例,指定的参数中:
    // 1. s: 提供基本的Etcd的配置信息
    // 2. genericConfig.MergedResourceConfig:指定了Enable的API Resource
    storageFactory, err := BuildStorageFactory(s, genericConfig.MergedResourceConfig)
    if err != nil {
        return nil, nil, nil, nil, nil, err
    }
    // 把存储工厂实例封装存放到genericConfig.RESTOptionsGetter 变量(同时添加Etcd的健康检查方法)
    if err := s.Etcd.ApplyWithStorageFactoryTo(storageFactory, genericConfig); err != nil {
        return nil, nil, nil, nil, nil, err
    }

    // 使用protobufs用来内部交互,(外部的看来都是application/json)
    // 看来是基于Loopback的ip和端口来访问自己?????
    // Use protobufs for self-communication.
    // Since not every generic apiserver has to support protobufs, we
    // cannot default to it in generic apiserver and need to explicitly
    // set it in kube-apiserver.
    genericConfig.LoopbackClientConfig.ContentConfig.ContentType = "application/vnd.kubernetes.protobuf"

    // 生成API 客户端
    client, err := internalclientset.NewForConfig(genericConfig.LoopbackClientConfig)
    if err != nil {
        kubeAPIVersions := os.Getenv("KUBE_API_VERSIONS")
        if len(kubeAPIVersions) == 0 {
            return nil, nil, nil, nil, nil, fmt.Errorf("failed to create clientset: %v", err)
        }

        // KUBE_API_VERSIONS is used in test-update-storage-objects.sh, disabling a number of API
        // groups. This leads to a nil client above and undefined behaviour further down.
        //
        // TODO: get rid of KUBE_API_VERSIONS or define sane behaviour if set
        glog.Errorf("Failed to create clientset with KUBE_API_VERSIONS=%q. KUBE_API_VERSIONS is only for testing. Things will break.", kubeAPIVersions)
    }

    kubeClientConfig := genericConfig.LoopbackClientConfig
    // 原来创建到自己的连接的目的在这里,实现共享通知功能,这个在出了API Server的其他模块都在大量使用。
    // 资源的变化,都能够通过该功能进行通知。从而可以依据它来做出必要的响应。
    sharedInformers := informers.NewSharedInformerFactory(client, 10*time.Minute)

    // 这里生成了另外一个Client
    // TODO:需要了解一下clientgoclientset 与 internelclientset的区别在哪里
    clientgoExternalClient, err := clientgoclientset.NewForConfig(kubeClientConfig)
    if err != nil {
        return nil, nil, nil, nil, nil, fmt.Errorf("failed to create real external clientset: %v", err)
    }
    versionedInformers := clientgoinformers.NewSharedInformerFactory(clientgoExternalClient, 10*time.Minute)

    var serviceResolver aggregatorapiserver.ServiceResolver // ServiceResolver让我们找到Srevice的URI
    if s.EnableAggregatorRouting {  // EnableAggregatorRouting似乎是让所有的Service,都基于Endpoint Ip来访问,而不基于Cluster Ip
        serviceResolver = aggregatorapiserver.NewEndpointServiceResolver(
            versionedInformers.Core().V1().Services().Lister(),
            versionedInformers.Core().V1().Endpoints().Lister(),
        )
    } else {
        serviceResolver = aggregatorapiserver.NewClusterIPServiceResolver(
            versionedInformers.Core().V1().Services().Lister(),
        )
    }

    // 创建认证实例
    // 注意:可能有多种认证,最终会合并成一个对象(合并方法:在union包中,func union.New(authRequestHandlers ...authenticator.Request) authenticator.Request)
    // 支持的认证:
    // 1. 请求Header认证
    // 2. Auth文件认证
    // 3. KeyStone认证,应该是KMS吧。
    // 4. CA认证认证(也就是常用的双向认证) 【 一般的使用方式 】
    // 5. Token文件认证
    // 6. ServiceAccount认证
    // 7. Bootstrap认证。。。。。          【一般使用,生成客户端证书】
    genericConfig.Authenticator, genericConfig.OpenAPIConfig.SecurityDefinitions, err = BuildAuthenticator(s, storageFactory, client, sharedInformers)
    if err != nil {
        return nil, nil, nil, nil, nil, fmt.Errorf("invalid authentication config: %v", err)
    }
      .....

    return genericConfig, sharedInformers, versionedInformers, insecureServingOptions, serviceResolver, nil
}

存储工厂实例

存储这块会在《API Server之 Etcd存储》中讲解

构建master.Config

master.Config是API Server服务的配置。

preparedGenericAPIServer.Run -> preparedGenericAPIServer.NonBlockingRun -> GenericAPIServer.serveSecurely -> RunServer

启动服务

API Server运行了安全服务和非安全服务,不过过程都差不多,这里只分析安全服务的运行过程,最终的执行我们直到,是运行Aggrator Server实例的Run方法,在这个方法中的调用链为:

preparedGenericAPIServer.Run -> preparedGenericAPIServer.NonBlockingRun -> GenericAPIServer.serveSecurely -> RunServer

这个运行过程跟一般的http/https服务的启动过程一样,这里就不做大量篇幅来贴代码了。

后续

API Server启动的过程基本分析完了,但是还有一个很关键的地方这里没有提到,那就是API 的安装,因为这块也是API Server的关键部分,需要较大的篇幅来分析,所以准备另外写一篇文章专门分析。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容