Operator SDK User Guide

2020-03-06 18:48:36 浏览数 (1)

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

代码语言:txt复制
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所有控制器要监视的资源:

代码语言:txt复制
mgr, err := manager.New(cfg, manager.Options{Namespace: namespace})

默认情况下这将是operator运行的namespace。如果需要查看所有的namespace,请将namespace设置为空:

代码语言:txt复制
mgr, err := manager.New(cfg, manager.Options{Namespace: ""})

也可以使用 MultiNamespacedCacheBuilder 查看一组特定的namespace:

代码语言:txt复制
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。

代码语言:txt复制
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:

代码语言:txt复制
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文件之后,运行下面命令更新和生成代码:

代码语言:txt复制
$ 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

现在MemcachedSpecMemcachedStatus 有一些 fields 和 possibly annotations, 必须更新API's group 和 kind 与 CRD一致. 所以需要运行下面命令:

代码语言:txt复制
$ 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类型规范:

代码语言:txt复制
//  kubebuilder:validation:Enum=Lion;Wolf;Dragon
type Alias string

CRD generation和marker文档讨论了markers在代码中的是用。完整的OpenAPIv3 validation markers请参考这里

运行下面命令,更新CRDdeploy/crds/cache.example.com_memcacheds_crd.yaml.

代码语言:txt复制
operator-sdk generate crds

一个生成YAML的例子如下:

代码语言:txt复制
spec:
  validation:
    openAPIV3Schema:
      properties:
        spec:
          properties:
            size:
              format: int32
              type: integer

要了解有关Custom Resource Definitions中的OpenAPI v3.0验证模式的更多信息,请参阅Kubernetes文档。

Add a new Contrller

添加一个新的Controller到项目,将监视和协调Memcached资源:

代码语言:txt复制
$ operator-sdk add controller --api-version=cache.limingnihao.com/v1alpha1 --kind=Memcached

这将在pkg/controller/memcached/...下搭建一个新的Controller实现。

这个例子将生成文件pkg/controller/memcached/memcached_controller.gomemcached_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):

代码语言:txt复制
// 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作为辅助资源监视。

代码语言:txt复制
// 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,从缓存:

代码语言:txt复制
// 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:

代码语言:txt复制
// 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。

代码语言:txt复制
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注册:

代码语言:txt复制
$ 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/目录,运行

代码语言:txt复制
$ go mod vendor

构建memcached-operator image发布和注册:

代码语言:txt复制
$ 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,因为默认只是个占位符。

代码语言:txt复制
containers:
  - name: memcached-operator
    # Replace this with the built image name
    image: REPLACE_IMAGE
    imagePullPolicy: IfNotPresent

安装RBAC和发布memcached-operator:

代码语言:txt复制
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的名称:

代码语言:txt复制
export OPERATOR_NAME=memcached-operator

使用$HOME/.kube/config中的默认Kubernetes配置文件在本地运行该operator:

代码语言:txt复制
$ 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`生成:

代码语言:txt复制
$ 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创建部署:

代码语言:txt复制
$ 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:

代码语言:txt复制
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数量发生改变:

代码语言:txt复制
kubectl get deployment

cleanup

清除所有resources:

代码语言:txt复制
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

Advanced Topics

Manage CR status conditions

0 人点赞