kube-apiserver 作为整个 Kubernetes 集群操作 etcd 的唯一入口,负责 Kubernetes 各资源的认证&鉴权,校验以及 CRUD 等操作,提供 RESTful APIs,供其它组件调用:
kube-apiserver 其实包含三种 APIServer:
AggregatorServer:负责处理 apiregistration.k8s.io 组下的 APIService 资源请求,同时将来自用户的请求拦截转发给 Aggregated APIServer(AA);
KubeAPIServer:负责对请求的一些通用处理,包括:认证、鉴权以及各个内建资源(pod, deployment,service)的 REST 服务等;
ApiExtensionsServer:负责 CustomResourceDefinition(CRD)apiResources 以及 apiVersions 的注册,同时处理 CRD 以及相应 CustomResource(CR)的REST请求(如果对应 CR 不能被处理的话则会返回404),也是 apiserver Delegation 的最后一环;
三个 APIServer 通过 delegation 的关系关联,在 kube-apiserver 初始化创建的过程中,首先创建的是 APIExtensionsServer,它的 delegationTarget 是一个空的 Delegate,即什么都不做,继而将 APIExtensionsServer 的 GenericAPIServer,作为 delegationTarget 传给了 KubeAPIServer,创建出了 KubeAPIServer,再然后,将 kubeAPIServer 的 GenericAPIServer 作为 delegationTarget 传给了 AggregatorServer,创建出了 AggregatorServer,所以他们之间 delegation 的关系为: Aggregator → KubeAPIServer → APIExtensions,如下图所示:
如何快速构建 Aggregated APIServer?虽然官方提供了一个 sample-apiserver,我们可以参考实现自己的 Aggregated APIServer。但完全手工编写太过复杂,也不便于后期维护,我们最终选择了官方推荐的工具 apiserver-builder,apiserver-builder 可以帮助我们快速创建项目骨架,并且使用 apiserver-builder 构建的项目目录结构比较清晰,更利于后期维护。
安装 apiserver-builder 工具通过 Go Get 安装
$ GO111MODULE=on go get sigs.k8s.io/apiserver-builder-alpha/cmd/apiserver-boot通过安装包安装
下载最新版本
解压到 /usr/local/apiserver-builder/
如果此目录不存在,则创建此目录
添加/usr/local/apiserver-builder/bin到您的路径 export PATH=$PATH:/usr/local/apiserver-builder/bin
运行apiserver-boot -h
初始化项目完成 apiserver-boot 安装后,可通过如下命令来初始化一个 Aggregated APIServer 项目:
$ mkdir skai-demo $ cd skai-demo $ apiserver-boot init repo --domain skai.io执行后会生成如下目录:
. ├── BUILD.bazel ├── Dockerfile ├── Makefile ├── PROJECT ├── WORKSPACE ├── bin ├── cmd │ ├── apiserver │ │ └── main.go │ └── manager │ └── main.go -> ../../main.go ├── go.mod ├── hack │ └── boilerplate.go.txt ├── main.go └── pkg └── apis └── doc.gohack 目录存放自动脚本
cmd/apiserver 是 aggregated server的启动入口
cmd/manager 是 controller 的启动入口
pkg/apis 存放 CR 相关的结构体定义,会在下一步自动生成
生成自定义资源 $ apiserver-boot create group version resource --group animal --version v1alpha1 --kind Cat --non-namespaced=false Create Resource [y/n] y Create Controller [y/n] n可根据自己的需求选择是否生成 Controller,我们这里暂时选择不生成, 对于需要通过 namespace 隔离的 resource 需要增加 --non-namespaced=false 的参数,默认都是 true。
执行完成后代码结构如下:
└── pkg └── apis ├── animal │ ├── doc.go │ └── v1alpha1 │ ├── cat_types.go │ ├── doc.go │ └── register.go └── doc.go可以看到在 pkg/apis 下生成了 animal 的 group 并在 v1alpha1 版本下新增了 cat_types.go 文件,此文件包含了我们资源的基础定义,我们在 spec 中增加字段定义,并在已经实现的 Validate 方法中完成基础字段的校验。
// Cat // +k8s:openapi-gen=true type Cat struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` Spec CatSpec `json:"spec,omitempty"` Status CatStatus `json:"status,omitempty"` } // CatSpec defines the desired state of Cat type CatSpec struct { Name string `json:"name"` } func (in *Cat) Validate(ctx context.Context) field.ErrorList { allErrs := field.ErrorList{} if len(in.Spec.Name) == 0 { allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "name"), in.Spec.Name, "must be specify")) } return allErrs } 部署运行