Список пользовательских ресурсов из клиента кэширования с помощью настраиваемого fieldSelector

Я использую 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":"..."}

Самая важная часть

Индекс с полем имени:spec.someField не существует

Я уже просмотрел документацию Operator SDK по API-клиенту по умолчанию и немного узнал о внутренней работе клиента, но не получил подробного объяснения этой ошибки или того, как ее исправить.

Что означает это сообщение об ошибке, и как я могу создать этот отсутствующий индекс для эффективного перечисления объектов по значению этого поля?

1 ответ

Решение

API-клиент по умолчанию, предоставляемый контроллером, является разделенным клиентом - он обслуживает Get а также List запросы из локального кэша и переадресация других методов, таких как Create а также Update непосредственно на сервер API Kubernetes. Это также объясняется в соответствующей документации:

SDK сгенерирует код для создания диспетчера, который содержит кэш и клиент для использования в операциях CRUD и связи с сервером API. По умолчанию Reconciler контроллера заполнен клиентом менеджера, который является сплит-клиентом. [...] Разделенный клиент читает (Get и List) из кэша и записывает (Create, Update, Delete) на сервер API. Чтение из кэша значительно снижает нагрузку на сервер API; до тех пор, пока кэш обновляется сервером 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 будет работать из локального кэша, как и ожидалось.

Другие вопросы по тегам