简介
在构建自定义的 Operator 时会涉及到如下几种组件:
client-go
底层用于与 K8S API 进行交互,支持资源的 CRUD 操作,包含了 ClientSet、DynamicClient、RESTClient 三种。controller-runtime
封装了控制器的处理框架,底层会调用client-go
库。kubebuilder
可以很方便渲染出 Controller 整个框架,该框架使用的就是controller-runtime
模块。operator-sdk
同样基于controller-runtime
实现,而且同时使用了kubebuilder
来构建 Go 项目。
简单来说,当前 Controller 的编写包含了 OperatorSDK、Kubebuilder、ClientGo 三种方式,前两者提供了更加实用的封装,而 ClientGo 相对来说要简单很多,这里简单介绍 Kubebuilder 的使用方式。
Kubebuilder
Kubebuilder 由 K8S Special Interest Group, SIG API Machinery 拥有和维护,用于帮助开发者创建 CRD 并生成 Controller 脚手架,包含了如下的组件:
- Client 封装了对资源的操作,修改会直接访问 APIServer ,而查询则会访问本地 Cache 信息。
- Cache 负责生成 SharedInformer,会监听 GVK 下的 GVR 变化,然后触发 Controller 的 Reconcile 逻辑。
- Manager 管理协调多个 Controller,提供共有依赖以及基础服务(例如保活),负责初始化 Controller、Cache、Client 的工作。
- Finzlizers 用于处理资源的预删除逻辑,保障资源被删除后能够从 Cache 中读取到,清理相关的其它资源。
- Builder 构造器,提供了一系列配置接口,可以通过链式条用进行组装,最终为 Reconciler 生成相应的 Controller 对象。
示例
可以直接从 GitHub Release 上下载对应的二进制文件。
----- 切换到默认的工作目录
$ cd $GOPATH/src/example.io/hello
----- 初始化项目,会同时下载依赖
$ go mod init example.io/hello
$ kubebuilder init --domain example.io
----- 创建API,会自动生成资源、Controller的定义
$ kubebuilder create api --group batch --version v1 --kind Hello
$ ls api/v1/hello_types.go
$ ls internal/controller/hello_controller.go
----- 安装CRD资源
$ make install
$ kubectl get crd | grep example.io
$ kubectl api-versions | grep example.io
$ kubectl api-resources --namespaced=true | grep example.io
----- 直接本地运行,下面介绍如何部署到K8S中
$ make run
----- 启动CustomResource,初始化项目时已经生成了示例
$ kubectl apply -f config/samples/batch_v1_hello.yaml
$ kubectl get hello
$ kubectl get hellos.batch.example.io hello-sample
$ kubectl delete hellos.batch.example.io hello-sample
也可以将 Controller 以 Deployment 的方式部署到 K8S 集群上。
----- 构建镜像并Push到DockerHub上,然后部署到K8S集群
make docker-build docker-push IMG=YourRepo/kubebuilder-example:latest
make deploy IMG=YourRepo/kubebuilder-example:latest
----- 在初始化项目时会自动创建一个Namespace配置
$ kubectl get deployment -n kubebuilder-example-system
$ kubectl get pod -n kubebuilder-example-system
增加业务逻辑
这里简单通过 Spec 将信息传递给资源,然后打印与 CRD 相关的信息,修改 api/v1/hello_types.go
文件。
type HelloSpec struct {
Message string `json:"message,omitempty"`
}
type HelloStatus struct {
Status string `json:"status"`
}
以及 internal/controller/hello_controller.go
文件,关键是 Reconcile
函数。
func (r *HelloReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := log.FromContext(ctx)
obj := &batchv1.Hello{}
if err := r.Get(ctx, req.NamespacedName, obj); err != nil {
logger.Info("Unable to fetch object", "error", err)
} else {
logger.Info("Geeting from Kubebuilder", "message", obj.Spec.Message)
}
obj.Status.Status = "Running"
if err := r.Status().Update(ctx, obj); err != nil {
logger.Info("Unable to update status", "error", err)
}
return ctrl.Result{}, nil
}
修改完后类似如上的方式编译运行。
----- 本地运行
$ make run
----- 修改CR文件,增加参数
$ vim config/samples/batch_v1_hello.yaml
apiVersion: batch.example.io/v1
kind: Hello
metadata:
name: hello-sample
spec:
message: HelloWorld
----- 应用到K8S
$ kubectl apply -f config/samples/batch_v1_hello.yaml
其它
健康检查
内部集成了健康检查功能,可以通过 Manager.AddHealthzCheck()
和 Manager.AddReadyzCheck()
注册监控检查逻辑,其端口和路径可以在如下的 Options
中配置,然后通过 Manager.Start()
启动时会同时包含一个 HTTP Server 提供监控检查的返回结果。
type Options struct {
// HealthProbeBindAddress is the TCP address that the controller should bind to
// for serving health probes
HealthProbeBindAddress string
// Readiness probe endpoint name, defaults to "readyz"
ReadinessEndpointName string
// Liveness probe endpoint name, defaults to "healthz"
LivenessEndpointName string
}
监控指标
在 pkg/metrics
和 pkg/internal/controller/metrics
中内置了很多模块的监控指标,同样可以在 Options.MetricsBindAddress
中配置,包括通过 pkg/metrics
中的 Registry 自定义监控指标。
参考
- Book Kubebuilder 官方的介绍。
- GitHub Memcache Docker 包含了官方的 Dockerfile 制作文件,通常在 Docker Library 中维护,文档信息可以查看 Docs 。