List custom resources from caching client with custom fieldSelector

hel*_*ert 8 go kubernetes operator-sdk

I'm using the Operator SDK to build a custom Kubernetes operator. I have created a custom resource definition and a controller using the respective Operator SDK commands:

operator-sdk add api --api-version example.com/v1alpha1 --kind=Example
operator-sdk add controller --api-version example.com/v1alpha1 --kind=Example
Run Code Online (Sandbox Code Playgroud)

在主协调循环中(对于上面的示例,自动生成的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
}
Run Code Online (Sandbox Code Playgroud)

当我运行该运算符并创建新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":"..."}
Run Code Online (Sandbox Code Playgroud)

最重要的部分是

名称字段索引:spec.someField 不存在

我已经搜索了关于默认 API 客户端的 Operator SDK 文档,并了解了一些有关客户端内部工作原理的信息,但没有详细解释此错误或如何修复它。

此错误消息是什么意思,如何创建此缺失索引以按此字段值有效列出对象?

hel*_*ert 9

控制器提供的默认 API 客户端是一个拆分客户端——它从本地保存的缓存提供服务Get和请求,并将其他方法(例如直接转发到 Kubernetes API 服务器)转发。相应的文档中也对此进行了解释:ListCreateUpdate

SDK将生成代码来创建一个Manager,它拥有一个Cache和一个Client,用于CRUD操作并与API服务器通信。默认情况下,控制器的协调器将填充管理器的客户端,该客户端是一个拆分客户端。[...] 拆分客户端从缓存中读取(获取和列出)并向 API 服务器写入(创建、更新、删除)。从Cache中读取显着减少了API服务器上的请求负载;只要API服务器更新Cache,读操作最终是一致的。

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

要注册自定义索引器,请将以下代码添加到运算符的引导逻辑中(在自动生成的代码中,这直接在 中完成main)。这需要在实例化控制器管理器 ( )之后以及将自定义 API 类型添加到完成:manager.Newruntime.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)
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

当定义相应的索引器函数时,字段选择器spec.someField将按预期从本地缓存工作。