Knative Eventing 中 Channel 如何注入默认 Provisioner
摘要: 在 Knative Eventing 中创建 Broker 时,如果不指定 provisioner, 系统会自动创建默认的 provisioner, 那么这个机制是如何实现的呢? 本文基于 Knative Eventing 0.5 版本,介绍了这个实现机制。
场景
通常的在创建Broker时,我们需要通过 spec.ChannelTemplate
指定使用某个具体的 Channel Provisioner。例如这样的Broker:
apiVersion: eventing.knative.dev/v1alpha1 kind: Broker metadata: name: pubsub-channel spec: channelTemplate: provisioner: apiVersion: eventing.knative.dev/v1alpha1 kind: ClusterChannelProvisioner name: gcp-pubsub
这里通过spec.ChannelTemplate
指定了名称为gcp-pubsub
的provisioner。那么我们也遇到过这样的Broker:
apiVersion: eventing.knative.dev/v1alpha1 kind: Broker metadata: name: default
并没有指定使用某个具体的 channel, 但创建完Broker之后会发现已经创建出来了Channel:
apiVersion: eventing.knative.dev/v1alpha1 kind: Channel metadata: ... name: default-broker-8ml79 namespace: default ownerReferences: - apiVersion: eventing.knative.dev/v1alpha1 blockOwnerDeletion: true controller: true kind: Broker name: default uid: 2e4c3332-6755-11e9-a81f-00163f005e02 spec: provisioner: apiVersion: eventing.knative.dev/v1alpha1 kind: ClusterChannelProvisioner name: in-memory ...
分析
我们知道 Broker创建之后,会通过 reconcile controller 会创建相应的Channel, 也就是下面这段代码:
// newChannel creates a new Channel for Broker 'b'. func newChannel(b *v1alpha1.Broker, l map[string]string) *v1alpha1.Channel { var spec v1alpha1.ChannelSpec if b.Spec.ChannelTemplate != nil { spec = *b.Spec.ChannelTemplate } return &v1alpha1.Channel{ ObjectMeta: metav1.ObjectMeta{ Namespace: b.Namespace, GenerateName: fmt.Sprintf("%s-broker-", b.Name), Labels: l, OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(b, schema.GroupVersionKind{ Group: v1alpha1.SchemeGroupVersion.Group, Version: v1alpha1.SchemeGroupVersion.Version, Kind: "Broker", }), }, }, Spec: spec, } }
分析上面这段代码,我们可以很清楚得出这样的结论:如果Broker中设置了Spec.ChannelTemplate
, 那么Channel中会直接使用ChannelTemplate所对应的provisioner。
但如果没有设置的话, 那么Channel中的spec应该设置为nil。但事实上设置了in-memory provisioner, 那么这个是在哪里注入的呢?
注入机制
经过定位源代码,我们发现在channel_defaults.go中,发现下面这段代码:
func (c *Channel) SetDefaults(ctx context.Context) { if c != nil && c.Spec.Provisioner == nil { // The singleton may not have been set, if so ignore it and validation will reject the // Channel. if cd := ChannelDefaulterSingleton; cd != nil { prov, args := cd.GetDefault(c.DeepCopy()) c.Spec.Provisioner = prov c.Spec.Arguments = args } } c.Spec.SetDefaults(ctx) }
分析一下,我们可以看到当c.Spec.Provisioner==nil
时, 会设置默认的Provisioner。
进一步分析ChannelDefaulterSingleton
, 我们可以在webhook中赋予了实现设置:
... // Watch the default-channel-webhook ConfigMap and dynamically update the default // ClusterChannelProvisioner. channelDefaulter := channeldefaulter.New(logger.Desugar()) eventingv1alpha1.ChannelDefaulterSingleton = channelDefaulter configMapWatcher.Watch(channeldefaulter.ConfigMapName, channelDefaulter.UpdateConfigMap) ...
接着分析发现 ChannelDefaulter 实现了 GetDefault 方法:
// GetDefault determines the default provisioner and arguments for the provided channel. func (cd *ChannelDefaulter) GetDefault(c *eventingv1alpha1.Channel) (*corev1.ObjectReference, *runtime.RawExtension) { // Because we are treating this as a singleton, be tolerant to it having not been setup at all. if cd == nil { return nil, nil } if c == nil { return nil, nil } config := cd.getConfig() if config == nil { return nil, nil } // TODO Don't use a single default, instead use the Channel's arguments to determine the type of // Channel to use (e.g. it can say whether it needs to be persistent, strictly ordered, etc.). dp := getDefaultProvisioner(config, c.Namespace) cd.logger.Info("Defaulting the ClusterChannelProvisioner", zap.Any("defaultClusterChannelProvisioner", dp)) return dp, nil }
并且这里是通过一个ConfigMap设置使用的默认provisioner, 这个ConfigMap名称为default-channel-webhook
, 没错可以在 Knative Eventing 安装文件中发现这个资源:
apiVersion: v1 data: default-channel-config: | clusterdefault: apiversion: eventing.knative.dev/v1alpha1 kind: ClusterChannelProvisioner name: in-memory namespacedefaults: some-namespace: apiversion: eventing.knative.dev/v1alpha1 kind: ClusterChannelProvisioner name: some-other-provisioner kind: ConfigMap metadata: name: default-channel-webhook namespace: knative-eventing
那么分析到此,我们梳理一下整个注入的流程:
结论
通过上面的分析, 我们现在了解了默认provisioner的注入机制, 同时我们也可以通过 webhook 修改默认的provisioner。
作者:元毅
原文链接
本文为云栖社区原创内容,未经允许不得转载。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
分库分表中间件的高可用实践
分库分表中间件的高可用实践 前言 分库分表中间件在我们一年多的锤炼下,基本解决了可用性和高性能的问题(只能说基本,肯定还有隐藏的坑要填),问题自然而然的就聚焦于高可用。本文就阐述了我们在这方面做出的一些工作。 哪些高可用的问题 作为一个无状态的中间件,高可用问题并没有那么困难。但是尽量减少不可用期间的流量损失,还是需要一定的工作的。这些流量损失主要分布在: (1)某台中间件所在的物理机突然宕机。 (2)中间件的升级和发布。 由于我们的中间件是作为数据库的代理提供给应用的,即应用把我们的中间件当做数据库,如下图所示: 所以出现上述问题后,业务上很难通过重试等操作去屏蔽这些影响。这就势必需要我们在底层做一些操作,能够自动的感知中间件的状态从而有效避免流量的损失。 中间件所在物理机宕机的情况 物理机宕机其实是一种常见现象,这时候应用一瞬间就没了响应。那么跑在上面的sql肯定也是失败了的(准确来说是未知状态,除非重新查询后端数据库,应用无法得知准确的状态)。这部分流量我们肯定是无法挽救。我们所做的是在client端(Druid数据源)能够快速的发现并剔除宕机的中间件节点。 发现并剔除不可用节点...
- 下一篇
如何利用开源风控系统 TH-Nubula(星云)防止撞库?
“撞库”是安全领域经常发生的一种黑产攻击事件。在常见的安全防护中,安全团队通常会在登陆接口设置安全策略来应对攻击。可是,一旦黑产更换攻击规则,就会导致策略失效。 在这样的情况下,我们需要的就不仅仅的表层的“防火墙”,而是一套完整的业务风控系统,它可以有效的规避风险,降低损失。 在这篇文章中,我们将介绍如何利用开源风控系统TH-Nebule(星云)防止“撞库”攻击。 文章会从“撞库”的介绍逐渐深入到对TH-Nebula的使用,包括:如何部署、如何使用、和为什么需要风控系统等。阐述为什么需要一套“系统”去解决业务安全问题,接着手把手教你部署本系统,以及如何利用咱们这套风控来阻断风险,并提供模拟测试demo。 TH-Nebula是由威胁猎人开源的风控系统,目前源码已放在Github和Gitee上,完全开放所有源代码,文档,以及安装包。 地址: https://github.com/threathunterX/nebula https://gitee.com/threathunter/nebula 0x00 如何防止撞库 1.什么是撞库? 说到撞库,先得从”社工库”说起,社工库是社会工程学数据...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,CentOS8安装Elasticsearch6.8.6
- 2048小游戏-低调大师作品
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Windows10,CentOS7,CentOS8安装Nodejs环境
- CentOS7安装Docker,走上虚拟化容器引擎之路
- SpringBoot2全家桶,快速入门学习开发网站教程