go - 使用自定义 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 不存在
我已经在默认 API 客户端上搜索了 Operator SDK 的文档,并了解了客户端的内部工作原理,但没有详细说明此错误或如何修复它。
此错误消息是什么意思,如何创建此缺失索引以按此字段值有效列出对象?
解决方案
控制器提供的默认 API 客户端是一个拆分客户端——它为本地缓存提供服务Get
和List
请求,并将其他方法(如直接转发Create
到Update
Kubernetes API 服务器)。这也在相应的文档中进行了解释:
SDK 将生成代码来创建一个 Manager,其中包含一个 Cache 和一个用于 CRUD 操作并与 API 服务器通信的客户端。默认情况下,Controller 的 Reconciler 将填充 Manager 的客户端,它是一个拆分客户端。[...] 拆分客户端从缓存中读取(获取和列出)并将(创建、更新、删除)写入 API 服务器。从缓存中读取显着减少了 API 服务器上的请求负载;只要 Cache 被 API server 更新,读操作最终是一致的。
要使用自定义字段选择器从缓存中查询值,缓存需要具有该字段的搜索索引。可以在设置缓存后立即定义此索引器。
要注册自定义索引器,请将以下代码添加到运算符的引导逻辑中(在自动生成的代码中,这是直接在 中完成的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
将按预期从本地缓存中工作。
推荐阅读
- java - 如何在 Room databaseBuilder 函数中使用字符串变量作为数据库名称?(JAVA,安卓))
- python - 如何用 Python 绘制时间序列热图?
- javascript - React、webpack 和 Wavesurfer.js
- node.js - 处理云函数中的嵌套承诺
- visual-studio-2019 - 有谁知道为什么“更新 UML 模型”不从 VS 2019 IDE 填充 Visual Paradigm 16.1 中的类存储库?
- vba - vbModeless 打破用户窗体
- python - 如何分批处理 N 个元素的列表,而不会丢失最后一个?
- c - 为什么我不能返回 C 中递归函数的最后一个值?
- c - C 字符串的快速排序
- ruby-on-rails - 从 Rails 4.2 升级到 5.1+ 后如何修复延迟作业反序列化错误?