当前位置:首页 > 文章列表 > Golang > Go问答 > 观察其他控制器CR的Kubernetes控制器

观察其他控制器CR的Kubernetes控制器

来源:stackoverflow 2024-02-16 08:36:24 0浏览 收藏

哈喽!大家好,很高兴又见面了,我是golang学习网的一名作者,今天由我给大家带来一篇《观察其他控制器CR的Kubernetes控制器》,本文主要会讲到等等知识点,希望大家一起学习进步,也欢迎大家关注、点赞、收藏、转发! 下面就一起来看看吧!

问题内容

我有按预期工作的 k8s 运算符,我需要向其他运算符 crd(不是我的)添加一个“监视”,为了简单起见,我们将其称为 extcr,我们的运算符 cr 称为 incr

我尝试了以下方法,但存在如何触发协调的问题。

func (r *insiconciler) setupwithmanager(mgr ctrl.manager) error {
                return ctrl.newcontrollermanagedby(mgr).
                    for(&inv1alpha1.iget{}}).
                    watches(&source.kind{type: &ext.se{}},  handler.enqueuerequestsfrommapfunc(r.fwatch)).
                    complete(r)
}
    
func (r *insiconciler) fwatch(c client.object) []reconcile.request {
        val := c.(*ivi.srv)
        req := reconcile.request{namespacedname: types.namespacedname{name: val.name, namespace: val.namespace}}
        return []reconcile.request{req}
}

这里的问题是我触发了与 extcr 的协调,我想在 fwatch 内部更新 incr 并使用 incr 而不是 extcr 启动协调,我该怎么做?

我的意思是,为了避免类似下面的代码,因为有时会为 incr 进行协调,有时会为 extcr 进行协调,而不是我会得到一些丑陋的 if

func (r *insiconciler) reconcile(ctx context.context, req ctrl.request) (ctrl.result, error) {
        var incr foo
        var extcr bar
    
        if err := r.get(ctx, req.namespacedname, &incr); err != nil {
            return ctrl.result{}, err
        }
        
        if err := r.get(ctx, req.namespacedname, &extcr); err != nil {
            return ctrl.result{}, err
        }

我想知道处理这种情况的正确/干净的方法是什么

当您需要监听externalcr(不是控制器的一部分)和internalcr(来自控制器)的情况。

还有一件事 - cr 与 gvk 不同,但 exteranlcr 包含许多不需要的字段,只是其中一些字段。但必填字段在两个 cr 上具有相同的名称

更新

type incr struct {
    metav1.typemeta   `json:",inline"`
    metav1.objectmeta `json:"metadata,omitempty"`

    spec   inspec  `json:"spec,omitempty"`  / / ————————here is the difference 
    status insighttargetstatus `json:"status,omitempty"`
}

//———— 这是在不属于我们的其他程序上定义的,因此不能“重用”

type bar struct {
    metav1.typemeta   `json:",inline"`
    metav1.objectmeta `json:"metadata,omitempty"`

    spec   extspec  `json:"spec,omitempty"`    // ———————here is the difference 
    status servicestatus `json:"status,omitempty"`
}

并且 inspec 具有以下字段(extspec 的子集)

type inspec struct {
    name string
    age  int
}

extspec 具有这些字段以及更多不相关的字段

type extspec struct {
    name string   
    age  int
    foo string  // not relevant
    bar string  // not relevant
    bazz string // not relevant
}

最后,在协调内我需要将 relevant 字段移动到某些函数。 完全相同的函数只是有时从 extcr 获取字段,有时从 incr 获取字段,具体取决于发生的事件(例如用户更新 extcr 或更新 incr)

更新2

func sharedLogic(r reconciler, ctx context.Context, c client.Object) (ctrl.Result, error) {
    
    
    in := c.(*inCR)
    
    
    vPass , e := vps.Get(ctx, r.Client, in.Spec.foo, in.Spec.bar)
    
    
     return ctrl.Result{}, nil
    }

But for extCR I should do the following


func sharedLogic(r reconciler, ctx context.Context, c client.Object) (ctrl.Result, error) {


ext := c.(*extCR)


vPass , e := vps.Get(ctx, r.Client, ext.Spec.val.foo, ext.Spec.val.bar)


 return ctrl.Result{}, nil
}

正确答案


需要记住的几点:

  • 每个控制器恰好负责一个资源。
  • 协调请求包含协调 kubernetes 对象所需的信息。这包括唯一标识对象的信息 - 它的名称和命名空间。它不包含有关任何特定事件或对象内容本身的信息。

您可以在没有资源定义的情况下创建第二个控制器。在您的主文件中,两个控制器都将被注册。

如果 crd 根本不相关或者外部资源引用内部资源,这可能会很有用,因此您可以在外部协调器中对内部资源进行更改。

kubebuilder create api --group other --version v2 --kind external \
 --resource=false --controller=true

这将为您提供一个带有 setupwithmanager 方法的控制器,如下所示。

func (r *externalreconciler) setupwithmanager(mgr ctrl.manager) error {
    return ctrl.newcontrollermanagedby(mgr).
        // uncomment the following line adding a pointer to an instance of the controlled resource as an argument
        // for().
        complete(r)
}

请注意 for 方法是如何被注释掉的,因为您需要导入要从其他地方观看的资源并引用它。

import (
    ...
    otherv2 "other.io/external/api/v2"
)
...
func (r *externalreconciler) setupwithmanager(mgr ctrl.manager) error {
    return ctrl.newcontrollermanagedby(mgr).
        for(&otherv2.external{}).
        complete(r)
}

如果您无法导入外部资源,您可以自行模拟它,但这可能不是一个非常干净的方法。您确实应该尝试从其他控制器项目导入它。

kubebuilder edit --multigroup=true
kubebuilder create api --group=other --version v2 --kind external \
  --resource --controller

另一种方法是当资源彼此相关时,内部资源在其规范中具有对外部资源的引用,并且知道如何在协调时在其规范中获取外部资源。可以在此处找到相关示例:https://book.kubebuilder.io/reference/watching-resources/externally-managed.html

type internalspec struct {
    // name of an external resource
    externalresource string `json:"externalresource,omitempty"`
}

这意味着在每个协调循环中,控制器将查找外部资源并使用它来管理内部资源。

func (r *internalreconciler) reconcile(ctx context.context, req ctrl.request) (ctrl.result, error) {
    _ = log.fromcontext(ctx)

    internal := examplev1.internal{}
    if err := r.get(context.todo(), types.namespacedname{
        name:      req.name,
        namespace: req.namespace,
    }, &internal); err != nil {
        return ctrl.result{}, err
    }

    external := otherv2.external{}
    if err := r.get(context.todo(), types.namespacedname{
        // note how the name is taken from the internal spec
        name:      internal.spec.externalresource,
        namespace: req.namespace,
    }, &internal); err != nil {
        return ctrl.result{}, err
    }

    // do something with internal and external here

    return ctrl.result{}, nil
}

这样做的问题是,当内部资源没有变化时,即使外部资源发生变化,也不会触发协调事件。为了解决这个问题,我们可以通过观察外部资源来触发协调。注意 watches 方法:

func (r *internalreconciler) setupwithmanager(mgr ctrl.manager) error {
    return ctrl.newcontrollermanagedby(mgr).
        for(&examplev1.main{}).
        watches(
            &source.kind{type: &otherv2.externalresource{}},
            handler.enqueuerequestsfrommapfunc(r.triggerreconcilebecauseexternalhaschanged),
            builder.withpredicates(predicate.resourceversionchangedpredicate{}),
        ).
        complete(r)
}

为了知道我们应该为哪个内部对象触发事件,我们使用映射函数来查找所有引用外部资源的内部对象。

func (r *internalreconciler) triggerreconcilebecauseexternalhaschanged(o client.object) []reconcile.request {
    usedbyinternals := &examplev1.internallist{}
    listops := &client.listoptions{
        fieldselector: fields.onetermequalselector(".spec.externalresource", o.getname()),
        namespace:     o.getnamespace(),
    }
    err := r.list(context.todo(), usedbyinternals, listops)
    if err != nil {
        return []reconcile.request{}
    }
    requests := make([]reconcile.request, len(usedbyinternals.items))
    for i, item := range usedbyinternals.items {
        requests[i] = reconcile.request{
            namespacedname: types.namespacedname{
                name:      item.getname(),
                namespace: item.getnamespace(),
            },
        }
    }
    return requests
}

既然您更新了问题,我建议您执行如下操作。

我正在创建一个新项目和 2 个控制器。请注意,第二个控制器命令不会随控制器一起创建资源。这是因为控制器 将观看外部资源。

mkdir demo && cd demo
go mod init example.io/demo
kubebuilder init --domain example.io --repo example.io/demo --plugins=go/v4-alpha
kubebuilder create api --group=demo --version v1 --kind internal --controller --resource
kubebuilder create api --group=other --version v2 --kind external --controller --resource=false
$ tree controllers
controllers
├── external_controller.go
├── internal_controller.go
└── suite_test.go

现在我们需要一些共享逻辑,例如将其添加到控制器包中。我们将从两个协调器中调用它。

// the interface may need tweaking
// depending on what you want to do with
// the reconiler
type reconciler interface {
 client.reader
 client.writer
 client.statusclient
}

func sharedlogic(r reconciler, kobj *demov1.internal) (ctrl.result, error) {
 // do your shared logic here operating on the internal object struct
 // this works out because the external controller will call this passing the
 // internal object
 return ctrl.result{}, nil
}

这是内部协调器的示例。

func (r *internalreconciler) reconcile(ctx context.context, req ctrl.request) (ctrl.result, error) {
 _ = log.fromcontext(ctx)
 obj := demov1.internal{}
 if err := r.get(ctx, req.namespacedname, &obj); err != nil {
  return ctrl.result{}, err
 }
 return sharedlogic(r, &obj)
}

在外部协调器中我们也做同样的事情。

func (r *ExternalReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 _ = log.FromContext(ctx)
 // note, we can use the internal object here as long as the external object
 // does contain the same fields we want. That means when unmarshalling the extra
 // fields are dropped. If this cannot be done, you could first unmarshal into the external
 // resource and then assign the fields you need to the internal one, before passing it down
 obj := demov1.Internal{}
 if err := r.Get(ctx, req.NamespacedName, &obj); err != nil {
  return ctrl.Result{}, err
 }
 return sharedLogic(r, &obj)
}

func (r *ExternalReconciler) SetupWithManager(mgr ctrl.Manager) error {
 return ctrl.NewControllerManagedBy(mgr).
 // note the external resource is imported from another project
 // you may be able to watch this without import by creating a minimal
 // type with the right GKV
  For(otherv2.External{}).
  Complete(r)
}

到这里,我们也就讲完了《观察其他控制器CR的Kubernetes控制器》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于的知识点!

版本声明
本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
GORM 支持选择预加载特定列GORM 支持选择预加载特定列
上一篇
GORM 支持选择预加载特定列
为什么golang中使用readCloser作为响应体?
下一篇
为什么golang中使用readCloser作为响应体?
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    542次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    508次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    497次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    484次学习
查看更多
AI推荐
  • 可图AI图片生成:快手可灵AI2.0引领图像创作新时代
    可图AI图片生成
    探索快手旗下可灵AI2.0发布的可图AI2.0图像生成大模型,体验从文本生成图像、图像编辑到风格转绘的全链路创作。了解其技术突破、功能创新及在广告、影视、非遗等领域的应用,领先于Midjourney、DALL-E等竞品。
    36次使用
  • MeowTalk喵说:AI猫咪语言翻译,增进人猫情感交流
    MeowTalk喵说
    MeowTalk喵说是一款由Akvelon公司开发的AI应用,通过分析猫咪的叫声,帮助主人理解猫咪的需求和情感。支持iOS和Android平台,提供个性化翻译、情感互动、趣味对话等功能,增进人猫之间的情感联系。
    32次使用
  • SEO标题Traini:全球首创宠物AI技术,提升宠物健康与行为解读
    Traini
    SEO摘要Traini是一家专注于宠物健康教育的创新科技公司,利用先进的人工智能技术,提供宠物行为解读、个性化训练计划、在线课程、医疗辅助和个性化服务推荐等多功能服务。通过PEBI系统,Traini能够精准识别宠物狗的12种情绪状态,推动宠物与人类的智能互动,提升宠物生活质量。
    32次使用
  • 可图AI 2.0:快手旗下新一代图像生成大模型,专业创作者与普通用户的多模态创作引擎
    可图AI 2.0图片生成
    可图AI 2.0 是快手旗下的新一代图像生成大模型,支持文本生成图像、图像编辑、风格转绘等全链路创作需求。凭借DiT架构和MVL交互体系,提升了复杂语义理解和多模态交互能力,适用于广告、影视、非遗等领域,助力创作者高效创作。
    33次使用
  • 毕业宝AIGC检测:AI生成内容检测工具,助力学术诚信
    毕业宝AIGC检测
    毕业宝AIGC检测是“毕业宝”平台的AI生成内容检测工具,专为学术场景设计,帮助用户初步判断文本的原创性和AI参与度。通过与知网、维普数据库联动,提供全面检测结果,适用于学生、研究者、教育工作者及内容创作者。
    48次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码