Список пользовательских ресурсов из клиента кэширования с помощью настраиваемого 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
будет работать из локального кэша, как и ожидалось.