【k8s源码分析-Apiserver-2】kube-apiserver 结构概览以及主体部分源码分析

参考

  • Kubernetes 源码剖析(书籍)
  • kube-apiserver的设计与实现 - 自记小屋

kube-apiserver 核心思想

  • APIGroupInfo 记录 GVK 与 Storage 的对应关系

    • 将 GVK 转换成,Restful HTTP Path
    • 将 Storage 封装成 HTTP Handler
    • 将上面两个形成映射,实现相关的路由处理
  • 发起请求并处理的流程

    1. 发送请求:通过 GVK 对应的 Restful HTTP Path 发送请求(对 k8s 资源的操作)
    2. 认证:经过认证插件,判断是否为合法用户
    3. 鉴权(或叫授权):经过鉴权插件,判断该用户是否有权限操作此资源
    4. 准入控制:先执行已配置的 mutating 变更准入控制插件(修改用户提交的资源对象信息,如新增 label 等),再执行已配置 Validating 验证准入控制插件(验证用户提交的资源对象信息,如是否具有某个 label 等)
      • 在此过程中好像涉及 Schema Validation,不清楚此处作用(没有定位到,后续若找到,再补充)
    5. 执行(存储):经过以上流程,会到达 Handler 转换为对应的资源 Storage 结构,然后读取 Storage 中的存储配置信息,然后存储到 etcd 数据库中(若配置了加密,将在存入 etcd 之前,对资源对象信息进行加密)
      • 在存入之前,好像会转换为资源的某一特定版本或内部版本(没有定位到,后续若找到,再补充)
      • 【k8s源码分析-Apiserver-2】kube-apiserver 结构概览以及主体部分源码分析_第1张图片

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

【k8s源码分析-Apiserver-2】kube-apiserver 结构概览以及主体部分源码分析_第2张图片

kube-apiserver 启动流程

在kube-apiserver组件启动过程中,代码逻辑可分为9个步骤,分 别介绍如下。

(1)资源注册。 (2)Cobra命令行参数解析。 (3)创建APIServer通用配置。 (4)创建APIExtensionsServer。 (5)创建KubeAPIServer。(6)创建AggregatorServer。 (7)创建GenericAPIServer。 (8)启动HTTP服务。 (9)启动HTTPS服务。

【k8s源码分析-Apiserver-2】kube-apiserver 结构概览以及主体部分源码分析_第3张图片

资源注册

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函数
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通用配置流程

【k8s源码分析-Apiserver-2】kube-apiserver 结构概览以及主体部分源码分析_第4张图片

生成通用配置
调用逻辑
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

【k8s源码分析-Apiserver-2】kube-apiserver 结构概览以及主体部分源码分析_第5张图片

具体流程介绍如下。 (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 请 求 路 径 , 其 表 现 形 式 为 //(即/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的流程说明如下。

  1. 创建GenericAPIServer。
  2. 实例化 Instance( 旧版本叫 Master)。
  3. 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下的资源与子资源信息。
  4. InstallAPIs注册/apis资源。(有组名的资源,如 deployment 在 apps group 中)
    • 通过m.InstallAPIsI函数将【拥有组名的资源组】注册到KubeAPIServer的/apis下。可以通过访问http://localhost:8080/apis/apps/v1/deployments获得其下的资源与子资源信息。

【k8s源码分析-Apiserver-2】kube-apiserver 结构概览以及主体部分源码分析_第6张图片

创建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可以获得 资源/子资源的详细信息

【k8s源码分析-Apiserver-2】kube-apiserver 结构概览以及主体部分源码分析_第7张图片

创建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的请求,拦截后的请求进入准入控制器中处理,对请求的资源对象进行自定义(校验、修改或拒绝)等操作。

【k8s源码分析-Apiserver-2】kube-apiserver 结构概览以及主体部分源码分析_第8张图片

认证

在开启HTTPS服务后,所有的请求都需要经过认证。kubeapiserver支持多种认证机制,并支持同时开启多个认证功能。当客户端发起一个请求,经过认证阶段时,只要有一个认证器通过,则认证成功。如果认证成功,用户名就会传入授权阶段做进一步的授权验证,而对于认证失败的请求则返回HTTP 401状态码。

kube-apiserver目前提供了9种认证机制,分别是BasicAuth、 ClientCA 、 TokenAuth 、 BootstrapToken 、 RequestHeader、WebhookTokenAuth、 Anonymous、 OIDC、 ServiceAccountAuth。 每一种 认证机制被实例化后会成为认证器(Authenticator),每一个认证器 都被封装在http.Handler请求处理函数中, 它们接收组件或客户端的 请求并认证请求。 当客户端请求通过认证器并返回true时, 则表示认 证通过。认证流程如图7-21所示。

【k8s源码分析-Apiserver-2】kube-apiserver 结构概览以及主体部分源码分析_第9张图片

假 设 所 有 的 认 证 器 都 被 启 用 , 当 客 户 端 发 送 请 求 到 kubeapiserver服务,该请求会进入Authentication Handler函数(处理认 证相关的Handler函数),在Authentication Handler函数中,会遍历已启用的认证器列表, 尝试执行每个认证器, 当有一个认证器返回 true时,则认证成功,否则继续尝试下一个认证器。

WithAuthentication函数可以作为kube-apiserver的认证Handler 函数。 如果auth认证器为空, 说明kube-apiserver未启用任何认证功 能;如果其不为空, 则通过auth.AuthenticateRequest函数对请求进 行认证。 如果身份认证失败, 则通过failed.ServeHTTP函数返回HTTP 401 Unauthorized, 表示认证被拒绝;如果身份认证成功, 则不再需 要Authorization请求头并进入授权阶段。

【k8s源码分析-Apiserver-2】kube-apiserver 结构概览以及主体部分源码分析_第10张图片

# 接口
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决策状态时,则表示授权成功。

【k8s源码分析-Apiserver-2】kube-apiserver 结构概览以及主体部分源码分析_第11张图片

上面的WithAuthorization函数是kube-apiserver的授权Handler 方法。 如果a授权器为空, 则说明kube-apiserver未启用任何授权功 能;如果a授权器不为空, 则通过GetAuthorizerAttributes函数从 HTTP请求中获取客户端信息。a.Authorize函数对请求进行授权,如果 授 权 失 败 , 则 通 过 responsewriters.Forbidden 函 数 返 回 HTTP 401 Unauthorized并返回授权失败的原因。如果返回DecisionAllow决策状 态,则表示授权成功,并进入准入控制器阶段。

【k8s源码分析-Apiserver-2】kube-apiserver 结构概览以及主体部分源码分析_第12张图片

# 接口
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):用于身份验证,能够验证用户提交的资源对象信息。

  • 提示 :变更准入控制器运行在验证准入控制器之前。

vendor/k8s.io/apiserver/pkg/admission/interfaces.go
// 遍历函数路径:vendor/k8s.io/apiserver/pkg/admission/chain.go
// admission 插件路径: plugin/pkg/admission

你可能感兴趣的:(Kubernetes学习笔记,kubernetes,容器,云原生)