转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com

本文使用的Istio源码是 release 1.5。

Config Controller用于管理各种配置数据,包括用户创建的流量管理规则和策略。Istio目前支持三种类型的Config Controller:

  • MCP:是一种网络配置协议,用于隔离Pilot和底层平台(文件系统、K8s),使得Pilot无须感知底层平台的差异,从而达到解耦的目的。
  • File:通过监视器周期性地读取本地配置文件,将配置规则缓存在内存中,并维护配置的增加、更新、删除事件,当缓存由变化的时候,异步通知执行事件回调。
  • Kubernetes:基于k8s的Config发现利用了k8s Informer的监听能力。在k8s集群中,Config以CustomResource的形式存在。通过监听apiserver配置规则资源,维护所有资源的缓存Store,并触发事件处理回调函数。

ConfigController初始化

ConfigController是在initConfigController中被初始化的,在initConfigController方法中会调用makeKubeConfigController进行controller的初始化。

  1. func (s *Server) makeKubeConfigController(args *PilotArgs) (model.ConfigStoreCache, error) {
  2. //创建configClient
  3. configClient, err := controller.NewClient(args.Config.KubeConfig, "", collections.Pilot,
  4. args.Config.ControllerOptions.DomainSuffix, buildLedger(args.Config), args.Revision)
  5. if err != nil {
  6. return nil, multierror.Prefix(err, "failed to open a config client.")
  7. }
  8. //创建controller,并为config资源设置监听
  9. return controller.NewController(configClient, args.Config.ControllerOptions), nil
  10. }
  11. func NewController(client *Client, options controller2.Options) model.ConfigStoreCache {
  12. log.Infof("CRD controller watching namespaces %q", options.WatchedNamespace)
  13. // The queue requires a time duration for a retry delay after a handler error
  14. out := &controller{
  15. client: client,
  16. queue: queue.NewQueue(1 * time.Second),
  17. kinds: make(map[resource.GroupVersionKind]*cacheHandler),
  18. }
  19. // add stores for CRD kinds
  20. //获取所有的CRD类型
  21. for _, s := range client.Schemas().All() {
  22. //为每一种Config资源都创建一个informer,监听所有的Config资源
  23. out.addInformer(s, options.WatchedNamespace, options.ResyncPeriod)
  24. }
  25. return out
  26. }

初始化完controller之后会获取所有的CRD类型,为每一种Config资源都创建一个informer,监听所有的Config资源。

  1. Pilot = collection.NewSchemasBuilder().
  2. //MeshPolicy
  3. MustAdd(IstioAuthenticationV1Alpha1Meshpolicies).
  4. MustAdd(IstioAuthenticationV1Alpha1Policies).
  5. MustAdd(IstioConfigV1Alpha2Httpapispecbindings).
  6. MustAdd(IstioConfigV1Alpha2Httpapispecs).
  7. MustAdd(IstioMixerV1ConfigClientQuotaspecbindings).
  8. MustAdd(IstioMixerV1ConfigClientQuotaspecs).
  9. //DestinationRule
  10. MustAdd(IstioNetworkingV1Alpha3Destinationrules).
  11. //EnvoyFilter
  12. MustAdd(IstioNetworkingV1Alpha3Envoyfilters).
  13. //Gateway
  14. MustAdd(IstioNetworkingV1Alpha3Gateways).
  15. //ServiceEntry
  16. MustAdd(IstioNetworkingV1Alpha3Serviceentries).
  17. //Sidecar
  18. MustAdd(IstioNetworkingV1Alpha3Sidecars).
  19. //VirtualService
  20. MustAdd(IstioNetworkingV1Alpha3Virtualservices).
  21. MustAdd(IstioRbacV1Alpha1Clusterrbacconfigs).
  22. MustAdd(IstioRbacV1Alpha1Rbacconfigs).
  23. MustAdd(IstioRbacV1Alpha1Servicerolebindings).
  24. MustAdd(IstioRbacV1Alpha1Serviceroles).
  25. MustAdd(IstioSecurityV1Beta1Authorizationpolicies).
  26. MustAdd(IstioSecurityV1Beta1Peerauthentications).
  27. MustAdd(IstioSecurityV1Beta1Requestauthentications).
  28. Build()

这里定义好了所有要用到的Config资源类型,主要涉及网络配置、认证、鉴权、策略管理等。

ConfigController事件处理

下面我们看一下controller定义:

  1. type controller struct {
  2. client *Client
  3. queue queue.Instance
  4. kinds map[resource.GroupVersionKind]*cacheHandler
  5. }

client是调用controller.NewClient初始化的client;queue会在Informer监听到资源的变动的时候将数据push到队列中,controller在调用run方法的时候单独运行一个线程运行queue中的函数;kinds在调用addInformer方法的时候初始化进去。

queue.Instance的定义如下:

  1. type Task func() error
  2. type Instance interface {
  3. Push(task Task)
  4. Run(<-chan struct{})
  5. }
  6. type queueImpl struct {
  7. delay time.Duration
  8. tasks []Task
  9. cond *sync.Cond
  10. closing bool
  11. }

queueImpl继承了Instance接口,在调用push方法的时候,会将Task放入到tasks数组中,并在调用Run方法的时候消费数组中的数据。

controller继承了ConfigStoreCache接口:

  1. type ConfigStoreCache interface {
  2. ConfigStore
  3. // 注册规则事件处理函数
  4. RegisterEventHandler(kind resource.GroupVersionKind, handler func(Config, Config, Event))
  5. // 运行
  6. Run(stop <-chan struct{})
  7. // 配置缓存是否已同步
  8. HasSynced() bool
  9. }

ConfigStoreCache通过RegisterEventHandler接口为上面提到的配置资源都注册事件处理函数,通过Run方法启动控制器。

  1. func (c *controller) Run(stop <-chan struct{}) {
  2. log.Infoa("Starting Pilot K8S CRD controller")
  3. go func() {
  4. cache.WaitForCacheSync(stop, c.HasSynced)
  5. //单独启动一个线程运行queue里面的函数
  6. c.queue.Run(stop)
  7. }()
  8. for _, ctl := range c.kinds {
  9. go ctl.informer.Run(stop)
  10. }
  11. <-stop
  12. log.Info("controller terminated")
  13. }

在调用Run方法的时候会单独的启动一个线程调用queue的Run方法消费队列中的数据,并遍历所有的配置信息,调用informer的Run方法开启监听。

监听器的EventHandler通过如下代码注册:

  1. func (c *controller) newCacheHandler(
  2. schema collection.Schema,
  3. o runtime.Object,
  4. otype string,
  5. resyncPeriod time.Duration,
  6. lf cache.ListFunc,
  7. wf cache.WatchFunc) *cacheHandler {
  8. informer := cache.NewSharedIndexInformer(
  9. &cache.ListWatch{ListFunc: lf, WatchFunc: wf}, o,
  10. resyncPeriod, cache.Indexers{})
  11. h := &cacheHandler{
  12. c: c,
  13. schema: schema,
  14. informer: informer,
  15. }
  16. informer.AddEventHandler(
  17. cache.ResourceEventHandlerFuncs{
  18. AddFunc: func(obj interface{}) {
  19. incrementEvent(otype, "add")
  20. //将ADD事件发送至队列
  21. c.queue.Push(func() error {
  22. return h.onEvent(nil, obj, model.EventAdd)
  23. })
  24. },
  25. UpdateFunc: func(old, cur interface{}) {
  26. if !reflect.DeepEqual(old, cur) {
  27. incrementEvent(otype, "update")
  28. //将Update事件发送至队列
  29. c.queue.Push(func() error {
  30. return h.onEvent(old, cur, model.EventUpdate)
  31. })
  32. } else {
  33. incrementEvent(otype, "updatesame")
  34. }
  35. },
  36. DeleteFunc: func(obj interface{}) {
  37. incrementEvent(otype, "delete")
  38. //将Delete事件发送至队列
  39. c.queue.Push(func() error {
  40. return h.onEvent(nil, obj, model.EventDelete)
  41. })
  42. },
  43. })
  44. return h
  45. }

当Config资源创建、更新、删除时,EventHandler创建任务对象并将其发送到任务队列中,然后由任务处理线程处理。当对应的事件被调用的时候会触发onEvent方法,会调用到cacheHandler的onEvent方法,最后设置完毕后将cacheHandler返回,controller会将此cacheHandler设置到kinds数组中存下来。

下面我们看一下cacheHandler的定义:

  1. type cacheHandler struct {
  2. c *controller
  3. schema collection.Schema
  4. informer cache.SharedIndexInformer
  5. handlers []func(model.Config, model.Config, model.Event)
  6. }

cacheHandler在上面初始化的时候,会传入对应的controller、Schema、informer,然后在调用configController的RegisterEventHandler方法的时候会初始化对应的configHandler。

configController的RegisterEventHandler方法会在初始化DiscoveryService的时候调用initEventHandlers方法进行初始化:

  1. func (s *Server) initEventHandlers() error {
  2. ...
  3. if s.configController != nil {
  4. configHandler := func(old, curr model.Config, _ model.Event) {
  5. pushReq := &model.PushRequest{
  6. Full: true,
  7. ConfigTypesUpdated: map[resource.GroupVersionKind]struct{}{curr.GroupVersionKind(): {}},
  8. Reason: []model.TriggerReason{model.ConfigUpdate},
  9. }
  10. s.EnvoyXdsServer.ConfigUpdate(pushReq)
  11. }
  12. //遍历所有的资源
  13. for _, schema := range collections.Pilot.All() {
  14. // This resource type was handled in external/servicediscovery.go, no need to rehandle here.
  15. //ServiceEntry 这个资源不在这里注册,感兴趣的朋友可以自己找一下
  16. if schema.Resource().GroupVersionKind() == collections.IstioNetworkingV1Alpha3Serviceentries.
  17. Resource().GroupVersionKind() {
  18. continue
  19. }
  20. //注册configHandler到configController中
  21. s.configController.RegisterEventHandler(schema.Resource().GroupVersionKind(), configHandler)
  22. }
  23. }
  24. return nil
  25. }

initEventHandlers会调用collections.Pilot.All方法获取所有的资源配置,然后遍历调用RegisterEventHandler方法将configHandler函数注册到cacheHandler的handlers中,至于configHandler函数做了什么,我们到下一篇讲XdsServer的时候再讲。

这一部分的代码是比较绕的,这里画个图理解一下吧。

整个执行流程为:

总结

至此,ConfigController的核心原理及工作流程就介绍完毕了。本篇主要讲解了我们常用的Istio的Gateway、DestinationRule及VirtualService等配置是如何被Istio监听到并作出相应改变的。希望大家能有所收获。

Reference

https://ruofeng.me/2018/11/08/how-does-istio-pilot-push-eds-config/

https://zhaohuabing.com/post/2019-10-21-pilot-discovery-code-analysi

https://www.servicemesher.com/blog/envoy-proxy-config-deep-dive/

https://www.cnblogs.com/163yun/p/8962278.html

3.深入Istio:Pilot配置规则ConfigController的更多相关文章

  1. istio路由配置

    istio路由配置   istio的代理配置参考文档: 中文文档: https://istio.io/zh/docs/reference/config/istio.networking.v1alpha ...

  2. Istio 的配置分析

    Istio 的配置分析 目录 Istio 的配置分析 Analyzer 的消息格式 ConflictingMeshGatewayVirtualServiceHosts 问题解决 举例 Conflict ...

  3. quartz 时间配置规则

    quartz 时间配置规则 格式: [秒] [分] [小时] [日] [月] [周] [年]  序号 说明  是否必填  允许填写的值 允许的通配符  1  秒  是  0-59    , - * / ...

  4. Linux iptables 配置规则

    Linux iptables 防火墙配置规则 前言:把网上我感觉不错iptables的访问规则都统一在这里,以后做参考. modprobe ipt_MASQUERADE modprobe ip_con ...

  5. 【Web】Nginx配置规则

    Nginx配置基本说明 以下是nginx的基本配置文件如下(编辑命令:vi /usr/local/nginx/conf/nginx.conf): #user nobody; #nginx进程数,建议设 ...

  6. linux 下crontab相关定时触发的配置规则

    linux 下crontab相关定时触发的配置规则: 1.基本格式 :* * * * * command(分 时 日 月 周 命令)2.取值范围:分钟1-59 每分钟用*或者 */1表示小时1-23( ...

  7. dubbo之配置规则

    配置规则 向注册中心写入动态配置覆盖规则 1.该功能通常由监控中心或治理中心的页面完成. RegistryFactory registryFactory = ExtensionLoader.getEx ...

  8. Springboot中以配置类方式自定义Mybatis的配置规则(如开启驼峰映射等)

    什么是自定义Mybatis的配置规则? 答:即原来在mybatis配置文件中中我们配置到<settings>标签中的内容,如下第6-10行内容: 1 <?xml version=&q ...

  9. Istio DestinationRule 目标规则

    概念及示例 与VirtualService一样,DestinationRule也是 Istio 流量路由功能的关键部分.您可以将虚拟服务视为将流量如何路由到给定目标地址,然后使用目标规则来配置该目标的 ...

随机推荐

  1. 浅析 JIT 即时编译技术

    即时编译回顾 HotSpot 虚拟机执行 Java 程序时,先通过解释器对代码解释执行,发现某个方法或代码块执行比较频繁后,对热点代码进行编译,编译后生成与本地平台相关的机器码,再去执行机器码获得较高 ...

  2. Java学习的第三十六天

    1.2.1 public class cjava { public static void main(String[]args) { int a,b; a='A'; b='B'; System.out ...

  3. django支持多语言

    Django支持多语言切换 下面介绍下如何使网站或APP国际化,让其支持多种语言 . 官网 效果 1.创建locale文件夹 先在项目根目录下创建一个名为locale的文件夹,这个文件夹是用来存放dj ...

  4. python开发基础(二)-运算符以及数据类型

    ##运算符 算数运算符: ---> 赋值运算符 >>>返回结果为值 + # 加 - # 减 * # 乘 / # 除以 ** # 幂运算 % # 取余数 // # 取商 #### ...

  5. 5分钟GET我使用Github 5 年总结的这些骚操作!

    我使用 Github 已经有 5 年多了,今天毫无保留地把自己觉得比较有用的 Gihub 小技巧送给关注 JavaGuide 的各位小伙伴. 这篇文章肝了很久,就挺用心的,大家看内容就知道了. 如果觉 ...

  6. ubunutu16.04 更改普通用户权限注销后只有guest身份 没有用户身份

    第一次踩进百度经验的坑..... 之前对百度经验百信不疑,现在怀疑人生.. 网上搜了很多,也变得小心翼翼,最后姑且相信,但还是有点出入,以下是我的实践: (1)重启ubuntu系统,长按shift进入 ...

  7. 23longest-consecutive-sequence

    题目描述 给定一个无序的整数类型数组,求最长的连续元素序列的长度. 例如: 给出的数组为[100, 4, 200, 1, 3, 2], 最长的连续元素序列为[1, 2, 3, 4]. 返回这个序列的长 ...

  8. python菜鸟教程学习1:背景性学习

    https://www.runoob.com/python3/python3-intro.html 优点 简单 -- Python 是一种代表简单主义思想的语言.阅读一个良好的 Python 程序就感 ...

  9. mdp文件-Chapter2-NVT.mdp

    这是mdp文件系列的第二篇,介绍nvt平衡中要使用的mdp文件. 先上代码,nvt.mdp 1 title = OPLS Lysozyme NVT equilibration 2 define = - ...

  10. 开发IDE的一些设置

    一.修改和设置idea或eclipse的快捷键: 二.idea的settings的一些设置: settings 可以导出,也可以导入.也可以设置每次新建和新打开一个工程用同一个setting 三.全局 ...