功能介绍
API 网关
kube-apiserver
充当 Kubernetes 集群的 API 网关,接收和处理所有 API 请求。这些请求包括创建、读取、更新和删除(CRUD)操作,涉及集群中的各种资源,如 Pods、Services、Deployments 等。
身份验证与权限控制
kube-apiserver
负责对用户和服务进行身份验证和授权。它支持多种身份验证机制,包括客户端证书、Bearer Token、用户名和密码等。授权方面,kube-apiserver
使用基于角色的访问控制(RBAC)或准入控制插件来决定是否允许请求执行。
资源调度和协调
kube-apiserver
与其他核心组件(如 kube-scheduler
和 kube-controller-manager
)协作,以调度和管理集群资源。它将调度请求传递给 kube-scheduler
,并协调控制器以确保集群处于预期状态。
数据存储
kube-apiserver
通过 etcd
存储集群的所有数据,包括配置信息、状态和元数据。所有资源的创建、更新和删除操作都会记录在 etcd
中,确保数据的一致性和持久性。
API 版本控制
Kubernetes 不断演进,kube-apiserver
提供了 API 版本控制,以支持向后兼容性。它同时支持多个 API 版本(如 v1、v1beta1),允许用户和服务逐步迁移到新的 API 版本。
准入控制
kube-apiserver
使用准入控制插件来拦截请求并对其进行修改或拒绝。这些插件可以执行各种策略,如资源配额、限制命名空间使用等。常见的准入控制插件包括 NamespaceLifecycle、ResourceQuota、PodSecurityPolicy 等。
负载均衡与高可用
为了提高可用性和可靠性,kube-apiserver
通常以集群方式部署,使用负载均衡器来分配请求。这样,即使某个 kube-apiserver
实例发生故障,其他实例仍然可以继续处理请求。
日志与监控
kube-apiserver
提供详细的日志记录功能,帮助管理员监控和排查集群问题。它还支持与 Prometheus 集成,以便进行更高级的监控和警报设置。
整体架构
整体结构
整个Kubernetes技术体系由声明式API以及Controller构成,而kube-apiserver是Kubernetes的声明式api server,并为其它组件交互提供了桥梁。因此加深对kube-apiserver的理解就显得至关重要
kube-apiserver作为整个Kubernetes集群操作etcd的唯一入口,负责Kubernetes各资源的认证&鉴权,校验以及CRUD等操作,提供RESTful APIs,供其它组件调用:
kube-apiserver包含三种APIServer:
-
aggregatorServer:负责处理
apiregistration.k8s.io
组下的APIService资源请求,同时将来自用户的请求拦截转发给aggregated server(AA) -
kubeAPIServer:负责对请求的一些通用处理,包括:认证、鉴权以及各个内建资源(pod, deployment,service and etc)的REST服务等
-
apiExtensionsServer:负责CustomResourceDefinition(CRD)apiResources以及apiVersions的注册,同时处理CRD以及相应CustomResource(CR)的REST请求(如果对应CR不能被处理的话则会返回404),也是apiserver Delegation的最后一环
另外还包括bootstrap-controller,主要负责Kubernetes default apiserver service的创建以及管理。
API调用流程
kube-apiserver 与其他组件交互主要是通过对外提供 API 来实现的,可以通过调用 kube-apiserver 的接口$ curl -k https:
//<masterIP>:6443
或者通过其提供的 swagger-ui来获取,主要有以下三个 API。
-
核心群体:主要在
/api/v1
. -
命名组:其路径为
/apis/$NAME/$VERSION
. -
一些暴露系统状态的 API:如
/metrics
,/healthz
等。
API 的 URL 大致由 组成/apis/group/version/namespaces/my-ns/myresource
,其中 API 的结构大致如下图所示。
请求的完整流程如下图
此处显示了 POST 请求的示例。当请求到达kube-apiserver时,kube-apiserver首先执行http过滤器链中注册的过滤器链,该过滤器链进行一系列过滤操作,主要是鉴权、鉴权等校验操作。当过滤器链完成后,请求被路由到相应的处理程序,该处理程序主要与 etcd 交互。处理程序中的主要操作如下
Decoder
kubernetes 中的大多数资源都会有一个internal
version
,因为一个资源在整个开发过程中可能有多个版本。例如,部署将具有extensions/v1beta1
, apps/v1
. 为了避免问题,kube-apiserver 必须知道如何在每对版本之间进行转换(例如,v1⇔v1alpha1、v1⇔v1beta1、v1beta1⇔v1alpha1)。因此它使用了一个特殊的internal
version
,它是一个通用的版本,它包含了版本的所有字段并且具有所有版本的功能。解码器会先将 creater 对象转换为internal
version
,然后再转换为storage
version
,这是存储在 etcd 中时的另一个版本。
解码时,首先从HTTP路径中获取期望的版本,然后使用scheme创建一个与正确版本匹配的空对象,并使用JSON或protobuf解码器进行转换,在转换的第一步,如果用户省略了一些字段,解码器将它们设置为默认值。
Admission
解码完成后,您需要通过验证集群的全局约束并根据集群配置设置默认值来检查是否可以创建或更新对象。您可以在目录中看到所有 kube-apiserver 可以使用的全局约束插件k8s.io/kubernetes/plugin/pkg/admission
。kube-apiserver 通过将-enable-admission-plugins
参数设置为 -ValidatingAdmissionWebhook
or -MutatingAdmissionWebhook
来启动。
Validation
主要检查对象中字段的合法性。
在handler中执行完以上操作后,会执行最后一个与etcd相关的操作,POST操作会将数据写入etcd。以上在handler中的主要处理流程如下图所示。
v1beta1 ⇒ internal ⇒ | ⇒ | ⇒ v1 ⇒ json/yaml ⇒ etcd admission validation
kube-apiserver 中的组件
kube-apiserver 由 3 个组件(Aggregator、KubeAPIServer、APIExtensionServer)组成,它们通过委托依次处理请求。
-
Aggregator:暴露类似七层负载均衡的功能,除了对核心业务数据进行转发,拦也截对用户注册的扩展服务请求转发到其他用户服务器,并负责整个APIServer的Discovery功能。
-
KubeAPIServer:负责一些通用的请求处理、认证、鉴权等,以及处理每个内置资源的 REST 服务。
-
APIExtensionServer:主要处理CustomResourceDefinition(CRD)和CustomResource(CR)REST请求,是Delegation的最后一个环节,如果对应的CR不能处理,返回404。
Aggregator 和 APIExtensionsServer 分别对应扩展 APIServer 资源的两种主要方式,即 AA 和 CRD。
Aggregator 聚合器
Aggregator 通过将 APIServices 对象关联到一个 Service 来转发请求,而与之关联的 Service 类型进一步决定了请求转发的形式。聚合器由一个GenericAPIServer
和一个控制器组成,控制器保持自己的状态。主要处理组下APIService资源的GenericAPIServer
请求apiregistration
.k8s.io
。
Aggregator 除了处理资源请求外,还包含几个控制器:
-
apiserviceRegistrationController
:负责APIServices中资源的注册和删除。 -
availableConditionController
:维护APIServices的可用性状态,包括其引用的Service是否可用等。 -
autoRegistrationController
:用于维护 API 中存在的一组特定 APIService。 -
crdRegistrationController
:负责将 CRD GroupVersions 自动注册到 APIServices 中。 -
openAPIAggregationController
:将 APIServices 资源的更改同步到提供的 OpenAPI 文档。
Kubernetes 中的一些附加组件,例如 metrics-server 通过 Aggregator 的方式进行扩展,可以在真实环境中使用apiserver-builder工具轻松创建自定义资源作为 Aggregator 扩展。
启用 API 聚合
需要在 kube-apiserver 中添加以下配置以启用 API 聚合。
--proxy-client-cert-file=/etc/kubernetes/certs/proxy.crt --proxy-client-key-file=/etc/kubernetes/certs/proxy.key --requestheader-client-ca-file=/etc/kubernetes/certs/proxy-ca.crt --requestheader-allowed-names=aggregator --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User
KubeAPI 服务器
KubeAPIServer 主要提供 API Resource 操作的请求,为 kubernetes 中的许多 API 注册路由信息,暴露 RESTful API,向公众提供 kubernetes 服务。
它使集群内外的服务能够通过 RESTful API 操作 Kubernetes 中的资源。
APIExtensionServer
APIExtensionServer 是委托链的最后一层,是处理用户通过自定义资源定义的所有资源的资源服务器。
包含的控制器及其功能如下所示。
-
openapiController
: 将 crd 资源的更改同步到提供的 OpenAPI 文档中,可以访问/openapi/v2
. -
crdController
: 负责将 crd 信息注册到 apiVersions 和 apiResources 中,两者都可以通过$ kubectl api-versions
和来查看$ kubectl api-resources
。 -
namingController
:检查 crd obj 中的命名冲突,可在 crd 中查看.status.conditions
。 -
establishingController
: 检查 crd 是否处于正常状态,在 crd 中可用.status.conditions
。 -
nonStructuralSchemaController
: 检查 crd obj 结构是否正常,在 crd 中可用.status.conditions
。 -
apiApprovalController
: 检查 crd 是否遵循 kubernetes API 声明策略,在 crd 中可用.status.conditions
。 -
finalizingController
: 一个类似于finalizes的函数,与CRs的移除有关。
源码分析
源码版本
release-1.30
服务启动
启动入口
Run方法的主要逻辑是。
-
调用
NewConfig
生成kube-apiserver 需要的配置。 -
调用
CreateServerChain
构建服务调用链,判断是否启动非安全http服务器。http服务器链包含apiserver要启动的三台服务器,以及为每台服务器注册相应资源的路由。 -
调用
server
.PrepareRun
准备运行的服务,主要完成OpenAPI
路由的健康检查、生存检查和注册。 -
调用
prepared
.Run
以启动 https 服务器。
服务器使用委托模式进行初始化,基本的API Server、CustomResource和Aggregator服务通过DelegationTarget接口链接在一起,对外提供服务。
//cmd/kube-apiserver/app/server.go
// Run runs the specified APIServer. This should never exit.
func Run(opts options.CompletedOptions, stopCh <-chan struct{}) error {
// To help debugging, immediately log version
klog.Infof("Version: %+v", version.Get())
klog.InfoS("Golang settings", "GOGC", os.Getenv("GOGC"), "GOMAXPROCS", os.Getenv("GOMAXPROCS"), "GOTRACEBACK", os.Getenv("GOTRACEBACK"))
// 为 kubeAPIServer 创建配置
config, err := NewConfig(opts)
if err != nil {
return err
}
completed, err := config.Complete()
if err != nil {
return err
}
// 构建服务调用链
server, err := CreateServerChain(completed)
if err != nil {
return err
}
// 备运行的服务,主要完成OpenAPI路由的健康检查、生存检查和注册。
prepared, err := server.PrepareRun()
if err != nil {
return err
}
// 启动 https 服务器
return prepared.Run(stopCh)
}
KubeAPI服务配置构建
CreateKubeAPIServerConfig
主要目的CreateKubeAPIServerConfig
是调用buildGenericConfig
创建 genericConfig
// cmd/kube-apiserver/app/server.go
// CreateKubeAPIServerConfig creates all the resources for running the API server, but runs none of them
func CreateKubeAPIServerConfig(opts options.CompletedOptions) (
*controlplane.Config,
aggregatorapiserver.ServiceResolver,
[]admission.PluginInitializer,
error,
) {
proxyTransport := CreateProxyTransport()
// 构建 genericConfig
genericConfig, versionedInformers, storageFactory, err := controlplaneapiserver.BuildGenericConfig(
opts.CompletedOptions,
[]*runtime.Scheme{legacyscheme.Scheme, extensionsapiserver.Scheme, aggregatorscheme.Scheme},
generatedopenapi.GetOpenAPIDefinitions,
)
if err != nil {
return nil, nil, nil, err
}
// 初始化所支持的 capabilities
capabilities.Setup(opts.AllowPrivileged, opts.MaxConnectionBytesPerSec)
opts.Metrics.Apply()
serviceaccount.RegisterMetrics()
// 构建控制面配置结构
config := &controlplane.Config{
// 通用配置
GenericConfig: genericConfig,
// 扩展配置
ExtraConfig: controlplane.ExtraConfig{
APIResourceConfigSource: storageFactory.APIResourceConfigSource,
StorageFactory: storageFactory,
EventTTL: opts.EventTTL,
KubeletClientConfig: opts.KubeletConfig,
EnableLogsSupport: opts.EnableLogsHandler,
ProxyTransport: proxyTransport,
ServiceIPRange: opts.PrimaryServiceClusterIPRange,
APIServerServiceIP: opts.APIServerServiceIP,
SecondaryServiceIPRange: opts.SecondaryServiceClusterIPRange,
APIServerServicePort: 443,
ServiceNodePortRange: opts.ServiceNodePortRange,
KubernetesServiceNodePort: opts.KubernetesServiceNodePort,
EndpointReconcilerType: reconcilers.Type(opts.EndpointReconcilerType),
MasterCount: opts.MasterCount,
ServiceAccountIssuer: opts.ServiceAccountIssuer,
ServiceAccountMaxExpiration: opts.ServiceAccountTokenMaxExpiration,
ExtendExpiration: opts.Authentication.ServiceAccounts.ExtendExpiration,
VersionedInformers: versionedInformers,
},
}
// ...
return config, serviceResolver, pluginInitializers, nil
}
通用配置构建
BuildGenericConfig
主要逻辑如下。
-
调用
genericapiserver
.NewConfig
生成默认的genericConfig,genericConfig主要配置DefaultBuildHandlerChain
,DefaultBuildHandlerChain
包含一系列用于认证、鉴权、鉴权的http过滤器链,以及一系列http过滤器链。 -
调用
master
.DefaultAPIResourceConfigSource
加载需要启用的API资源,在k8s.io/api
代码目录下可以看到集群中所有的API资源,随着版本的迭代也会不断变化。 -
为 genericConfig 中的一些字段设置默认值。
-
调用
completedStorageFactoryConfig
.New
创建 storageFactory,稍后会使用它为每个 API Resource 创建对应的 RESTStorage。
// pkg/controlplane/apiserver/config.go
// BuildGenericConfig takes the master server options and produces the genericapiserver.Config associated with it
func BuildGenericConfig(
s controlplaneapiserver.CompletedOptions,
schemes []*runtime.Scheme,
getOpenAPIDefinitions func(ref openapicommon.ReferenceCallback) map[string]openapicommon.OpenAPIDefinition,
) (
genericConfig *genericapiserver.Config,
versionedInformers clientgoinformers.SharedInformerFactory,
storageFactory *serverstorage.DefaultStorageFactory,
lastErr error,
) {
genericConfig = genericapiserver.NewConfig(legacyscheme.Codecs)
//为 genericConfig 设置默认值
genericConfig.MergedResourceConfig = controlplane.DefaultAPIResourceConfigSource()
if lastErr = s.GenericServerRunOptions.ApplyTo(genericConfig); lastErr != nil {
return
}
if lastErr = s.SecureServing.ApplyTo(&genericConfig.SecureServing, &genericConfig.LoopbackClientConfig); lastErr != nil {
return
}
// 设置使用 protobufs 用来内部交互,并且禁用压缩功能
// 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"
// Disable compression for self-communication, since we are going to be
// on a fast local network
genericConfig.LoopbackClientConfig.DisableCompression = true
kubeClientConfig := genericConfig.LoopbackClientConfig
clientgoExternalClient, err := clientgoclientset.NewForConfig(kubeClientConfig)
if err != nil {
lastErr = fmt.Errorf("failed to create real external clientset: %v", err)
return
}
versionedInformers = clientgoinformers.NewSharedInformerFactory(clientgoExternalClient, 10*time.Minute)
if lastErr = s.Features.ApplyTo(genericConfig, clientgoExternalClient, versionedInformers); lastErr != nil {
return
}
if lastErr = s.APIEnablement.ApplyTo(genericConfig, controlplane.DefaultAPIResourceConfigSource(), legacyscheme.Scheme); lastErr != nil {
return
}
if lastErr = s.EgressSelector.ApplyTo(genericConfig); lastErr != nil {
return
}
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerTracing) {
if lastErr = s.Traces.ApplyTo(genericConfig.EgressSelector, genericConfig); lastErr != nil {
return
}
}
// wrap the definitions to revert any changes from disabled features
getOpenAPIDefinitions = openapi.GetOpenAPIDefinitionsWithoutDisabledFeatures(getOpenAPIDefinitions)
namer := openapinamer.NewDefinitionNamer(schemes...)
genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(getOpenAPIDefinitions, namer)
genericConfig.OpenAPIConfig.Info.Title = "Kubernetes"
genericConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config(getOpenAPIDefinitions, namer)
genericConfig.OpenAPIV3Config.Info.Title = "Kubernetes"
genericConfig.LongRunningFunc = filters.BasicLongRunningRequestCheck(
sets.NewString("watch", "proxy"),
sets.NewString("attach", "exec", "proxy", "log", "portforward"),
)
kubeVersion := version.Get()
genericConfig.Version = &kubeVersion
if genericConfig.EgressSelector != nil {
s.Etcd.StorageConfig.Transport.EgressLookup = genericConfig.EgressSelector.Lookup
}
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerTracing) {
s.Etcd.StorageConfig.Transport.TracerProvider = genericConfig.TracerProvider
} else {
s.Etcd.StorageConfig.Transport.TracerProvider = oteltrace.NewNoopTracerProvider()
}
// // 初始化 storageFactory
storageFactoryConfig := kubeapiserver.NewStorageFactoryConfig()
storageFactoryConfig.APIResourceConfig = genericConfig.MergedResourceConfig
storageFactory, lastErr = storageFactoryConfig.Complete(s.Etcd).New()
if lastErr != nil {
return
}
// 初始化 RESTOptionsGetter,后期根据其获取操作 Etcd 的句柄,同时添加 etcd 的健康检查方法
if lastErr = s.Etcd.ApplyWithStorageFactoryTo(storageFactory, genericConfig); lastErr != nil {
return
}
ctx := wait.ContextForChannel(genericConfig.DrainedNotify())
// 创建认证实例,支持多种认证方式:请求 Header 认证、Auth 文件认证、CA 证书认证、
// Bearer token 认证、
// ServiceAccount 认证、BootstrapToken 认证、WebhookToken 认证等
// Authentication.ApplyTo requires already applied OpenAPIConfig and EgressSelector if present
if lastErr = s.Authentication.ApplyTo(ctx, &genericConfig.Authentication, genericConfig.SecureServing, genericConfig.EgressSelector, genericConfig.OpenAPIConfig, genericConfig.OpenAPIV3Config, clientgoExternalClient, versionedInformers, genericConfig.APIServerID); lastErr != nil {
return
}
var enablesRBAC bool
// 创建鉴权实例,包含:Node、RBAC、Webhook、ABAC、AlwaysAllow、AlwaysDeny
genericConfig.Authorization.Authorizer, genericConfig.RuleResolver, enablesRBAC, err = BuildAuthorizer(
ctx,
s,
genericConfig.EgressSelector,
genericConfig.APIServerID,
versionedInformers,
)
if err != nil {
lastErr = fmt.Errorf("invalid authorization config: %v", err)
return
}
if s.Authorization != nil && !enablesRBAC {
genericConfig.DisabledPostStartHooks.Insert(rbacrest.PostStartHookName)
}
lastErr = s.Audit.ApplyTo(genericConfig)
if lastErr != nil {
return
}
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.AggregatedDiscoveryEndpoint) {
genericConfig.AggregatedDiscoveryGroupManager = aggregated.NewResourceManager("apis")
}
return
}
服务初始化
CreateServerChain
CreateServerChain
是完成服务端初始化的方法,包含初始化,最后返回实例的所有过程APIExtensionsServer
,初始化过程主要包括:http过滤链的配置,API Group的注册,http路径与handler的关联以及处理程序后端存储 etcd 的配置。主要逻辑如下。KubeAPIServerAggregatorServeraggregatorapiserver. APIAggregator
-
调用创建KubeAPIServer需要的配置
CreateKubeAPIServerConfig
,主要是createmaster
.Config
,会调用buildGenericConfig
生成genericConfig,其中包含apiserver核心配置的核心配置。 -
确定是否启用了扩展 API 服务器并调用
createAPIExtensionsConfig
为其创建配置。apiExtensions server 是 kubeapiserver 中其他服务器的代理服务,例如 metric-server。 -
调用
createAPIExtensionsServer
以创建 apiExtensionsServer 的实例。 -
调用
CreateKubeAPIServer
以初始化 kubeAPIServer。 -
调用
createAggregatorConfig
以创建 aggregatorServer 的配置并调用createAggregatorServer
以初始化 aggregatorServer。 -
配置并确定是否启动非安全http服务器。
-
KubeAPIServer:
-
KubeAPIServer
是 Kubernetes 的核心组件之一,它是 Kubernetes API 服务器的实现,负责处理集群中所有 API 请求。 -
它提供了对 Kubernetes 集群的访问和管理,包括创建、更新和删除资源对象,例如 Pods、Deployments、Services 等。
-
KubeAPIServer
扮演着集群的“大脑”,负责控制整个集群的状态和配置。
-
-
APIExtensionsServer:
-
APIExtensionsServer
是负责管理 Kubernetes 的 API 扩展的组件,它允许用户通过自定义资源定义 (Custom Resource Definitions, CRDs) 来扩展 Kubernetes API。 -
使用
APIExtensionsServer
,用户可以定义自己的资源类型,从而为 Kubernetes 添加新的 API 资源和控制器。 -
这些自定义资源类型可以像内置资源(如 Pods、Services 等)一样被创建、更新和删除,而它们的行为由用户编写的控制器来定义。
-
/// cmd/kube-apiserver/app/server.go
// CreateServerChain creates the apiservers connected via delegation.
func CreateServerChain(config CompletedConfig) (*aggregatorapiserver.APIAggregator, error) {
notFoundHandler := notfoundhandler.New(config.ControlPlane.GenericConfig.Serializer, genericapifilters.NoMuxAndDiscoveryIncompleteKey)
//判断是否配置了 APIExtensionsServer,创建 apiExtensionsConfig
apiExtensionsServer, err := config.ApiExtensions.New(genericapiserver.NewEmptyDelegateWithCustomHandler(notFoundHandler))
if err != nil {
return nil, err
}
// 判断crd api 是否enbale, 表示是否支持用户扩展api
crdAPIEnabled := config.ApiExtensions.GenericConfig.MergedResourceConfig.ResourceEnabled(apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions"))
// 初始化 KubeAPIServer
kubeAPIServer, err := config.ControlPlane.New(apiExtensionsServer.GenericAPIServer)
if err != nil {
return nil, err
}
// 初始化 AggregatorServer 对API进行聚合
// aggregator comes last in the chain
aggregatorServer, err := createAggregatorServer(config.Aggregator, kubeAPIServer.GenericAPIServer, apiExtensionsServer.Informers, crdAPIEnabled)
if err != nil {
// we don't need special handling for innerStopCh because the aggregator server doesn't create any go routines
return nil, err
}
return aggregatorServer, nil
}
KubeAPI服务初始化
kubeAPIServerConfig.Complete().New
主要逻辑如下。
-
调用 GenericAPIServer 初始化 GenericAPIServer,
c
.GenericConfig.New
上面分析了它的主要实现。 -
判断是否支持日志相关路由,如果支持,添加
/logs
路由。 -
调用
m
.InstallLegacyAPI
将核心 API 资源添加到路由中,该路由对应 apiserver 作为以 . 开头的资源/api
。 -
调用
m
.InstallAPIs
以将扩展 API 资源添加到路由,在 apiserver 中是以 . 开头的资源/apis
。
// pkg/controlplane/instance.go
// New returns a new instance of Master from the given config.
// Certain config fields will be set to a default value if unset.
// Certain config fields must be specified, including:
// KubeletClientConfig
func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget) (*Instance, error) {
if reflect.DeepEqual(c.ExtraConfig.KubeletClientConfig, kubeletclient.KubeletClientConfig{}) {
return nil, fmt.Errorf("Master.New() called with empty config.KubeletClientConfig")
}
// 初始化 GenericAPIServer
s, err := c.GenericConfig.New("kube-apiserver", delegationTarget)
if err != nil {
return nil, err
}
// 注册 logs 相关的路由
if c.ExtraConfig.EnableLogsSupport {
routes.Logs{}.Install(s.Handler.GoRestfulContainer)
}
// Metadata and keys are expected to only change across restarts at present,
// so we just marshal immediately and serve the cached JSON bytes.
md, err := serviceaccount.NewOpenIDMetadata(
c.ExtraConfig.ServiceAccountIssuerURL,
c.ExtraConfig.ServiceAccountJWKSURI,
c.GenericConfig.ExternalAddress,
c.ExtraConfig.ServiceAccountPublicKeys,
)
if err != nil {
// If there was an error, skip installing the endpoints and log the
// error, but continue on. We don't return the error because the
// metadata responses require additional, backwards incompatible
// validation of command-line options.
msg := fmt.Sprintf("Could not construct pre-rendered responses for"+
" ServiceAccountIssuerDiscovery endpoints. Endpoints will not be"+
" enabled. Error: %v", err)
if c.ExtraConfig.ServiceAccountIssuerURL != "" {
// The user likely expects this feature to be enabled if issuer URL is
// set and the feature gate is enabled. In the future, if there is no
// longer a feature gate and issuer URL is not set, the user may not
// expect this feature to be enabled. We log the former case as an Error
// and the latter case as an Info.
klog.Error(msg)
} else {
klog.Info(msg)
}
} else {
routes.NewOpenIDMetadataServer(md.ConfigJSON, md.PublicKeysetJSON).
Install(s.Handler.GoRestfulContainer)
}
m := &Instance{
GenericAPIServer: s,
ClusterAuthenticationInfo: c.ExtraConfig.ClusterAuthenticationInfo,
}
clientset, err := kubernetes.NewForConfig(c.GenericConfig.LoopbackClientConfig)
if err != nil {
return nil, err
}
// 安装 LegacyAPI, 注册了核心API
// TODO: update to a version that caches success but will recheck on failure, unlike memcache discovery
discoveryClientForAdmissionRegistration := clientset.Discovery()
legacyRESTStorageProvider, err := corerest.New(corerest.Config{
GenericConfig: corerest.GenericConfig{
StorageFactory: c.ExtraConfig.StorageFactory,
EventTTL: c.ExtraConfig.EventTTL,
LoopbackClientConfig: c.GenericConfig.LoopbackClientConfig,
ServiceAccountIssuer: c.ExtraConfig.ServiceAccountIssuer,
ExtendExpiration: c.ExtraConfig.ExtendExpiration,
ServiceAccountMaxExpiration: c.ExtraConfig.ServiceAccountMaxExpiration,
APIAudiences: c.GenericConfig.Authentication.APIAudiences,
Informers: c.ExtraConfig.VersionedInformers,
},
Proxy: corerest.ProxyConfig{
Transport: c.ExtraConfig.ProxyTransport,
KubeletClientConfig: c.ExtraConfig.KubeletClientConfig,
},
Services: corerest.ServicesConfig{
ClusterIPRange: c.ExtraConfig.ServiceIPRange,
SecondaryClusterIPRange: c.ExtraConfig.SecondaryServiceIPRange,
NodePortRange: c.ExtraConfig.ServiceNodePortRange,
IPRepairInterval: c.ExtraConfig.RepairServicesInterval,
},
})
if err != nil {
return nil, err
}
// The order here is preserved in discovery.
// If resources with identical names exist in more than one of these groups (e.g. "deployments.apps"" and "deployments.extensions"),
// the order of this list determines which group an unqualified resource name (e.g. "deployments") should prefer.
// This priority order is used for local discovery, but it ends up aggregated in `k8s.io/kubernetes/cmd/kube-apiserver/app/aggregator.go
// with specific priorities.
// TODO: describe the priority all the way down in the RESTStorageProviders and plumb it back through the various discovery
// handlers that we have.
restStorageProviders := []RESTStorageProvider{
legacyRESTStorageProvider,
apiserverinternalrest.StorageProvider{},
authenticationrest.RESTStorageProvider{Authenticator: c.GenericConfig.Authentication.Authenticator, APIAudiences: c.GenericConfig.Authentication.APIAudiences},
authorizationrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorization.Authorizer, RuleResolver: c.GenericConfig.RuleResolver},
autoscalingrest.RESTStorageProvider{},
batchrest.RESTStorageProvider{},
certificatesrest.RESTStorageProvider{},
coordinationrest.RESTStorageProvider{},
discoveryrest.StorageProvider{},
networkingrest.RESTStorageProvider{},
noderest.RESTStorageProvider{},
policyrest.RESTStorageProvider{},
rbacrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorization.Authorizer},
schedulingrest.RESTStorageProvider{},
storagerest.RESTStorageProvider{},
svmrest.RESTStorageProvider{},
flowcontrolrest.RESTStorageProvider{InformerFactory: c.GenericConfig.SharedInformerFactory},
// keep apps after extensions so legacy clients resolve the extensions versions of shared resource names.
// See https://github.com/kubernetes/kubernetes/issues/42392
appsrest.StorageProvider{},
admissionregistrationrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorization.Authorizer, DiscoveryClient: discoveryClientForAdmissionRegistration},
eventsrest.RESTStorageProvider{TTL: c.ExtraConfig.EventTTL},
resourcerest.RESTStorageProvider{},
}
// 安装API
if err := m.InstallAPIs(c.ExtraConfig.APIResourceConfigSource, c.GenericConfig.RESTOptionsGetter, restStorageProviders...); err != nil {
return nil, err
}
// ...
return m, nil
}
KubeAPI安装API
InstallAPIs方法的主要作用是将核心API注册到路由中,是apiserver初始化过程中最核心的方法之一,但是它的调用链很深,下面会深入分析。将API注册到路由的最终目的是提供外部RESTful API来操作对应的资源,注册API主要分为两步,第一步是为API中的每个资源初始化RESTStorage来操作变更对于后端存储中的数据,第二步是根据每个资源的动词构建对应的路由第二步是根据每个资源的动词构建对应的路由。的主要逻辑如下。
-
调用
RESTStorage
为 每个资源创建 RESTStorage。RESTStorage 的目的是对应每个资源的访问路径及其在后端存储中的操作。 -
为资源创建 RESTStorage 后,调用
m
.GenericAPIServer.InstallAPIGroup
为 APIGroup 注册路由信息。方法的调用链InstallAPIGroup
很深,主要是InstallLegacyAPIGroup
--> installAPIResources --> InstallREST --> Install --> registerResourceHandlers
,而最终的核心路由构建在registerResourceHandlers
方法中,比较复杂,它的主要作用是确定哪些操作(如创建、更新等)可以通过通过上一步构建的REST Storage获取资源,并将对应的操作存储到action中,每个action对应一个标准最后,根据actions数组,每个action都会添加一个handler方法并注册到路由中,然后该路由将注册到网络服务。Web 服务最终将按照 go-restful 设计模式注册到容器中。
// pkg/controlplane/instance.go
// InstallAPIs will install the APIs for the restStorageProviders if they are enabled.
func (m *Instance) InstallAPIs(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter, restStorageProviders ...RESTStorageProvider) error {
nonLegacy := []*genericapiserver.APIGroupInfo{}
// used later in the loop to filter the served resource by those that have expired.
resourceExpirationEvaluator, err := genericapiserver.NewResourceExpirationEvaluator(*m.GenericAPIServer.Version)
if err != nil {
return err
}
for _, restStorageBuilder := range restStorageProviders {
groupName := restStorageBuilder.GroupName()
// 每个资源创建 RESTStorag
apiGroupInfo, err := restStorageBuilder.NewRESTStorage(apiResourceConfigSource, restOptionsGetter)
if err != nil {
return fmt.Errorf("problem initializing API group %q : %v", groupName, err)
}
if len(apiGroupInfo.VersionedResourcesStorageMap) == 0 {
// If we have no storage for any resource configured, this API group is effectively disabled.
// This can happen when an entire API group, version, or development-stage (alpha, beta, GA) is disabled.
klog.Infof("API group %q is not enabled, skipping.", groupName)
continue
}
// Remove resources that serving kinds that are removed.
// We do this here so that we don't accidentally serve versions without resources or openapi information that for kinds we don't serve.
// This is a spot above the construction of individual storage handlers so that no sig accidentally forgets to check.
resourceExpirationEvaluator.RemoveDeletedKinds(groupName, apiGroupInfo.Scheme, apiGroupInfo.VersionedResourcesStorageMap)
if len(apiGroupInfo.VersionedResourcesStorageMap) == 0 {
klog.V(1).Infof("Removing API group %v because it is time to stop serving it because it has no versions per APILifecycle.", groupName)
continue
}
klog.V(1).Infof("Enabling API group %q.", groupName)
if postHookProvider, ok := restStorageBuilder.(genericapiserver.PostStartHookProvider); ok {
name, hook, err := postHookProvider.PostStartHook()
if err != nil {
klog.Fatalf("Error building PostStartHook: %v", err)
}
m.GenericAPIServer.AddPostStartHookOrDie(name, hook)
}
if len(groupName) == 0 {
// the legacy group for core APIs is special that it is installed into /api via this special install method.
if err := m.GenericAPIServer.InstallLegacyAPIGroup(genericapiserver.DefaultLegacyAPIPrefix, &apiGroupInfo); err != nil {
return fmt.Errorf("error in registering legacy API: %w", err)
}
} else {
// everything else goes to /apis
nonLegacy = append(nonLegacy, &apiGroupInfo)
}
}
//它的主要作用是确定哪些操作(如创建、更新等)可以通过通过上一步构建的REST Storage获取资源,
//并将对应的操作存储到action中,每个action对应一个标准最后,根据actions数组,
//每个action都会添加一个handler方法并注册到路由中,
//然后该路由将注册到网络服务。Web 服务最终将按照 go-restful 设计模式注册到容器中。
if err := m.GenericAPIServer.InstallAPIGroups(nonLegacy...); err != nil {
return fmt.Errorf("error in registering group versions: %v", err)
}
return nil
}
APIExtensions服务初始化
APIExtensionsServer 最先被初始化,通过如下逻辑调用初始化apiextensionsConfig
.Complete
()
.New
服务器createAPIExtensionsServer
。
-
首先调用
c
.GenericConfig.New
根据go-restful
模式初始化Container,在c
.GenericConfig.New
调用NewAPIServerHandler
中初始化handler,APIServerHandler是APIServer使用的Handler类型,包括go-restful
andnon-go-restful
,和一个你在两者之间选择的Director对象,go-restful
用来处理注册的handler和non-go restful
是用于处理不存在的处理程序,API URI 处理的选择过程是:FullHandlerChain-> Director -> {GoRestfulContainer, NonGoRestfulMux}
. 在c
.GenericConfig.New
,installAPI
中也调用添加路由信息包括/
,/debug/*
,/metrics
,/version
等。这三种服务器都是通过调用c
.GenericConfig.New
初始化genericServer然后注册API来初始化的。 -
调用
s
.GenericAPIServer.InstallAPIGroup
注册路由中的API资源,这个方法的调用链很深,主要是注册要暴露给服务端的API资源,从而可以通过http接口对资源进行REST操作。其他几个服务器也在InstallAPI
初始化期间执行相应的操作。 -
初始化服务器中需要用到的控制器,主要是
openapiController
,crdController
,namingController
,establishingController
,nonStructuralSchemaController
,apiApprovalController
,finalizingControlle
r。 -
将需要启动的控制器和通知器添加到 PostStartHook。
// staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/apiserver.go
// New returns a new instance of Cu