参考
- Kubernetes 源码剖析(书籍)
- kube-apiserver的设计与实现 - 自记小屋
kube-apiserver 核心思想
-
APIGroupInfo 记录 GVK 与 Storage 的对应关系
- 将 GVK 转换成,Restful HTTP Path
- 将 Storage 封装成 HTTP Handler
- 将上面两个形成映射,实现相关的路由处理
-
发起请求并处理的流程
- 发送请求:通过 GVK 对应的 Restful HTTP Path 发送请求(对 k8s 资源的操作)
- 认证:经过认证插件,判断是否为合法用户
- 鉴权(或叫授权):经过鉴权插件,判断该用户是否有权限操作此资源
- 准入控制:先执行已配置的 mutating 变更准入控制插件(修改用户提交的资源对象信息,如新增 label 等),再执行已配置 Validating 验证准入控制插件(验证用户提交的资源对象信息,如是否具有某个 label 等)
- 在此过程中好像涉及 Schema Validation,不清楚此处作用(没有定位到,后续若找到,再补充)
- 执行(存储):经过以上流程,会到达 Handler 转换为对应的资源 Storage 结构,然后读取 Storage 中的存储配置信息,然后存储到 etcd 数据库中(若配置了加密,将在存入 etcd 之前,对资源对象信息进行加密)
- 在存入之前,好像会转换为资源的某一特定版本或内部版本(没有定位到,后续若找到,再补充)
kube-apiserver 架构详解
-
APIExtensionsServer、KubeAPIServer、AggregatorServer 中的每个都是一个接口服务器(用于处理不同类型资源的请求),运行时可以理解为是 kube-apiserver 的 3 个进程
- APIExtensionsServer:处理对 CRD 资源的请求,其 Scheme 记录关注的 CRD 资源相关信息
- KubeAPIServer: 处理对 k8s 核心资源(如 core 组)的请求,其 Scheme 记录关注的 k8s 核心资源相关信息
- AggregatorServer:处理对用户额外引入的资源(如通过 APIService 注册外部的 Server 或集群内的其他服务)的请求,其 Scheme 记录用户注册资源的相关信息
-
但以上三种 Server 都依赖于 GenericAPIServer(通用服务器),该 Server 进行一些基础通用配置,并将负责各类 Server 的启动
Master 结构在 1.24.3 版本改为 Instance 结构
路径: pkg/controlplane/instance.go
kube-apiserver 启动流程
在kube-apiserver组件启动过程中,代码逻辑可分为9个步骤,分 别介绍如下。
(1)资源注册。 (2)Cobra命令行参数解析。 (3)创建APIServer通用配置。 (4)创建APIExtensionsServer。 (5)创建KubeAPIServer。(6)创建AggregatorServer。 (7)创建GenericAPIServer。 (8)启动HTTP服务。 (9)启动HTTPS服务。
资源注册
kube-apiserver组件启动后的第一件事情是将Kubernetes所支持 的资源注册到Scheme资源注册表中, 这样后面启动的逻辑才能够从 Scheme 资 源 注 册 表 中 拿 到 资 源 信 息 并 启 动 和 运 行 APIExtensionsServer 、 KubeAPIServer 、 AggregatorServer 这 3 种 服 务。
资源的注册过程并不是通过函数调用触发的, 而是通过Go语言的 导入(import)和初始化(init)机制触发的
- import 某 package,会自动完成该 package 下 const、 var和init函数的初始化
- import 按顺序执行
- 若多层 import,先执行最下层的,再执行上层的
- Pkg A import B --> pkg B import C --> pkg C import D
- 先执行 pkg D 的 const、 var和init函数,再执行 pkg C 的 const、 var和init函数,然后 B 的 const、 var和init函数,最后 A 的 const、 var和init函数
- Pkg A import B --> pkg B import C --> pkg C import D
kube-apiserver 的 import 信息 | cmd/kube-apiserver/app/server.go | |
import “k8s.io/kubernetes/pkg/api/legacyscheme” | 初始化 k8s 核心资源注册表 legacyscheme.Scheme | |
import “k8s.io/kubernetes/pkg/controlplane” | 2. 注册 k8s 核心资源到 legacyscheme.Scheme 中 | |
第1步细化 | pkg/api/legacyscheme/scheme.go | legacyscheme 包中全局变量 Scheme 初始化 |
第2步细化 | pkg/controlplane/import_known_versions.go | 注册所有 |
除将KubeAPIServer(API核心服务)注册至legacyscheme.Scheme资源注册表以外,还需要了解APIExtensionsServer和AggregatorServer资源注册过程。
●将APIExtensionsServer(API扩展服务)注册至extensionsapiserver.Scheme资源注册表,注册过程定义在vendor/k8s.io/apiextensionsapiserver/pkg/apiserver/apiserver.go中。
●将AggregatorServer(API聚合服务)注册至aggregatorscheme.Scheme资源注册表,注册过程定义在vendor/k8s.io/kubeaggregator/pkg/apiserver/scheme/scheme.go中。
- 下面代码为 k8s 核心资源注册表(legacyscheme.Scheme)的详细初始化和注册流程
// 0. kube-apiserver 的 import 信息
// cmd/kube-apiserver/app/server.go
package app
import (
"k8s.io/kubernetes/pkg/api/legacyscheme" // ymjx: 初始化 k8s 核心资源注册表 legacyscheme.Scheme
"k8s.io/kubernetes/pkg/controlplane" // ymjx: 注册 k8s 核心资源到 legacyscheme.Scheme 中
)
// 1. 初始化 k8s 核心资源注册表全局变量 Scheme,之后别的包可通过 legacyscheme.Scheme 进行引用,从而获知到 k8s 核心资源信息
// pkg/api/legacyscheme/scheme.go
package legacyscheme
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
)
var (
// Scheme is the default instance of runtime.Scheme to which types in the Kubernetes API are already registered.
// NOTE: If you are copying this file to start a new api group, STOP! Copy the
// extensions group instead. This Scheme is special and should appear ONLY in
// the api group, unless you really know what you're doing.
// TODO(lavalamp): make the above error impossible.
Scheme = runtime.NewScheme()
// Codecs provides access to encoding and decoding for the scheme
Codecs = serializer.NewCodecFactory(Scheme)
// ParameterCodec handles versioning of objects that are converted to query parameters.
ParameterCodec = runtime.NewParameterCodec(Scheme)
)
// 2. 将 k8s 所有核心资源信息通过 各个资源的 install 包信息中 init 函数,注册到 legacyscheme.Scheme 中
// pkg/controlplane/import_known_versions.go
package controlplane
import (
// These imports are the API groups the API server will support.
_ "k8s.io/kubernetes/pkg/apis/admission/install"
_ "k8s.io/kubernetes/pkg/apis/admissionregistration/install"
_ "k8s.io/kubernetes/pkg/apis/apiserverinternal/install"
_ "k8s.io/kubernetes/pkg/apis/apps/install"
_ "k8s.io/kubernetes/pkg/apis/authentication/install"
_ "k8s.io/kubernetes/pkg/apis/authorization/install"
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
_ "k8s.io/kubernetes/pkg/apis/batch/install"
_ "k8s.io/kubernetes/pkg/apis/certificates/install"
_ "k8s.io/kubernetes/pkg/apis/coordination/install"
_ "k8s.io/kubernetes/pkg/apis/core/install"
_ "k8s.io/kubernetes/pkg/apis/discovery/install"
_ "k8s.io/kubernetes/pkg/apis/events/install"
_ "k8s.io/kubernetes/pkg/apis/extensions/install"
_ "k8s.io/kubernetes/pkg/apis/flowcontrol/install"
_ "k8s.io/kubernetes/pkg/apis/imagepolicy/install"
_ "k8s.io/kubernetes/pkg/apis/networking/install"
_ "k8s.io/kubernetes/pkg/apis/node/install"
_ "k8s.io/kubernetes/pkg/apis/policy/install"
_ "k8s.io/kubernetes/pkg/apis/rbac/install"
_ "k8s.io/kubernetes/pkg/apis/scheduling/install"
_ "k8s.io/kubernetes/pkg/apis/storage/install"
)
// 3. 举例,core 组的资源注册到 legacyscheme.Scheme 中
// pkg/apis/core/install/install.go
package install
import (
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/v1"
)
func init() {
Install(legacyscheme.Scheme)
}
// Install registers the API group and adds types to a scheme
func Install(scheme *runtime.Scheme) {
// ymjx: 如果有多 个资源版本,排在最前面的为资源首选版本
utilruntime.Must(core.AddToScheme(scheme)) // ymjx: core.AddToScheme函数注册了core资源组内部版本的资源
utilruntime.Must(v1.AddToScheme(scheme)) // ymjx: v1.AddToScheme函数注册了core资源组外部版本的资源
utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion)) // ymjx: scheme.SetVersionPriority函数注册了资源组的版本顺序
}
Cobra命令行参数解析
cmd/kube-apiserver/app/server.go | NewAPIServerCommand | 该命令是 kube-apiserver 的启动命令,下面都是解析该函数内部的函数 |
s := options.NewServerRunOptions() | 初始化各个模块的默认配置, 例如初始化Etcd、Audit、Admission等模块的默认配置 |
|
completedOptions, err := Complete(s) | 通过Complete函数填充默认的配置参数 | |
completedOptions.Validate() | 通过Validate函数验证配置参数的合法性和可用性 | |
Run(completedOptions, genericapiserver.SetupSignalHandler()) | 最后将ServerRunOptions(kube-apiserver组件的运行配置)对象传入Run函数,Run函数定义了kube-apiserver组件启动的逻辑,它是一个运行不退出的常驻进程。 |
创建APIServer通用配置
APIServer通用配置是kube-apiserver不同模块实例化所需的配置,APIServer通用配置流程
生成通用配置 调用逻辑 |
cmd/kube-apiserver/app/server.go | NewAPIServerCommand --> RunE --> Run --> CreateServerChain –> CreateKubeAPIServerConfig --> buildGenericConfig |
通用配置通过此函数读取, 其他APIServer 之后直接进行引用,不需要再次读取 |
kubeAPIServerConfig, … := CreateKubeAPIServerConfig(completedOptions) | |
APIExtensionsServer 配置信息,引用已创建的通用配置 | createAPIExtensionsConfig(*kubeAPIServerConfig.GenericConfig, …) | |
AggregatorServer 配置信息,引用已创建的通用配置 | createAggregatorConfig(*kubeAPIServerConfig.GenericConfig …) |
- 接着上面分析,此处详细分析通用配置都做了些什么
cmd/kube-apiserver/app/server.go | buildGenericConfig | 接下来详细分析如何构建通用配置 |
1. 实例化genericConfig对象,并注册 handler | genericapiserver.NewConfig(legacyscheme.Codecs) | 实例化genericConfig对象, 并为genericConfig对象设置默认值 该实例化过程包含个重要函数 DefaultBuildHandlerChain 该函数注册了多个handler,用于认证、授权等 |
2. 设置启用和禁用 Group/Version | genericConfig.MergedResourceConfig = controlplane.DefaultAPIResourceConfigSource() | genericConfig.MergedResourceConfig用于设置启用/禁用GV(资源组、资源版本)及其Resource(资源) 如果未在命令行参数中指定启用/禁用的GV,则通过master.DefaultAPIResourceConfigSource启用默认设置的GV及其资源。master.DefaultAPIResourceConfigSource将启用资源版本为Stable和Beta的资源,默认不启用Alpha资源版本的资源。通过EnableVersions函数启用指定资源,而通过DisableVersions函数禁用指定资源 |
3. OpenAPI 相关配置 | genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig( … ) | genericConfig.OpenAPIConfig用于生成OpenAPI规范。 在默认的 情况下, 通过DefaultOpenAPIConfig函数为其设置默认值 |
4. 构建 etcd 存储配置信息对象 storageFactoryConfig |
storageFactoryConfig := kubeapiserver.NewStorageFactoryConfig() storageFactoryConfig.Complete(s.Etcd) |
kubeapiserver.NewStorageFactoryConfig 函 数 实 例 化 了 storageFactoryConfig对象, 该对象定义了kube-apiserver与Etcd的 交互方式, 例如Etcd认证、 Etcd地址、 存储前缀等。 另外, 该对象也 定义了资源存储方式,例如资源信息、资源编码类型、资源状态等 storageFactoryConfig.Complete 读取 apiserver 配置的 etcd 加密信息 |
5. 构建 etcd 存储对象 genericConfig.RESTOptionsGetter |
storageFactory, lastErr = completedStorageFactoryConfig.New() s.Etcd.ApplyWithStorageFactoryTo(storageFactory, genericConfig) |
根据上面获取的 storageFactoryConfig 配置信息,创建存储通用配置对象 storageFactory 将 storageFactory 存到了 genericConfig.RESTOptionsGetter 字段中 |
6. 认证配置 genericConfig.Authentication(认证相关信息) genericConfig.Authenti-cation.Authenticator(认证器列表) |
s.Authentication.ApplyTo(&genericConfig.Authentication …) 调用authInfo.Authenticator, openAPIConfig.SecurityDefinitions, err = authenticatorConfig.New() |
kube-apiserver目前提供了9种认证机制, 分别是BasicAuth、 ClientCA 、 TokenAuth 、 BootstrapToken 、 RequestHeader 、 WebhookTokenAuth、 Anonymous、 OIDC、 ServiceAccountAuth。 每一种 认证机制被实例化后会成为认证器(Authenticator),每一个认证器 都被封装在http.Handler请求处理函数中, 它们接收组件或客户端的 请求并认证请求。 该函数会生成认证器,其会调用authenticatorConfig.New函数,该函数会在在实例化认证器的过程中,会根据认证的配置信息(由flags命令行参数传入)决定是否启用认证方法,并对启用的认证方法生成对应的HTTPHandler函数,最后通过union函数将已启用的认证器合并到authenticators数组对象中 authenticators中存放的是已启用的认证器列表。union.New函数 将authenticators合并成一个authenticator认证器,实际上将认证器 列表存放在union结构的Handlers []authenticator.Request对象中。 当客户端请求到达kube-apiserver时, kube-apiserver会遍历认证器 列表, 尝试执行每个认证器, 当有一个认证器返回true时, 则认证成 功。 |
7. 鉴权配置 genericConfig.Authorization.Authorizer (授权器列表) genericConfig.RuleResolver(授权规则解析器) |
BuildAuthorizer(s, genericConfig.EgressSelector, versionedInformers) | 在Kubernetes系统组件或客户端请求通过认证阶段之后, 会来到 授权阶段。 kube-apiserver同样支持多种授权机制, 并支持同时开启 多个授权功能,客户端发起一个请求,在经过授权阶段时,只要有一 个授权器通过则授权成功。 kube-apiserver目前提供了6种授权机制, 分别是AlwaysAllow、 AlwaysDeny、Webhook、Node、ABAC、RBAC。每一种授权机制被实例化 后 会 成 为 授 权 器 ( Authorizer ) , 每 一 个 授 权 器 都 被 封 装 在 http.Handler请求处理函数中, 它们接收组件或客户端的请求并授权 请求。kube-apiserver通过BuildAuthorizer函数实例化授权器, authorizationConfig.New函数在实例化授权器的过程中, 会根 据–authorization-mode参数的配置信息(由flags命令行参数传入) 决 定 是 否 启 用 授 权 方 法 , 并 对 启 用 的 授 权 方 法 生 成 对 应 的 HTTP Handler 函 数 , 最 后 通 过 union 函 数 将 已 启 用 的 授 权 器 合 并 到 authorizers数组对象中 authorizers中存放的是已启用的授权器列表, ruleResolvers中 存放的是已启用的授权器规则解析器,实际上分别将它们存放在union 结构的[]authorizer.Authorizer和[]authorizer.RuleResolver对象 中。 当客户端请求到达kube-apiserver时, kube-apiserver会遍历授 权器列表,并按照顺序执行授权器,排在前面的授权器具有更高的优 先级(允许或拒绝请求)。 客户端发起一个请求, 在经过授权阶段 时,只要有一个授权器通过,则授权成功。 |
8. Admission 准入控制器配置 | cmd/kube-apiserver/app/server.go NewAPIServerCommand --> options.NewServerRunOptions() --> kubeoptions.NewAdmissionOptions() --> NewAdmissionOptions() 该函数中的如下两个函数实现了所有准入控制器的注册 genericoptions.NewAdmissionOptions()(该函数还包含准入控制器存储结构 Plugins 的初始化) RegisterAllAdmissionPlugins(options.Plugins) |
Kubernetes系统组件或客户端请求通过授权阶段之后, 会来到准 入控制器阶段,它会在认证和授权请求之后,对象被持久化之前,拦 截kube-apiserver的请求, 拦截后的请求进入准入控制器中处理, 对 请求的资源对象进行自定义(校验、 修改或拒绝)等操作。 kubeapiserver支持多种准入控制器机制,并支持同时开启多个准入控制器 功能,如果开启了多个准入控制器,则按照顺序执行准入控制器 kube-apiserver在启动时注册所有准入控制器, 准入控制器通过 Plugins数据结构统一注册、 存放、 管理所有的准入控制器。 vendor/k8s.io/apiserver/pkg/server /options/admission.go vendor/k8s.io/apiserver/pkg/server/plugins.go |
创建APIExtensionsServer
具体流程介绍如下。 (1)创建GenericAPIServer。 (2)实例化CustomResourceDefinitions。(3)实例化APIGroupInfo,将资源版本、资源、资源存储对象进 行相互映射。
( 4 ) InstallAPIGroup 注 册 APIGroup(apiextensions.k8s.io)。
生成通用配置 调用逻辑 |
cmd/kube-apiserver/app/server.go | NewAPIServerCommand --> RunE --> Run --> CreateServerChain –> createAPIExtensionsServer --> apiextensionsConfig.Complete().New(delegateAPIServer) |
genericServer, err := c.GenericConfig.New(“apiextensions-apiserver”, delegationTarget) | APIExtensionsServer的运行依赖于GenericAPIServer,通过c.GenericConfig.New函数创建名为apiextensions-apiserver的服务 | |
s := &CustomResourceDefinitions{ GenericAPIServer: genericServer, } | APIExtensionsServer(API扩展服务)通过CustomResourceDefinitions对象进行管理,实例化该对象后才能注册APIExtensionsServer下的资源 | |
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(…) | APIGroupInfo 对 象 用 于 描 述 资 源 组 信 息 , 其 中 该 对 象 的 VersionedResourcesStorageMap字段用于存储资源与资源存储对象的 对应关系,其表现形式为map[string]map[string]rest.Storage(即< 资 源 版 本 >/< 资 源 >/< 资 源 存 储 对 象 > ) , 例 如 CustomResourceDefinitions 资 源 与 资 源 存 储 对 象 的 映 射 关 系 是 v1beta1/customresourcedefinitions/customResourceDefintionStor age | |
重要的函数 | NewREST | 每个资源(包括子资源)都通过类似于NewREST的函数创建资源存 储对象(即RESTStorage) |
InstallAPIGroup | 将 APIGroupInfo对象中的<资源组>/<资源版本>/<资源>/<子资源>(包括 资源存储对象)注册到APIExtensionsServerHandler函数。 其过程是 遍历APIGroupInfo, 将<资源组>/<资源版本>/<资源名称>映射到HTTP PATH请求路径, 通过InstallREST函数将资源存储对象作为资源的 Handlers方法, 最后使用go-restful的ws.Route将定义好的请求路径 和 Handlers 方 法 添 加 路 由 到 go-restful 中 。 整 个 过 程 为 InstallAPIGroup→s.installAPIResources→InstallREST | |
InstallREST | InstallREST函数接收restful.Container指针对象。 安装过程分 为4步,分别介绍如下。 ( 1 ) prefix 定 义 了 HTTP PATH 请 求 路 径 , 其 表 现 形 式 为 <apiPrefix>/<group>/<version>(即/apis/apiextensions.k8s.io/v1beta1)。 (2)实例化APIInstaller安装器。 ( 3 ) 在 installer.Install 安 装 器 内 部 创 建 一 个 go-restful WebService, 然后通过a.registerResourceHandlers函数, 为资源注 册对应的Handlers方法(即资源存储对象Resource Storage), 完成 资源与资源Handlers方法的绑定并为go-restful WebService添加该路 由。 ( 4 ) 最 后 通 过 container.Add 函 数 将 WebService 添 加 到 gorestful Container中。 APIExtensionsServer负责管理apiextensions.k8s.io资源组下的 所有资源, 该资源有v1beta1版本。 通过访问http://127.0.0.1: 8080/apis/apiextensions.k8s.io/v1获得该资源/子资源的详细信 息 |
创建KubeAPIServer
调用逻辑 | cmd/kube-apiserver/app/server.go | NewAPIServerCommand --> RunE --> Run --> CreateServerChain –> CreateKubeAPIServer |
创建KubeAPIServer的流程与创建APIExtensionsServer的流程类 似,其原理都是将<资源组>/<资源版本>/<资源>与资源存储对象进行 映 射 并 将 其 存 储 至 APIGroupInfo 对 象 的 VersionedResourcesStorageMap字段中。 通过installer.Install安装 器 为 资 源 注 册 对 应 的 Handlers 方 法 ( 即 资 源 存 储 对 象 Resource Storage), 完成资源与资源Handlers方法的绑定并为go-restful WebService 添 加 该 路 由 。 最 后 将 WebService 添 加 到 go-restful Container中。创建KubeAPIServer的流程如图7-17所示。
创建KubeAPIServer的流程说明如下。
- 创建GenericAPIServer。
- 实例化 Instance( 旧版本叫 Master)。
- InstallLegacyAPI注册/api资源。(没有组名的资源,pod 的组名就为空,该组也叫作核心组 core group)
- KubeAPIServer会先判断CoreGroups/v1(即核心资源组/资源版本)是否已启用,如果其已启用,则通过m.InstallLegacyAPI函数将CoreGroups/v1注册到KubeAPIServer的/api/v1下。可以通过访问http://127.0.0.1:8080/api/v1获得CoreGroups/v1下的资源与子资源信息。
- InstallAPIs注册/apis资源。(有组名的资源,如 deployment 在 apps group 中)
- 通过m.InstallAPIsI函数将【拥有组名的资源组】注册到KubeAPIServer的/apis下。可以通过访问http://localhost:8080/apis/apps/v1/deployments获得其下的资源与子资源信息。
创建AggregatorServer
同样,创建AggregatorServer的流程与创建APIExtensionsServer的流程类似,其原理都是将<资源组>/<资源版本>/<资源>与资源存储对象进行映射并将其存储至APIGroupInfo对象的VersionedResourcesStorageMap字段中。通过installer.Install安装器为资源注册对应的Handlers方法(即资源存储对象ResourceStorage),完成资源与资源Handlers方法的绑定并为go-restfulWebService添加该路由。最后将WebService添加到go-restfulContainer中。
AggregatorServer负责管理apiregistration.k8s.io资源组下的 所 有 资 源 , 这 些 资 源 有 v1beta1 和 v1 版 本 , 通 过 访 问 http://127.0.0.1:8080/apis/apiregistration.k8s.io/v1可以获得 资源/子资源的详细信息
创建GenericAPIServer(小结,分析上面三种Server异同)
- 上面小结
相同的注册流程 | |
---|---|
1实例化APIGroupInfo对象 | APIGroupInfo 对 象 用 于 描 述 资 源 组 信 息 ( group , version ,scheme,NegotiatedSerializer,ParameterCodec 等) 其中该对象的VersionedResourcesStorageMap字段用于存储资源与资源存储对象的对应关系,其表现形式为map[string]map[string]rest.Storage(即<资源版本>/<资源>/<资源存储对象>),例如CustomResourceDefinitions资源与资源存储对象的映射关系是v1beta1/customresourcedefinitions/customResourceDefintionStorage。 |
2创建资源存储对象RESTStorage | 每个资源(包括子资源)都通过类似于NewREST的函数创建资源存 储对象(即RESTStorage) (注意:一个资源组对应一个APIGroupInfo对象,该资源组内的每个资源(包括子资源)对应一个资源存储对象RESTStorage。) |
3InstallAPIGroup 注 册 APIGroupInfo | 该过程非常重要,将APIGroupInfo对象中的<资源组>/<资源版本>/<资源>/<子资源>(包括资源存储对象)注册到APIExtensionsServerHandler函数。其过程是遍历APIGroupInfo,将<资源组>/<资源版本>/<资源名称>映射到HTTPPATH请求路径,通过InstallREST函数将资源存储对象作为资源的Handlers方法,最后使用go-restful的ws.Route将定义好的请求路径和Handlers方法添加路由到go-restful中。整个过程为InstallAPIGroup→s.installAPIResources→InstallREST |
资源的操作 | kube-apiserver将RESTStorage封装成HTTPHandler函数,资源存储对象以RESTful的方式运行,一个RESTStorage对象负责一个资源的增、删、改、查操作。当操作XX资源数据时,通过对应的RESTStorage资源存储对象与genericregistry.Store进行交互 |
不同点 | |
APIExtensionsServer | 关注CustomResourceDefinitions资源数据 APIExtensionsServer负责管理apiextensions.k8s.io资源组下的所有资源,该资源有v1beta1版本。通过访问http://127.0.0.1:8080/apis/apiextensions.k8s.io/v1获得该资源/子资源的详细信息 |
KubeAPIServer | 关注 k8s 核心资源数据 KubeAPIServer负责管理众多资源组,以apps资源组为例,通过访问http://127.0.0.1:8080/apis/apps/v1可以获得该资源/子资源的详细信息。 【有组名前缀为 /apis】通过m.InstallAPIs函数将拥有组名的资源组注册到KubeAPIServer的/apis下。可以通过访问http://localhost:8080/apis/apps/v1/deployments获得其下的资源与子资源信息。 【没有组名前缀为 /api】KubeAPIServer会先判断CoreGroups/v1(即核心资源组/资源版本)是否已启用,如果其已启用,则通过m.InstallLegacyAPI函数将CoreGroups/v1注册到KubeAPIServer的/api/v1下。可以通过访问http://127.0.0.1:8080/api/v1获得CoreGroups/v1下的资源与子资源信息。 |
AggregatorServer | 关注 ApiService 资源数据 AggregatorServer负责管理apiregistration.k8s.io资源组下的所有资源,这些资源有v1beta1和v1版本,通过访问http://127.0.0.1:8080/apis/apiregistration.k8s.io/v1可以获得资源/子资源的详细信息 |
底层共同依赖 | 无论创建APIExtensionsServer、KubeAPIServer,还是AggregatorServer,它们在底层都依赖于GenericAPIServer。通过GenericAPIServer将Kubernetes资源与RESTAPI进行映射 |
通 过 c.GenericConfig.New 函 数 创 建 GenericAPIServer 。 在 NewAPIServerHandler函数的内部, 通过restful.NewContainer创建 restful Container实例,并设置Router路由 | |
NewAPIServerCommand --> RunE --> Run --> CreateServerChain –> createAPIExtensionsServer --> apiextensionsConfig.Complete().New --> c.GenericConfig.New --> NewAPIServerHandler 和 installAPI(s, c.Config) 通 过 c.GenericConfig.New 函 数 创 建 GenericAPIServer 。 - 在 NewAPIServerHandler函数的内部, 通过restful.NewContainer创建 restful Container实例,并设置Router路由 - installAPI通过routes注册GenericAPIServer的相关API |
启动HTTP服务
- 好像废弃了,没有找到此部分的调用逻辑
路径 | staging/src/k8s.io/apiserver/pkg/server/deprecated_insecure_serving.go | func (s *DeprecatedInsecureServingInfo) Serve |
启动HTTPS服务
调用逻辑 | cmd/kube-apiserver/app/server.go | NewAPIServerCommand --> RunE --> Run --> prepared.Run(stopCh) --> s.runnable.Run(stopCh) --> func (s preparedGenericAPIServer) Run --> s.NonBlockingRun(stopHttpServerCh, shutdownTimeout) --> s.SecureServingInfo.Serve(s.Handler, shutdownTimeout, internalStopCh) |
HTTPS服务在http.Server上增加了TLSConfig配置, TLSConfig用 于配置相关证书, 可以通过命令行相关参数(–client-ca-file、 -tls-private-key-file、–tls-cert-file参数)进行配置。 |
权限控制
kube-apiserver (Kubernetes API Server)作为Kubernetes集群的请求入口,接收集群中组件与客户端的访问请求,kube-apiserver 对接口请求访问,提供了3种安全权限控制,每个请求都需要经过认证、授权及准入控制器才有权限操作资源对象。Kubernetes ApI Server权限控制如图7-20所示。
Kubernetes 支持3种安全权限控制,分别介绍如下。
•认证:针对请求的认证,确认是否具有访问Kubernetes集群的权限。
•授权:针对资源的授权,确认是否对资源具有相关权限。
•准入控制器:在认证和授权之后,对象被特久化之前,拦截 kube-apiserver的请求,拦截后的请求进入准入控制器中处理,对请求的资源对象进行自定义(校验、修改或拒绝)等操作。
认证
在开启HTTPS服务后,所有的请求都需要经过认证。kubeapiserver支持多种认证机制,并支持同时开启多个认证功能。当客户端发起一个请求,经过认证阶段时,只要有一个认证器通过,则认证成功。如果认证成功,用户名就会传入授权阶段做进一步的授权验证,而对于认证失败的请求则返回HTTP 401状态码。
kube-apiserver目前提供了9种认证机制,分别是BasicAuth、 ClientCA 、 TokenAuth 、 BootstrapToken 、 RequestHeader、WebhookTokenAuth、 Anonymous、 OIDC、 ServiceAccountAuth。 每一种 认证机制被实例化后会成为认证器(Authenticator),每一个认证器 都被封装在http.Handler请求处理函数中, 它们接收组件或客户端的 请求并认证请求。 当客户端请求通过认证器并返回true时, 则表示认 证通过。认证流程如图7-21所示。
假 设 所 有 的 认 证 器 都 被 启 用 , 当 客 户 端 发 送 请 求 到 kubeapiserver服务,该请求会进入Authentication Handler函数(处理认 证相关的Handler函数),在Authentication Handler函数中,会遍历已启用的认证器列表, 尝试执行每个认证器, 当有一个认证器返回 true时,则认证成功,否则继续尝试下一个认证器。
WithAuthentication函数可以作为kube-apiserver的认证Handler 函数。 如果auth认证器为空, 说明kube-apiserver未启用任何认证功 能;如果其不为空, 则通过auth.AuthenticateRequest函数对请求进 行认证。 如果身份认证失败, 则通过failed.ServeHTTP函数返回HTTP 401 Unauthorized, 表示认证被拒绝;如果身份认证成功, 则不再需 要Authorization请求头并进入授权阶段。
# 接口
vendor/k8s.io/apiserver/pkg/authentication/authenticator/interfaces.go
# 接口的调用
vendor/k8s.io/apiserver/pkg/server/config.go
# DefaultBuildHandlerChain
vendor/k8s.io/apiserver/pkg/endpoints/filters/authentication.go
授权
在客户端请求通过认证之后, 会来到授权阶段。 kube-apiserver 同样也支持多种授权机制,并支持同时开启多个授权功能,如果开启 多个授权功能,则按照顺序执行授权器,在前面的授权器具有更高的 优先级来允许或拒绝请求。 客户端发起一个请求, 在经过授权阶段 后,只要有一个授权器通过则授权成功。
kube-apiserver目前提供了6种授权机制, 分别是AlwaysAllow、 AlwaysDeny 、 ABAC 、 Webhook 、 RBAC 、 Node , 可 通 过 指 定 -authorization-mode参数设置授权机制。
● AlwaysAllow :允许所有请求。
● AlwaysDeny :阻止所有请求。
● ABAC :即Attribute-Based Access Control, 基于属性的访问控制。
●Webhook :基于Webhook的一种HTTP协议回调, 可进行远程授 权管理。
● RBAC:即Role-Based Access Control, 基于角色的访问控 制。
● Node :节点授权,专门授权给kubelet发出的API请求。
每一种授权机制被实例化后会成为授权器(Authorizer), 每一 个授权器都被封装在http.Handler函数中, 它们接收组件或客户端的 请求并授权请求。 当客户端请求到达kube-apiserver的授权器, 并返 回DecisionAllow决策状态时,则表示授权成功。
上面的WithAuthorization函数是kube-apiserver的授权Handler 方法。 如果a授权器为空, 则说明kube-apiserver未启用任何授权功 能;如果a授权器不为空, 则通过GetAuthorizerAttributes函数从 HTTP请求中获取客户端信息。a.Authorize函数对请求进行授权,如果 授 权 失 败 , 则 通 过 responsewriters.Forbidden 函 数 返 回 HTTP 401 Unauthorized并返回授权失败的原因。如果返回DecisionAllow决策状 态,则表示授权成功,并进入准入控制器阶段。
# 接口
vendor/k8s.io/apiserver/pkg/authorization/authorizer/interfaces.go
# 接口的调用
vendor/k8s.io/apiserver/pkg/endpoints/filters/authorization.go
# DefaultBuildHandlerChain
vendor/k8s.io/apiserver/pkg/server/config.go
准入控制
准入控制器会在验证和授权请求之后, 对象被持久化之前, 拦截 kube-apiserver的请求, 拦截后的请求进入准入控制器中处理, 对请 求的资源对象执行自定义(校验、修改或拒绝等)操作。准入控制器 以插件的形式运行在kube-apiserver进程中, 插件化的好处在于可扩 展插件并单独启用/禁用指定插件,也可以将每个准入控制器称为准入 控制器插件。
kube-apiserver支持多种准入控制器机制, 并支持同时开启多个 准入控制器功能,如果开启了多个准入控制器,则按照顺序执行准入 控制器。
kube-apiserver目前提供了31种准入控制器,分为两种准入控制器。
-
变更准入控制器(Mutating Admission Controller):用于变更信息,能够修改用户提交的资源对象信息。
-
验证准入控制器(Validating Admission Controller):用于身份验证,能够验证用户提交的资源对象信息。文章来源:https://www.toymoban.com/news/detail-775057.html
-
提示 :变更准入控制器运行在验证准入控制器之前。文章来源地址https://www.toymoban.com/news/detail-775057.html
vendor/k8s.io/apiserver/pkg/admission/interfaces.go
// 遍历函数路径:vendor/k8s.io/apiserver/pkg/admission/chain.go
// admission 插件路径: plugin/pkg/admission
到了这里,关于【k8s源码分析-Apiserver-2】kube-apiserver 结构概览以及主体部分源码分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!