Kubernetes:kube-apiserver 之 scheme(一)
0. 前言
在进入 kube-apiserver
源码分析前,有一个非常重要的概念需要了解甚至熟悉的:资源注册表(scheme)。
Kubernetes
中一切皆资源,管理的是资源,创建、更新、删除的是资源。如何对庞杂的资源进行管理就成了一件大事。Kubernetes
通过引入 scheme
资源注册表,将资源信息注册到资源注册表,各个组件通过索引资源注册表实现资源的管理。
1. 介绍
直接开始阅读 kube-apiserver
scheme
部分的源码是比较困难的,这里举代码示例如下:
package main
import (
"fmt"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func main() {
// KnownType external
coreGV := schema.GroupVersion{Group: "", Version: "v1"}
extensionsGV := schema.GroupVersion{Group: "extensions", Version: "v1beta1"}
// KnownType internal
coreInternalGV := schema.GroupVersion{Group: "", Version: runtime.APIVersionInternal}
// UnversionedType
Unversioned := schema.GroupVersion{Group: "", Version: "v1"}
schema := runtime.NewScheme()
schema.AddKnownTypes(coreGV, &corev1.Pod{})
schema.AddKnownTypes(extensionsGV, &appsv1.DaemonSet{})
schema.AddKnownTypes(coreInternalGV, &corev1.Pod{})
schema.AddUnversionedTypes(Unversioned, &metav1.Status{})
fmt.Println(*schema)
fmt.Println(schema.KnownTypes(coreGV))
}
示例中有几点需要关注。
- 通过
runtime.NewScheme
创建scheme
实例:
func NewScheme() *Scheme {
s := &Scheme{
gvkToType: map[schema.GroupVersionKind]reflect.Type{},
typeToGVK: map[reflect.Type][]schema.GroupVersionKind{},
unversionedTypes: map[reflect.Type]schema.GroupVersionKind{},
unversionedKinds: map[string]reflect.Type{},
fieldLabelConversionFuncs: map[schema.GroupVersionKind]FieldLabelConversionFunc{},
defaulterFuncs: map[reflect.Type]func(interface{}){},
versionPriority: map[string][]string{},
schemeName: naming.GetNameFromCallsite(internalPackages...),
}
s.converter = conversion.NewConverter(nil)
...
return s
}
Scheme
的结构体有四个 field
需要重点关注:
gvkToType
: 记录的是schema.GroupVersionKind
和资源类型的映射关系。typeToGVK
: 记录的是资源类型和schema.GroupVersionKind
的映射关系。unversionedTypes
: 记录的是无版本资源类型和schema.GroupVersionKind
的映射关系。unversionedKinds
: 记录的是资源种类Kind
和无版本资源类型的映射关系。
还有一个 Scheme.converter
也挺重要,这里先跳过不讲。
- 调用
Scheme
的AddKnownTypes
和AddUnversionedTypes
方法建立资源Group/Version/Kind
和资源类型的相互映射关系。
以 AddKnownTypes
为例,函数通过反射 reflect.TypeOf(obj)
获得对象 runtime.Object
的资源类型。这里,对象是资源的接口,可实现资源和对象的相互转换。
func (s *Scheme) AddKnownTypes(gv schema.GroupVersion, types ...Object) {
s.addObservedVersion(gv)
for _, obj := range types {
t := reflect.TypeOf(obj)
if t.Kind() != reflect.Pointer {
panic("All types must be pointers to structs.")
}
t = t.Elem()
s.AddKnownTypeWithName(gv.WithKind(t.Name()), obj)
}
}
func (gv GroupVersion) WithKind(kind string) GroupVersionKind {
return GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind}
}
func (s *Scheme) AddKnownTypeWithName(gvk schema.GroupVersionKind, obj Object) {
...
t := reflect.TypeOf(obj)
s.gvkToType[gvk] = t
}
然后调用 gv.WithKind(t.Name())
转换为 GroupVersionKind
,可以看出上面反射的资源类型作为 kind
赋给 GroupVersionKind
。
最后调用 AddKnownTypeWithName
将 schema.GroupVersionKind
和资源类型写入 Scheme.gvkToType
。
执行代码结果如下:
{
map[
{ __internal Pod}:0xb46180
{ v1 Pod}:0xb46180
{ v1 Status}:0xb56d40
{extensions v1beta1 DaemonSet}:0xb44e40
]
map[
0xb44e40:[{extensions v1beta1 DaemonSet}]
0xb46180:[{ v1 Pod} { __internal Pod}]
0xb56d40:[{ v1 Status}]
]
map[
0xb56d40:{ v1 Status}
]
map[
Status:0xb56d40
]
map[]
map[]
0xc000124888
map[]
[{ v1} {extensions v1beta1}]
pkg/runtime/scheme.go:100
}
map[Pod:v1.Pod Status:v1.Status]
Kubernetes
资源分为外部资源和内部资源。外部资源是对外可访问的,其版本为v1/v1beta1
等,内部资源是Kubernetes
内部访问的资源,其版本为__internal
。
为什么会有内部版本呢?
为了适配版本间的 convert
。
试想,如果 v1
、v1apha1
、v1beta1
、v1beta2
要相互转换需要建立十二种转换关系:
v1 ----> v1alpha1
v1 ----> v1beta1
v1 ----> v1beta2
v1alpha1 ----> v1
v1alpha1 ----> v1beta1
v1alpha1 ----> v1beta2
v1beta1 ----> v1
v1beta1 ----> v1alpha1
v1beta1 ----> v1beta2
v1beta2 ----> v1
v1beta2 ----> v1alpha1
v1beta2 ----> v1beta1
可以看到这种转换已经比较复杂了,随着资源增多,这种资源版本之间的转换会越来越复杂且难以维护。Kubernetes
通过引入内部版本 __internl
建立每种资源到 __internal
的转换,从而实现不同资源版本的相互转换。
v1 ----> __internal
__internal ----> v1
v1alpha1 ----> __internal
__internal ----> v1alpha1
v1beta1 ----> __internal
__internal ----> v1beta1
v1beta2 ----> __internal
__internal ----> v1beta2
转换示意图如下:
可以看到,相当干净,清爽。
2. kube-apiserver scheme
第一节介绍了 scheme
结构及部分特性。继续看 kube-apiserver
中 scheme
的应用。
2.1 注册资源
kube-apiserver
中资源的注册通过导入包的形式实现。Kubernetes
将资源拆分为三类,并且由三种 HTTP Server
负责处理这三类资源,架构如下。
关于这幅图,这里不多讲,后续会逐层介绍。
要知道的是,三类资源分别注册到 extensionsapiserver.Scheme
,legacyscheme.Scheme
和 aggregatorscheme.Scheme
三种资源注册表中。
以 legacyscheme.Scheme
资源注册表为例。
kube-apiserver
的启动 app
包中导入 "k8s.io/kubernetes/pkg/api/legacyscheme"
和 "k8s.io/kubernetes/pkg/controlplane"
包:
package app
import (
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/controlplane"
)
legacyscheme
包中创建了 Scheme
资源注册表,Codecs
编码器和 ParameterCodec
参数编码器。
# kubernetes/pkg/api/legacyscheme/scheme.go
package legacyscheme
var (
Scheme = runtime.NewScheme()
Codecs = serializer.NewCodecFactory(Scheme)
ParameterCodec = runtime.NewParameterCodec(Scheme)
)
controlplane
包中导入需要注册的资源组:
# kubernetes/pkg/controlplane/import_known_versions.go
package controlplane
import (
_ "k8s.io/kubernetes/pkg/apis/apps/install"
)
以注册 apps
资源组为例:
# kubernetes/pkg/apis/apps/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/apps"
"k8s.io/kubernetes/pkg/apis/apps/v1"
"k8s.io/kubernetes/pkg/apis/apps/v1beta1"
"k8s.io/kubernetes/pkg/apis/apps/v1beta2"
)
func init() {
Install(legacyscheme.Scheme)
}
func Install(scheme *runtime.Scheme) {
utilruntime.Must(apps.AddToScheme(scheme))
utilruntime.Must(v1beta1.AddToScheme(scheme))
utilruntime.Must(v1beta2.AddToScheme(scheme))
utilruntime.Must(v1.AddToScheme(scheme))
utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion, v1beta2.SchemeGroupVersion, v1beta1.SchemeGroupVersion))
}
资源组中调用 apps.AddToScheme
,v1beta1.AddToScheme
,v1beta2.AddToScheme
和 v1.AddToScheme
函数将同一资源组不同版本的资源注册到 legacyscheme.Scheme
资源注册表中。
其中 apps.AddToScheme
注册的是内部版本的资源:
package apps
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)
const GroupName = "apps"
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&DaemonSet{},
&DaemonSetList{},
&Deployment{},
&DeploymentList{},
&DeploymentRollback{},
&autoscaling.Scale{},
&StatefulSet{},
&StatefulSetList{},
&ControllerRevision{},
&ControllerRevisionList{},
&ReplicaSet{},
&ReplicaSetList{},
)
return nil
}
v1beta1.AddToScheme
,v1beta2.AddToScheme
和 v1.AddToScheme
注册的是外部版本的资源,以 v1.AddToScheme
为例:
package v1
const GroupName = "apps"
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Deployment{},
&DeploymentList{},
&StatefulSet{},
&StatefulSetList{},
&DaemonSet{},
&DaemonSetList{},
&ReplicaSet{},
&ReplicaSetList{},
&ControllerRevision{},
&ControllerRevisionList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
需要注意的是,内部版本和外部版本注册的资源并不一样。比如 Deployment
资源,外部版本引用的是 kubernetes/vendor/k8s.io/api/apps/v1/types.go
中的资源定义:
type Deployment struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
Spec DeploymentSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
Status DeploymentStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}
资源声明了 json
和 protobuf
tag,以便于外部访问的序列化,反序列化操作。
内部版本引用的是 kubernetes/pkg/apis/apps/types.go
中的资源定义:
type Deployment struct {
metav1.TypeMeta
metav1.ObjectMeta
Spec DeploymentSpec
Status DeploymentStatus
}
内部资源不需要被外部访问,没有 tag 声明。
到这里,kube-apiserver 关于资源的注册就差不多了。下一篇将进一步介绍 scheme
的 convert
,kube-apiserver
中如何使用 scheme
及 scheme
和 object
相互转换等内容。
Kubernetes:kube-apiserver 之 scheme(一)的更多相关文章
- kubernetes的apiserver
1. API Server简介 k8s API Server提供了k8s各类资源对象(pod,RC,Service等)的增删改查及watch等HTTP Rest接口,是整个系统的数据总线和数据中心. ...
- 【云原生 · Kubernetes】apiserver高可用
个人名片: 因为云计算成为了监控工程师 个人博客:念舒_C.ying CSDN主页️:念舒_C.ying 7.1 高可用选型 ipvs+keepalived nginx+keepalived hap ...
- 一文读懂 Kubernetes APIServer 原理
前言 整个Kubernetes技术体系由声明式API以及Controller构成,而kube-apiserver是Kubernetes的声明式api server,并为其它组件交互提供了桥梁.因此加深 ...
- 【kubernetes 自带监控】 container级别cadvisor+kubelet,集群级别apiserver
apiserver https://feisky.gitbooks.io/kubernetes/components/apiserver.html kube-apiserver 支持同时提供 http ...
- Centos7 二进制安装 Kubernetes 1.13
目录 1.目录 1.1.什么是 Kubernetes? 1.2.Kubernetes 有哪些优势? 2.环境准备 2.1.网络配置 2.2.更改 HOSTNAME 2.3.配置ssh免密码登录登录 2 ...
- kubernetes CRD学习笔记
前言 最近在极客时间订阅了kubernetes的专栏,这篇文章是想记录一下自己学习CRD(custom resource definition)的过程,加深一下记忆. 准备工作 首先安装一下我们用的g ...
- kubernetes Dashboard 使用RBAC 权限认证控制
kubernetes RBAC实战 环境准备 先用kubeadm安装好kubernetes集群,[包地址在此](https://market.aliyun.com/products/56014009/ ...
- 【Kubernetes】深入解析声明式API
在Kubernetes中,一个API对象在Etcd里的完整资源路径,是由:Group(API组).Version(API版本)和Resource(API资源类型)三个部分组成的. 通过这样的结构,整个 ...
- kubernetes之手动部署k8s 1.14.1高可用集群
1. 架构信息 系统版本:CentOS 7.6 内核:3.10.0-957.el7.x86_64 Kubernetes: v1.14.1 Docker-ce: 18.09.5 推荐硬件配置:4核8G ...
- 基于Containerd安装部署高可用Kubernetes集群
转载自:https://blog.weiyigeek.top/2021/7-30-623.html 简述 Kubernetes(后续简称k8s)是 Google(2014年6月) 开源的一个容器编排引 ...
随机推荐
- Kali下载安装以及基础配置
Kali官网:Kali Linux | Penetration Testing and Ethical Hacking Linux Distribution Kali下载地址:Get Kali | K ...
- 2023年郑州轻工业大学校赛邀请赛mjh
首先,很感谢老师的信任,选择我去参加此次比赛:其次,感谢wh,wyh两位队友的全程带飞.此次比赛是我第一次参加线下的比赛活动,内心难免激动与紧张. 比赛开始,队友直接找到了签到题进行解答,而我拿到了看 ...
- Unity UGUI的LayoutElement(布局元素)组件的介绍及使用
Unity UGUI的LayoutElement(布局元素)组件的介绍及使用 1. 什么是LayoutElement组件? LayoutElement是Unity UGUI中的一个布局元素组件,用于控 ...
- Diffusers 一岁啦 !
十分高兴 Diffusers 迎来它的一岁生日!这是令人激动的一年,感谢社区和开源贡献者,我们对我们的工作感到十分骄傲和自豪.去年,文本到图像的模型,如 DALL-E 2, Imagen, 和 Sta ...
- CTF比赛中Web的php伪协议类型题小结
php协议类型 file:// - 访问本地文件系统 http:// - 访问 HTTP(s) 网址 ftp:// - 访问 FTP(s) URLs php:// - 访问各个输入/输出流(I/O s ...
- [django]数据的导入和导出
除了使用mysqldump或者MySQL客户端进行数据导出,django也提供了类似的功能. 导出 # 导出整个数据库并保存为json文件 python manage.py dumpdata > ...
- Dirty-Pipe Linux内核提权漏洞(CVE-2022-0847)
前言: 划水一波,哈哈,以后复现漏洞不再直接傻瓜无脑的走流程了,首先码字写加构思比较麻烦且写的不多还效率不高,现在就是当做见到了一个漏洞,在此记录一下这个漏洞,包括其来源,简单的描述,适用范围,以及其 ...
- html5 2.0学习
列表定义:是一种特别的对象集合.集合:集中在一起合二为一(聚集). 聚集:多个列(信息资源)排在一起.信息资源:一堆数据,可能是字符,可能是图片. 列表分类:有序列表 无序列表 (自)定义列表 有 ...
- C# 使用openxml解析PPTX中的文本内容
前言 本文讨论的仅针对微软Office 2007以后的(OOXML定义)PowerPoint文档,Office 2007以前的用二进制格式定义的(ppt格式)文档不在本文讨论范围. 一.依赖类库 本文 ...
- 部分 Linux 换国内源
Centos 8 / Redhat 8 换国内源 操作步骤 先把原本的官方 yum 源 删除 或 备份 cd /etc/yum.repos.d/ 备份(Redhat 同理) rename repo r ...