前言
# 1.简介
# 1.1.架构
apiserver提供资源对象的修改、监听、认证、鉴权及准入控制功能,主要作为集群的大脑或心脏存在,是所有模块的数据交互枢纽。--- 集群管理的API接口 提供修改、认证、鉴权、数据校验及集群状态变更 --- 数据枢纽 作为各模块运作的依赖,是所有模块的数据交互和通信枢纽 --- 安全控制 准入检查,提供集群安全管控机制 --- 数据持久化 直连后端存储etcd,是唯一的数据持久化入口1
2
3
4
5
6
7
8
9
10
11
注意
apiserver与各模块交互,是最复杂、最核心、涉及最广的组件
# 1.2.模块
kube-apiserver是直接交互etcd的组件,基于责任式串联aggregatorserver、apiextensionserver和apiserver,分别负责不同资源。--- apiserver 负责请求的通用处理,包括认证、鉴权及内建资源(pod/deploy/svc)的REST服务 --- apiextensionserver 负责crd资源,用于crd及cr的REST请求,是apiserver的下一级委托 --- aggregatorserver 负责处理apiregistration.k8s.io组的APIService资源请求,将请求拦截转发给自定义apiserver或kube-apiserver1
2
3
4
5
6
7
8
# 1.3.入口
bootstrap-controller主要负责default kubernetes service的创建及管理,暴露内部集群访问入口,是apiserver重要组成部分。--- service管理 创建kubernetes service,提供service clusterIP和nodePort的修复及检查功能 --- ns管理 创建default、kube-system、kube-public及kube-node-lease命名空间1
2
3
4
5
# 1.4.代理
proxy api用于代理rest请求,将apiserver收到的请求转发到节点上的kubelet进程rest端口,响应node或pod访问请求。--- node相关 /api/v1/prxoy/nodes/{name}/spec/ #列出指定节点的概要信息 /api/v1/proxy/nodes/{name}/exec #在节点上的某个容器中运行某条命令 --- pod相关 /api/v1/proxy/namespaces/{namespace}/pods/{name}/{path:*} #访问pod的某个服务接口 /api/v1/proxy/namespaces/{namespace}/pods/{name} #访问Pod --- service相关 /api/v1/proxy/namespaces/{namespace}/services/{name}1
2
3
4
5
6
7
8
9
10注意
proxy api多用于管理目的,如排查service关联的pod服务是否存在异常
# 1.5.网络
apiserver network policy可以将apiserver放在独立网络,实现核心的master网络与承载的node网络安全隔离,基于独立的网络连通性代理(connectivity proxy)解决连接问题。
优势
1.
connectivity porxy可以独立扩展,不影响apiserver发展2.
connectivity porxy支持自定义,实现类似VPN网络的穿透的高级代理3.
master网络和node网络隔离,提升apiserver代理内聚
# 2.术语
# 2.1.资源
资源是
kubernetes最小的管理单位,根据分组及版本粒度形成group、version、kind和resource核心结构,基于此实现了复杂的资源管理。--- apigroup 资源组,常见core,apps,extensions... --- apiversion 资源版本,用于多版本下区分资源 --- kind 资源种类,标记resource类型,常见pod,svc... --- apiresource 资源实例对象 --- subresource 子资源,常见status子资源 --- crd custom resource definitions,用户自定义资源类型1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 2.2.锚点
resource路径锚定形式为///——apps/v1/deployments/status,一般基于GVR描述资源的明确锚定位置,GVK描述资源的明确锚定类型。// GroupVersionKind unambiguously identifies a kind. type GroupVersionKind struct { Group string Version string Kind string } // GroupVersionResource unambiguously identifies a resource. type GroupVersionResource struct { Group string Version string Resource string }1
2
3
4
5
6
7
8
9
10
11
12
13注意
资源的结构体定义位于
group/types.go,TypeMeta和ObjectMeta是必须继承的元数据,代表resource是扩展资源
# 2.3.版本
resource version会分为内部版本和外部版本,以解耦多版本维护的复杂度,内部版本不会带json和proto标签,无需结构化提供给外部。// 内部版本 type Deployment struct { metav1.TypeMeta // +optional metav1.ObjectMeta // Specification of the desired behavior of the Deployment. // +optional Spec DeploymentSpec // Most recently observed status of the Deployment. // +optional Status DeploymentStatus } // 外部版本 type Deployment struct { metav1.TypeMeta `json:",inline"` // Standard object metadata. // +optional metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` // Specification of the desired behavior of the Deployment. // +optional Spec DeploymentSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"` // Most recently observed status of the Deployment. // +optional Status DeploymentStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30注意
内外版本的维护更多出于复杂性解耦目的,内部的调整不会造成外部资源定义大规模变动
# 2.4.基类
runtime.Object是所有资源类型结构的基石,作为interface被资源对象实现,作为一种通用结构体,资源对象可与runtime.Object转换。// Object interface must be supported by all API types registered with Scheme. type Object interface { GetObjectKind() schema.ObjectKind DeepCopyObject() Object } // All objects that are serialized from a Scheme encode their type information. type ObjectKind interface { // SetGroupVersionKind sets or clears the intended serialized kind of an object. SetGroupVersionKind(kind GroupVersionKind) // GroupVersionKind returns the stored gvk of an object. GroupVersionKind() GroupVersionKind }1
2
3
4
5
6
7
8
9
10
11
12
13注意
runtime.Object必须实现DeepCopyObject(),其内部又依赖deepCopyInfo,未实现deepCopyInfo创建对象副本会报错
# 2.5.接口
apiserver选用go-restful实现对外服务,接口实现对应go-restful层级概念结构,依次为container、web service及route。--- container 独立的http server,拥有独立的地址端口组合 --- web service 大粒度的分类,同类服务可归属一个web service,其挂载多个route --- route route对应url路径,该路径流量转发到对应handler1
2
3
4
5
6
7
8
# 3.scheme
# 3.1.定义
scheme的结构体作为注册表存放运行时的数据,提供给各种资源注册,内置版本转换和序列化功能,支持versionedType和unversionedType。type Scheme struct { // gvkToType allows one to figure out the go type of an object with the given version and name. gvkToType map[schema.GroupVersionKind]reflect.Type // typeToGVK allows one to find metadata for a given go object. typeToGVK map[reflect.Type][]schema.GroupVersionKind // unversionedTypes are transformed without conversion in ConvertToVersion. unversionedTypes map[reflect.Type]schema.GroupVersionKind // unversionedKinds are the names of kinds that can be created in the context of any group or version unversionedKinds map[string]reflect.Type // Map from version and resource to the corresponding func to convert // resource field labels in that version to internal version. fieldLabelConversionFuncs map[schema.GroupVersionKind]FieldLabelConversionFunc // defaulterFuncs is a map to funcs to be called with an object to provide defaulting // the provided object must be a pointer. defaulterFuncs map[reflect.Type]func(interface{}) // converter stores all registered conversion functions. It also has default converting behavior. converter *conversion.Converter // versionPriority is a map of groups to ordered lists of versions for those groups indicating the // default priorities of these versions as registered in the scheme versionPriority map[string][]string // observedVersions keeps track of the order we've seen versions during type registration observedVersions []schema.GroupVersion // schemeName is the name of this scheme. schemeName string } func (s *Scheme) AddKnownTypes(gv schema.GroupVersion, types ...Object) { // 注册观测的gv版本 s.addObservedVersion(gv) // 类型注册 for _, obj := range types { // 获取对象类型 t := reflect.TypeOf(obj).Elem() ... // 注册GVK与对象映射 s.AddKnownTypeWithName(gv.WithKind(t.Name()), obj) } } func (s *Scheme) AddKnownTypeWithName(gvk schema.GroupVersionKind, obj Object) { // 注册观测的gv版本 s.addObservedVersion(gvk.GroupVersion()) // 获取对象类型 t := reflect.TypeOf(obj).Elem() ... // 记录GVK对应Type s.gvkToType[gvk] = t // 检查type对GVK是否存在 for _, existingGvk := range s.typeToGVK[t] { if existingGvk == gvk { return } } // 记录 s.typeToGVK[t] = append(s.typeToGVK[t], gvk) // 类型实现DeepCopyInto(<obj>),注册复制转换函数 if m := reflect.ValueOf(obj).MethodByName("DeepCopyInto"); m.IsValid(){ if err := s.AddGeneratedConversionFunc(obj, obj, func(a, b interface{}, scope conversion.Scope) error { // 反射调用a.DeepCopyInfo(b) reflect.ValueOf(a).MethodByName("DeepCopyInto").Call([]reflect.Value{reflect.ValueOf(b)}) // 清空新对象的GVK信息,后续序列化或反序列化补回 b.(Object).GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{}) return nil }) ... } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80注意
deepCopyInfo是必须实现的核心方法,runtime.Object对象对其有依赖
# 3.2.分类
apiserver中资源的resource分为扩展资源(crd)、核心资源及聚合资源,分别注册到不同的scheme以实现管理目的。
# 3.3.注册
scheme未显示定义注册,通过包导入的init机制执行初始化完成资源注册,实现将支持的资源加载及记录到scheme定义的核心结构。import ( // 内部核心API "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/controlplane" ... // 客户端访问层(识别客户端访问资源) "k8s.io/client-go/kubernetes/scheme" // 聚合层API "k8s.io/kube-aggregator/pkg/apiserver/scheme" ... ) // k8s.io/kubernetes/pkg/controlplane import ( // These imports are the API groups the API server will support(controlplane包). _ "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/resource/install" _ "k8s.io/kubernetes/pkg/apis/scheduling/install" _ "k8s.io/kubernetes/pkg/apis/storage/install" ) var ( // legacyscheme 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) ) // core资源注册 func init() { Install(legacyscheme.Scheme) } // Install registers the API group and adds types to a scheme func Install(scheme *runtime.Scheme) { utilruntime.Must(core.AddToScheme(scheme)) utilruntime.Must(v1.AddToScheme(scheme)) utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion)) }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62注意
scheme注册其实就是将gvk与type关联,以识别、解析及构造为结构体
# 4.调试
# 4.1.依赖
version: '3' services: etcd: container_name: etcd image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/quay.io/coreos/etcd:v3.5.0 environment: - ETCD_NAME=etcd - ETCD_DATA_DIR=/var/etcd - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379 - ETCD_ADVERTISE_CLIENT_URLS=http://0.0.0.0:2379 - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380 - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://0.0.0.0:2380 - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster - ETCD_INITIAL_CLUSTER=etcd=http://0.0.0.0:2380 - ETCD_INITIAL_CLUSTER_STATE=new volumes: - ./data:/var/etcd ports: - "2379:2379" - "2380:2380" restart: always1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 4.2.证书
--- easyrsa安装 curl -LO https://dl.k8s.io/easy-rsa/easy-rsa.tar.gz tar xzf easy-rsa.tar.gz cd easy-rsa-master/easyrsa3 ./easyrsa init-pki --- 证书生成 export MASTER_IP=127.0.0.1 export MASTER_CLUSTER_IP=127.0.0.1 easyrsa --batch "--req-cn=${MASTER_IP}@`date +%s`" build-ca nopass easyrsa --subject-alt-name="IP:${MASTER_IP},"\ "IP:${MASTER_CLUSTER_IP},"\ "DNS:kubernetes,"\ "DNS:kubernetes.default,"\ "DNS:kubernetes.default.svc,"\ "DNS:kubernetes.default.svc.cluster,"\ "DNS:kubernetes.default.svc.cluster.local" \ --days=10000 \ build-server-full server nopass --- 证书拷贝 pki/ca.crt pki/issued/server.crt pki/private/server.key pki/private/ca.key拷贝至自定义目录 --- pod访问apiserver的SA证书 --service-account-issuer=api --service-account-key-file=cert/ca.crt --service-account-signing-key-file=cert/ca.key1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27启动配置
--etcd-servers=http://127.0.0.1:2379 --client-ca-file=cert/ca.crt --tls-cert-file=cert/server.crt --tls-private-key-file=cert/server.key --service-account-issuer=api --service-account-key-file=cert/ca.crt --service-account-signing-key-file=cert/ca.key
# 4.3.密钥
--- 生成客户端私钥 openssl genrsa -out client.key 2048 --- 生成证书签名请求(CSR) openssl req -new -key client.key -out client.csr -subj "/CN=<client-name>" --- 使用kube-apiserver的CA签署CSR,生成客户端证书 openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365 --- curl测试 curl --cacert ca.crt --cert client.crt --key client.key https://127.0.0.1:6443/version { "major": "", "minor": "", "gitVersion": "v0.0.0-master+$Format:%H$", "gitCommit": "$Format:%H$", "gitTreeState": "", "buildDate": "1970-01-01T00:00:00Z", "goVersion": "go1.20.3", "compiler": "gc", "platform": "linux/amd64" } --- kubectl测试 # 添加新集群(apiserver地址和ca证书) kubectl config set-cluster devk8s --server=https://127.0.0.1:6444 --certificate-authority=ca.crt # 添加用户(客户端证书) kubectl config set-credentials devk8s --client-certificate=client.crt --client-key=client.key # 添加上下文(绑定集群和用户) kubectl config set-context devk8s --user=devk8s --cluster=devk8s # 切换当前上下文 kubectl config use-context devk8s1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32