使用自定义字段选择器列出来自缓存客户端的自定义资源

时间:2019-07-17 19:52:56

标签: go kubernetes operator-sdk

我正在使用Operator SDK来构建自定义的Kubernetes运算符。我已经使用相应的Operator SDK命令创建了一个自定义资源定义和一个控制器:

operator-sdk add api --api-version example.com/v1alpha1 --kind=Example
operator-sdk add controller --api-version example.com/v1alpha1 --kind=Example

在主要对帐循环中(对于上面的示例,是自动生成的ReconcileExample.Reconcile方法),我有一些自定义业务逻辑,需要我在Kubernetes API中查询具有某种确定性的其他同类对象字段值。我突然想到,我可以使用带有自定义字段选择器的默认API客户端(由控制器提供):

func (r *ReconcileExample) Reconcile(request reconcile.Request) (reconcile.Result, error) {
    ctx := context.TODO()
    listOptions := client.ListOptions{
        FieldSelector: fields.SelectorFromSet(fields.Set{"spec.someField": "someValue"}),
        Namespace:     request.Namespace,
    }
    otherExamples := v1alpha1.ExampleList{}

    if err := r.client.List(ctx, &listOptions, &otherExamples); err != nil {
        return reconcile.Result{}, err
    }

    // do stuff...

    return reconcile.Result{}, nil
}

当我运行操作员并创建新的Example资源时,操作员将失败,并显示以下错误消息:

{"level":"info","ts":1563388786.825384,"logger":"controller_example","msg":"Reconciling Example","Request.Namespace":"default","Request.Name":"example-test"}
{"level":"error","ts":1563388786.8255732,"logger":"kubebuilder.controller","msg":"Reconciler error","controller":"example-controller","request":"default/example-test","error":"Index with name field:spec.someField does not exist","stacktrace":"..."}

最重要的部分是

  

名称为field:spec.someField的索引不存在

我已经在默认的API客户端上搜索了the Operator SDK's documentation,并了解了一些有关客户端内部工作的信息,但没有对此错误或如何解决的详细说明。

此错误消息是什么意思,我如何创建该丢失的索引以通过此字段值有效地列出对象?

1 个答案:

答案 0 :(得分:1)

控制器提供的默认API客户端是 split客户端-它可以处理来自本地持有的缓存的GetList请求,并转发其他方法例如CreateUpdate直接连接到Kubernetes API服务器。 the respective documentation中也对此进行了解释:

  

SDK将生成代码以创建一个Manager,该Manager包含要在CRUD操作中使用的缓存和客户端,并与API服务器通信。默认情况下,控制器的协调人将使用作为拆分客户端的Manager的客户端进行填充。 [...]拆分客户端从缓存读取(获取和列出),并将(创建,更新,删除)写入API服务器。从缓存中读取可大大减少API服务器上的请求负载;只要Cache由API服务器更新,读取操作最终都是一致的。

要使用自定义字段选择器从缓存中查询值,缓存需要为此字段具有搜索索引。可以在设置缓存后立即定义此索引器。

要注册自定义索引器,请将以下代码添加到运算符的自举逻辑中(在自动生成的代码中,这直接在main中完成)。必须在实例化控制器管理器(manager.New之后完成此操作,并且将自定义API类型添加到runtime.Scheme之后 :

package main

import (
    k8sruntime "k8s.io/apimachinery/pkg/runtime"
    "example.com/example-operator/pkg/apis/example/v1alpha1"
    // ...
)

function main() {
    // ...

    cache := mgr.GetCache()

    indexFunc := func(obj k8sruntime.Object) []string {
        return []string{obj.(*v1alpha1.Example).Spec.SomeField}
    }

    if err := cache.IndexField(&v1alpha1.Example{}, "spec.someField", indexFunc); err != nil {
        panic(err)
    }

    // ...
}

定义了相应的索引器功能后,spec.someField上的字段选择器将按预期从本地缓存中工作。