Operator SDK User Guide
Operator capability level
每种operator类型需要不同的能力。对于你的operator为项目选择什么类型时,了解每个项目类型的特性和限制是很重要的。
Phase I | Phase II | Phase III | Phase IV | Phase V |
---|---|---|---|---|
基本安装 | 无缝升级 | 完整生命周期 | 深入理解 | 自动驾驶 |
自动化应用程序配置和配置管理 | 支持补丁和小版本升级 | 应用程序生命周期,存储(备份,故障恢复) | metrics、alert、log处理和工作负载分析 | 水平/横向扩展,自动配置调优,异常检测,调度调优 |
Helm | Helm | |||
Ansible | Ansible | Ansible | Ansible | Ansible |
GO | GO | GO | GO | GO |
kubebuilder vs operator-sdk
kubebuilder和operator-sdk支持的Go项目之间没有太大的区别。两者都使用controller-tools和controller-runtime,并且都支持基本相似的go包结构。
他们的不同点:
- Operator SDK支持Ansible和Helm operator,这样很容易编写operator而不需要go,如果你对Ansible和Helm比较熟悉。
- Operator SDK集成了Operator生命周期管理(OLM),这是Operator Framework的关键组件,对于2个集群操作很重要,比如管理员在线升级你的operator。
- Operator SDK包含一个scorecard subcommand,帮助你了解operator是否遵循最佳实践。
- Operator SDK包含一个e2e测试框架,它简化了针对实际集群测试操作符的工作。
- Kubebuilder包含一个envtest包,允许operator开发人员使用独立的etcd和apiserver运行简单的测试。
- Kubebuilder搭建了一个Makefile来帮助用户完成operator的任务(构建、测试、运行、代码生成等);Operator SDK目前使用内置的子命令。每种方法都有优缺点。SDK团队将来可能会迁移到基于makefile的方法。
- Kubebuilder使用Kustomize构建部署清单;Operator SDK使用带有占位符的静态文件。
- Kubebuilder最近改进了对许可和CRD转换webhook的支持,但还没有将其加入到SDK中。
Create a new project
operator-sdk new memcached-operator
SDK还支持使用Ansible或Helm开发操作员。Helm使用指南。
Operator project layout
File/Folder s | Purpose |
---|---|
cmd | 包含文件manager/main.go。operator的main程序。他将实例化一个新的manager,注册所有pkg/apis/...下的自定义资源定义和启动所有在pkg/controllers/...下的controller。 |
pkg/apis | 包含自定义资源(CRD)API的树目录。用户可以展开编辑pkg/apis/<group>/<version>/<kind>_types.go文件,为每种资源类型定义API,并将这些包导入它们的控制器中,以监视这些资源类型。 |
pkg/controller | 此pkg包含控制器实现。用户可以展开编辑pkg/controller/<kind>/<kind>_controller.go文件。定义控制器的协调逻辑来处理指定kind的资源类型。 |
build | 包含Dockerfile编译辑脚本,用于编译operator。 |
deploy | 包含用于注册CRD、设置RBAC和将operator部署为Deployment的各种YAML清单。 |
go.mod go.sum | 描述该操作符的外部依赖项的Go mod清单。 |
vendor | golang vendor目录,包含满足此项目中Go import 的外部依赖项目的本地副本。Go modules 管理vendor目录。除非使用—vendor标志初始化项目,或者go mod vendor在项目根目录中运行,否则此目录将不存在。 |
我们主要是开发pkg下api和controller。
Manager
main程序为operator里的cmd/manager/main.go, 用于初始化并运行Manager。
Manager将为pkg/api /…下所有自定义资源自动注册schema,和运行pkg/controller/…下的所有controller。
Manager可以限制namespace所有控制器要监视的资源:
mgr, err := manager.New(cfg, manager.Options{Namespace: namespace})
默认情况下这将是operator运行的namespace。如果需要查看所有的namespace,请将namespace设置为空:
mgr, err := manager.New(cfg, manager.Options{Namespace: ""})
也可以使用 MultiNamespacedCacheBuilder 查看一组特定的namespace:
var namespaces []string // List of Namespaces
// Create a new Cmd to provide shared dependencies and start components
mgr, err := manager.New(cfg, manager.Options{
NewCache: cache.MultiNamespacedCacheBuilder(namespaces),
MapperProvider: restmapper.NewDynamicRESTMapper,
MetricsBindAddress: fmt.Sprintf("%s:%d", metricsHost, metricsPort),
})
默认情况main程序将设置namager的namespace使用在deploy/operator.yaml
定义的WATCH_NAMESPACE
。
Add a new Custom Resource Definition
增加一个名称为Memcached的Custom Resource Definition(CRD) API ,APIVersion cache.example.com/v1alpha1 和 Kind Memcached。
operator-sdk add api --api-version=cache.limingnihao.com/v1alpha1 --kind=Memcached
Define the spce and status
修改Memcached Custom Resource(CR)的spec和status在文件pkg/apis/cache/v1alpha1/memcached_types.go
:
type MemcachedSpec struct {
// Size is the size of the memcached deployment
Size int32 `json:"size"`
}
type MemcachedStatus struct {
// Nodes are the names of the memcached pods
Nodes []string `json:"nodes"`
}
在修改*_types.go文件之后,运行下面命令更新和生成代码:
$ operator-sdk generate k8s
INFO[0000] Running deepcopy code-generation for Custom Resource group versions: [cache:[v1alpha1], ]
INFO[0008] Code-generation complete.
Updating CRD mainfests
现在MemcachedSpec
和MemcachedStatus
有一些 fields 和 possibly annotations, 必须更新API's group 和 kind 与 CRD一致. 所以需要运行下面命令:
$ operator-sdk generate crds
INFO[0000] Running CRD generator.
INFO[0000] CRD generation complete.
storage version
创建 CustomResourceDefinition 时,会在 CustomResourceDefinition spec.versions 列表设置适当的稳定级和版本号。例如v1beta1表示第一个版本尚未稳定。所有自定义资源对象将首先存储在这个版本.
所以你项目的CRD必须精确地指定一个storage version.
如果转换涉及结构变更,并且需要自定义逻辑,转换应该使用 webhook。如果没有结构变更, 则使用 None 默认转换策略,不同版本时只有apiVersion字段有变更。
使用+kubebuilder:storageversion来marker指示API服务器应该使用的存储数据的GVK。该marker应该位于Memcached类型之上的注释中。
(没明白什么意思)
OpenAPI validation
当清单生成时,OpenAPIv3 schema被添加到spec.validation
块中的CRD清单中。这个验证块允许Kubernetes在创建或更新Memcached Custom Resource时验证它的属性。
Markers (annotations) 可用于验证您的API配置。这些markers将始终具有+kubebuilder:validation前缀。例如,可以通过添加以下标记来添加enum类型规范:
// +kubebuilder:validation:Enum=Lion;Wolf;Dragon
type Alias string
CRD generation和marker文档讨论了markers在代码中的是用。完整的OpenAPIv3 validation markers请参考这里
运行下面命令,更新CRDdeploy/crds/cache.example.com_memcacheds_crd.yaml
.
operator-sdk generate crds
一个生成YAML的例子如下:
spec:
validation:
openAPIV3Schema:
properties:
spec:
properties:
size:
format: int32
type: integer
要了解有关Custom Resource Definitions中的OpenAPI v3.0验证模式的更多信息,请参阅Kubernetes文档。
Add a new Contrller
添加一个新的Controller到项目,将监视和协调Memcached资源:
$ operator-sdk add controller --api-version=cache.limingnihao.com/v1alpha1 --kind=Memcached
这将在pkg/controller/memcached/...
下搭建一个新的Controller实现。
这个例子将生成文件pkg/controller/memcached/memcached_controller.go
,memcached_controller.go
是具体实现。
示例中的Controller将为所有的Memcached CR执行以下逻辑:
- 创建一个memcached Deployment如果不存在。
- 确保这些Deployment数量和
Memcached CR spec
定义的相同。 - 使用带有memcached pods名字的状态更新
Memcached CR
状态。
接下来的两个小节将解释Controller如何监视资源以及如何触发协调循环。
Resources watched by the Controller
查看pkg/controller/memcached/memcached_controller.go
的Controller实现,如何监听资源。
第一个监视对象是作为主要资源的Memcached类型。对于每个添加/更新/删除事件,会给那个Memcached对象发送一个调和Request(a namespace/name key):
// Watch for changes to primary resource Memcached
err = c.Watch(&source.Kind{Type: &cachev1alpha1.Memcached{}}, &handler.EnqueueRequestForObject{})
if err != nil {
return err
}
下面是对Deployments的监事,但是event handler将每个event映射到Deplyments所有者的Request。本例子中,Memcached对象是Deployment的创建者,这将允许controller将Deployments作为辅助资源监视。
// Watch for changes to secondary resource Pods and requeue the owner Memcached
err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForOwner{
IsController: true,
OwnerType: &cachev1alpha1.Memcached{},
})
if err != nil {
return err
}
Controller configurations
在初始化controller和生命watch参数时,有很多的配置。更多配置细节请参考controller godocs
- 通过MaxConcurrentReconciles选项设置控制器的最大并发协调数。默认为1。
_, err := controller.New("memcached-controller", mgr, controller.Options{
MaxConcurrentReconciles: 2,
...
})
- 使用predicates过滤监视事件。
- 选择EventHandelr的类型,可以将reconcile loop更改监听事件为reconcile request。对于operator更复杂的primary和secondary资源关系,可以使用EnqueueRequestsFromMapFunc handler,可以将监听事件转换为任务的reconcile request。EnqueueRequestForObject队列的一个请求包含事件源对象的Name和Namespace。
Reconcile loop
每个Controller都有一个Reconciler对象和一个实现了reconcile循环的reconcile()方法。reconcile loop通过Request argument查看主资源对象的Namespace/Name key,Memcached,从缓存:
// Reconcile读取Memcached对象的集群状态,并根据读取的状态和Memcached. spec中的内容进行更改
// 如果返回error为非空或Result.Requeue为true,控制器将再次请求处理Request,否则在完成后将从队列中删除。
func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Result, error) {
// Lookup the Memcached instance for this reconcile request
memcached := &cachev1alpha1.Memcached{}
err := r.client.Get(context.TODO(), request.NamespacedName, memcached)
...
}
根据返回值,Result和error,Request将重新请求,然后再次触发Reconcile loop:
// Reconcile successful - don't requeue
return reconcile.Result{}, nil
// Reconcile failed due to error - requeue
return reconcile.Result{}, err
// Requeue for any reason other than error
return reconcile.Result{Requeue: true}, nil
你还可以设置Result.RequeueAfter
,设置在一些时间之后重新请求Request。
import "time"
// Reconcile for any reason than error after 5 seconds
return reconcile.Result{RequeueAfter: time.Second*5}, nil
Note: 返回带RequeueAfter的Result,是定期调整CR的方法。
For a guide on Reconcilers, Clients, and interacting with resource Events, see the Client API doc.
Build and run the operator
在运行operator之前,CRD必须在 Kubernetes apiserver注册:
$ kubectl create -f deploy/crds/cache.limingnihao.com_memcacheds_crd.yaml
然后有两种方法,运行operator:
- 作为Kubernetes集群内部的Deployment。
- 集群外部的一个Go程序。
1. Run as a Deployment inside the cluster
Note:
operator-sdk buikd
调用docker build
,或者是buildah bud
。如果使用buildah
则跳过operator-sdk build
的跳过下面的说明。如果使用docker
确保docker守护进程正在运行,并且可以在没有sudo的情况下运行docker客户机。您可以通过运行docker version
来检查,
Note:存在vendor/目录,运行
$ go mod vendor
构建memcached-operator image发布和注册:
$ operator-sdk build quay.io/$USERNAME/memcached-operator:v0.0.1
$ docker login quay.io
$ docker push quay.io/$USERNAME/memcached-operator:v0.0.1
# Update the operator manifest to use the built image name (if you are performing these steps on OSX, see note below)
$ sed -i "s|REPLACE_IMAGE|quay.io/$USERNAME/app-operator|g" deploy/operator.yaml
# On OSX use:
$ sed -i "" "s|REPLACE_IMAGE|quay.io/$USERNAME/app-operator|g" deploy/operator.yaml
或者只发布到本地
$ operator-sdk build memcached-operator:v0.0.1
Deployment清单在deploy/operator.yaml中生成。请确认更新deployment imageREPLACE_IMAGE
,因为默认只是个占位符。
containers:
- name: memcached-operator
# Replace this with the built image name
image: REPLACE_IMAGE
imagePullPolicy: IfNotPresent
安装RBAC和发布memcached-operator:
kubectl create -f deploy/service_account.yaml
kubectl create -f deploy/role.yaml
kubectl create -f deploy/role_binding.yaml
kubectl create -f deploy/operator.yaml
kubectl create -f deploy/crds/cache.limingnihao.com_v1alpha1_memcached_cr.yaml
2.Run locally outside the cluster
此方法在开发周期中是首选的,以便更快地部署和测试。
在环境变量中设置operator的名称:
export OPERATOR_NAME=memcached-operator
使用$HOME/.kube/config中的默认Kubernetes配置文件在本地运行该operator:
$ operator-sdk run --local --namespace=default
2018/09/30 23:10:11 Go Version: go1.10.2
2018/09/30 23:10:11 Go OS/Arch: darwin/amd64
2018/09/30 23:10:11 operator-sdk Version: 0.0.6+git
2018/09/30 23:10:12 Registering Components.
2018/09/30 23:10:12 Starting the Cmd.
Create a Memcached CR
创建示例Memcached
的CR使用deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml`生成:
$ cat deploy/crds/cache.limingnihao.com_v1alpha1_memcached_cr.yaml
apiVersion: "cache.example.com/v1alpha1"
kind: "Memcached"
metadata:
name: "example-memcached"
spec:
size: 3
$ kubectl apply -f deploy/crds/cache.limingnihao.com_v1alpha1_memcached_cr.yaml
确保memcache -operator为CR创建部署:
$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
memcached-operator 1 1 1 1 2m
example-memcached 3 3 3 3 1m
检查pod和CR状态,确认memcached pods的状态变化:
Update the size
在memcached CR 将spec.size
字段从3改成4:
apiVersion: "cache.example.com/v1alpha1"
kind: "Memcached"
metadata:
name: "example-memcached"
spec:
size: 4
$ kubectl apply -f deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml
确认operator的deployment数量发生改变:
kubectl get deployment
cleanup
清除所有resources:
kubectl delete -f deploy/crds/cache.limingnihao.com_v1alpha1_memcached_cr.yaml
kubectl delete -f deploy/operator.yaml
kubectl delete -f deploy/role_binding.yaml
kubectl delete -f deploy/role.yaml
kubectl delete -f deploy/service_account.yaml