GMTC全球大前端技术大会(北京站)门票9折特惠截至本周五,点击立减¥480 了解详情
写点什么

Istio 控制面对接 Consul 注册中心

2020 年 10 月 22 日

Istio控制面对接Consul注册中心

伴随着非侵入式微服务技术 Service Mesh 服务网格的兴起,其解决了侵入式微服务框架的相关问题,实现了语言无关,对应用透明等能力。因此越来越多的开发者逐渐由传统的侵入式微服务解决方案(典型的技术方案为 Spring Cloud)转变为 Service Mesh 微服务解决方案。


作为 Service Mesh 领域的热门开放项目,Istio 为微服务提供无侵入的流量管理,安全通信,服务可见性等服务治理能力,目前 Istio 也基本成为了 Service Mesh 领域的事实标准。微服务项目开始考虑将自己的微服务应用向 Istio 进行迁移。


基于上述背景,Istio 中的替代服务发现主要基于 Kubernetes Service 来实现,同时结合百度云原生技术团队内部外部实践落地的场景,即发现部分开发者仍然希望使用第三方注册中心的现状,那么对于非 Kubernetes Service 上的服务数据应该如何分割到 Istio 中呢?


为解决这类问题,根本需要解决的问题为【服务发现】,即 Service Mesh 中微服务能够发现非 Kubernetes Service 中的服务,Istio 则需要对接支持第三方注册中心。


本文以 Istio 控制面对接第三方注册中心 Consul,为读者介绍 Istio 如何对接 Consul 注册中心以及具体的实践过程,同时为 Istio 如何对接第三方注册中心提供技术思路。


本文假设读者对 Kubernetes,Service Mesh,Helm 等有一定的了解,若您还尚未了解,请查阅相关资料。同时本文主要讲解 Istio 对接 Consul 注册中心,因此希望读者对 Consul 作为注册中心等基础知识有一定的了解。


如果您尚未了解 Consul 相关内容,请参考我们之前的公众号文章:Consul 作为注册中心在云环境的实践与应用。


Istio 中服务发现机制

默认服务发现机制

我们先看看 Istio 的主要架构:


  • 控制面板(控制平面):负责数据下发,如服务/服务实例数据,服务治理配置数据。

  • 数据面板(数据平面):高级代理负责具体的流量治理。


如下图,Istio 部署在 Kubernetes 平台后,替换的服务/服务实例数据布局 Kubernetes Service,Istio 控制面板(控制平面)列表监视 Kubernetes 中服务/服务实例数据,当数据发生变化后,Istio 控制平面将数据通过 XDS 方式推送至数据面板(数据平面)中的 Proxy。的服务无法调用 Consul 中部署的服务。



对接第三方注册中心的方式

通过查阅 Istio 官方文档及相应代码,发现 Istio 目前有如下三种方式对接第三方注册中心:



对接 Consul 注册中心方式

  • 整体架构


如本文前言所述,现存的应用程序对接的注册中心可能仍为第三方注册中心 Consul,因此如何将 Conss 上的服务/服务实例数据替换到 Istio 中呢?


这要求 Istio 控制平面能够对接 Consul 注册中心,考虑到成本最小化,此处使用官方提供的 Consul RegistryAdapter。Istio 启动后控制平面从 Consul 获取服务/服务实例数据,考虑到 Consul 中服务/服务实例的变更时效性,Istio 控制面通过 Long Polling 的方式监听 Consul XML 中心的数据变化。


如下图所示将 Consul 上的服务数据纳入到了 Istio 中。



  • Consul XML 适应 Istio


在 K8S 中资源都可以绑定 label 信息,那么在 Consul 中服务/服务实例的 label 信息具体怎样添加呢?


通过查看 Consul API 注册服务 接口,我们发现服务注册模型中有两个位置可以携带上述标签信息,分别为:


  • Tags (array: nil) -指定要分配给服务的标签列表。这些标签可用于以后的过滤,并通过 API 公开。我们建议使用 有效的 DNS 标签 以 与外部 DNS 兼容

  • Meta(map<string|string>: nil) -指定链接到服务实例的任意 KV 元数据。


通过官方文档说明,我们还不能完全知道 label 应该具体如何搬运,但通过查阅 Istio Pilot 代码后,我们发现 label 可携带在标签中和每个 label 的键和值按照分割符“ |” 分割,具体的实现代码逻辑(代码位置:consul.conversion.go)如下:


func convertLabels(labelsStr []string) labels.Instance {   out := make(labels.Instance, len(labelsStr))   for _, tag := range labelsStr {      // 按照 | 分割符号进行分割KV信息      vals := strings.Split(tag, "|")      // Labels not of form "key|value" are ignored to avoid possible collisions      if len(vals) > 1 {         out[vals[0]] = vals[1]      } else {         log.Debugf("Tag %v ignored since it is not of form key|value", tag)      }   }   return out}func convertLabels(labelsStr []string) labels.Instance {   out := make(labels.Instance, len(labelsStr))   for _, tag := range labelsStr {      // 按照 | 分割符号进行分割KV信息      vals := strings.Split(tag, "|")      // Labels not of form "key|value" are ignored to avoid possible collisions      if len(vals) > 1 {         out[vals[0]] = vals[1]      } else {         log.Debugf("Tag %v ignored since it is not of form key|value", tag)      }   }   return out}
复制代码


因此,在服务注册时,需要将标签信息存放在标签中,同时按照分割符“ |” 分割,如“ tag1 | value1”,如下为具体服务注册 注册 Service 接口的一个例子:


{  "ID": "instance-c7ac82ae14ef42d1a4ffa3b2ececa17f-local-provider-demo-172-22-204-83-provider-demo-10001",  #Instance ID确保一个region唯一  "Name": "provider-demo",  # 服务名  "Tags": [    "tag1|value1",               # 标签    "protocol|http"              # 标明其为http服务  ],  "Address": "127.0.0.1",   # 服务ip地址  "Port": 9999,             # 服务提供服务端口号  "Meta": {                 # metadata信息,kv形式    "protocol": "http"      # 标明其为http服务                  },  "Check": {                "TTL": "30s",                          # TTL健康检查    "deregisterCriticalServiceAfter": "30s"  # 异常服务下线  }}
复制代码


实践篇

本文实践部署的版本分别为:


  • 领事 1.6.1

  • Istio 1.6.8


领事部署

领事部署安装的途径有多种,本文中采用头盔在 K8S 环境中安装领事方式其他请参考官方安装文档。


  • 下载头盔包


K8S 环境中安装 Consul 时,官方推荐的方式为通过 Helm 来进行安装,为保证安装的顺利进行,建议您安装 Helm 3,Helm 安装完成后,下载 consul-helm (https://github.com/hashicorp / consul-helm)Helm 包来安装 Consul。


  • 安装领事


通常来说,配置无法满足实际的需求,因此可以通过自定义配置 config.yaml 文件覆盖配置配置达到定制化安装的目的:


# 通过覆盖默认配置达到定制化安装目的$ helm install consul ./consul-helm -f config.yaml -n test
复制代码


下面指定一个笔者实践的配置 config.yaml:


ui:  service:    type: 'NodePort'  # Consul UI界面通过NodePort的形式访问connectInject:  enabled: false      # 关闭consul connectInject功能client:  enabled: false       # 关闭consul client节点模式,即所有的节点为consul server# Use only one Consul server for local developmentserver:  enabled: true  storage: 1Gi                    # 自定义的strage信息  storageClass: rook-ceph-block  replicas: 1                     # 定义的副本信息,生产环境中建议为3个  bootstrapExpect: 1              # Consul集群正常启动时预期的节点数量,即集群中节点数目达到该数目时才正常选举启动  disruptionBudget:    enabled: true    maxUnavailable: 0
复制代码


注:若您想要配置更多 Consul 的功能,请参考:Helm Chart Reference(https://www.consul.io/docs/k8s/helm)。


安装后查看服务信息,可以看到 consul-consul-ui 的访问方式为 NodePort,其对应的端口为 30267,即后续可以通过 http:// {node_ip}:30267 访问注册中心。


$kubectl get service -n testconsul-consul-dns      ClusterIP   10.20.62.108    <none>   53/TCP,53/UDP                                                           8m38sconsul-consul-server   ClusterIP   None            <none>   8500/TCP,8301/TCP,8301/UDP,8302/TCP,8302/UDP,8300/TCP,8600/TCP,8600/UDP   8m38sconsul-consul-ui       NodePort    10.20.154.128   <none>   80:30267/TCP  

复制代码


Istio 部署

  • 下载安装包


在下载页下载安装包,注意选择对应的操作系统安装包,本文以的 MacOS 为例下载了 istio-1.6.8-osx.tar.gz,解压后进入 istio 目录。


# 进入istio目录,其中目录samples目录用于存放示例Bookinfo Application,bin目录存放istioctl命令,manifests用于存放的安装清单文件$ cd istio-1.6.8
复制代码


将 istioctl 命令加入路径


$ export PATH=$PWD/bin:$PATH
复制代码


  • 安装 Istio 并集成领事


Istio 1.6 中组件已经完成了精简,即 Istio 之前版本的多种组件已经完全统一至 Istiod 中,因此我们通过引用 Istio 官方文档对 pilot-discovery (控制面主要实现)命令参数说明,发现了对接 Consul XML 中心的参数说明:



即通过 pilot -discovery --registries = Consul — consulserverURL = http:// { {node_ip}}:39267 / ,但是这些参数具体在哪里配置呢?


通过对官方文档查阅,发现可以自定义清单来完成安装,我们修改清单 yaml 来指定参数:


# 文件位置:istio-1.6.8/manifests/charts/istio-control/istio-discovery/templates...  containers:        - name: discovery          image: pilot:dev  # 本文中修复了Consul数据变更后Istio推送失效的问题,因此重新构建了镜像{{- if .Values.global.imagePullPolicy }}          imagePullPolicy: {{ .Values.global.imagePullPolicy }}{{- end }}          args:          - "discovery"          - --monitoringAddr=:15014          - --registries=Kubernetes,Consul  # 考虑后面要部署BookInfo Application,因此可以对接多个注册中心,即Kubernetes和Consul,读者可根据实际情况选择集成那种注册中心          - --consulserverURL=http://{node_ip}:30267  # 注意{node_ip}需要替换为具体的地址...
复制代码


修改完成后完成最终部署:


# 注意此处profile=demo本质上对应了一系列的安装清单文件,manifests 目录中的清单文件夹manifests中文件会对默认的profile demo的内容进行覆盖配置安装$ istioctl install --charts=./manifests --set profile=demo
复制代码


最终我们在 default 命令空间下开启自动注入 Sidecar 功能:


$ kubectl label namespace default istio-injection=enabled
复制代码


为验证 XDS 规则等下发情况,我们参考官方 Bookinfo 应用程序 文档部署了示例。同时部署了服务 provider-demo,其注册在 Consul 注册中心上。


踩坑篇

对接过程发现了两个问题:


  1. XDS 变更变更失效,即 Consul XML 中心的中心。

  2. Istio 无法对接开启开启 ACL 鉴权认证的 Consul 注册中心。


XDS 变更引导为何失效

当部署完 BookInfo 应用程序示例后,通过重新修改 Consul 上的服务 provider-demo 实例信息,笔者满心欢喜进入 istio-proxy 容器访问 http://127.0.0.1:15000/config_dump 查询 envoy configdump 中的数据,有望能够将 Consul XML 中心上更改的服务 provider-demo 在 envoy configdump 中查询到,但查询数据发现更改的服务数据 provider-demo 无需通过 XDS 完成更改替换,这是什么原因呢?带着这样的疑问,笔者决定调试一下代码。


通过代码调试发现(代码位置:bootstrap.server.go),领事服务数据发生变化后,已经引起数据变更事件,但对应的 PushRequest.ConfigUpdated 中 ConfigKey.Name 始终不正确,该些主要表明具体的那个那个服务发生了变化,以服务 provier-demo 变更为例,预期该插入的变量为“ provider-demo.service.consul”,而实际却是“ .service.consul”,最终导致该数据被推前【被误判为不应该下发该数据],最终导致变更数据没有通过 XDS 进行下发。



该问题笔者在 Istio 代码的基础上完成了修改并完成重新重组验证,现有该问题已经修改,后续笔者也将会将提炼反馈给 Istio 社区。


如何对接开启了 ACL 认证鉴权的 Consul 注册中心

生产环境中的 Consul 注册中心经常都开启了 ACL 认证鉴权,但笔者在对接过程发现中 Istio 控制面代码标记并没设置设置 Consul ACL 令牌的配置项,笔者修改了 Istio 代码设置 Consul 令牌,用于处理从 Consul 注册中心获取数据,目前已经能够支持对接开启了 ACL 鉴权认证的 Consul 注册中心,后续笔者也会将 PR 反馈给 Istio 社区。


笔者通过亲身实践,发现 Istio 对接第三方注册中心尤其是对接 Consul 注册中心目前还存在一些功能问题待解决,后续笔者也将问题和解决方案及时反馈给社区,推动该问题的解决,同时希望更多的人能参与其中共建繁荣的 Istio 社区。


笔者有幸经历了百度由传统的微服务框架 Spring Cloud(Java 生态中微服务一体化解决方案)向 Service Mesh(服务网格,转变微服务一体化解决方案)架构的转变,实践了将第三方注册中心 Consul 集成至 Istio 的生态中,望此能够让读者对 Istio 集成第三方注册中心 Consul 有一定的了解。


附录:


《什么是 Istio?》:https://istio.io/v1.6/docs/concepts/what-is-istio/


《在 Kubernetes 上安装 Consul》:https://www.consul.io/docs/k8s/installation/install


《快速入门》:https://istio.io/v1.6/docs/setup/getting-started/


作者简介:


刘超,百度研发工程师,现就职于百度基础架构部云原生团队,并和参与百度内部外部多个大规模微服务化改造,专注于微服务及云原生领域相关技术,对 Spring Cloud ,服务网格,Istio,领事等方向有深入的研究和实践。


2020 年 10 月 22 日 14:421759

评论 1 条评论

发布
用户头像
2020 年 12 月 01 日 11:39
回复
没有更多了
发现更多内容

LeetCode题解:剑指 Offer 40. 最小的k个数,二叉堆,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

即构低延迟直播产品L3,打造更优质的实时互动体验

ZEGO即构

公安大数据可视化指挥决策平台建设,智慧警务系统开发

WX13823153201

京东将上线社区团购“京喜拼拼”:社区团购是否是一次泡沫大战

石头IT视角

一代版本一代神:利用Docker在Win10系统极速体验Django3.1真实异步(Async)任务

刘悦的技术博客

django python3.x 异步 异步任务

生产环境全链路压测建设历程 22:FAQ 1&2

数列科技杨德华

全链路压测 七日更

智慧警务平台搭建,大数据时代下的警务模式

t13823115967

智慧警务大数据系统开发

网易有道 iOS二面经验分享

iOSer

ios 面试题 网易 大厂面试 iOS面试

花火交易所APP开发|花火交易所软件系统开发

开發I852946OIIO

系统开发

AI技术在音视频领域的发展

anyRTC开发者

人工智能 ios android AI WebRTC

架构师训练营第六周总结

Geek_xq

推陈出新,一步到位,智慧水务这么用效率翻倍

一只数据鲸鱼

物联网 数据采集 智慧城市 组态软件 智慧水务

博睿数据支持腾讯云函数监控,Serverless时代已来临

博睿数据

Serverless APM 监控

咨询师的诱惑

escray

面经 大龄程序员 面试经历 101次面试

数字资产钱包系统开发及介绍

系统开发咨询:I76-883I-5I52 邓森

也谈“中年焦虑”

程序员架构进阶

方法论 职业规划 中年危机

简明设计模式—创建型

2970

golang 设计模式

智慧公安情报研判大数据系统分析平台搭建

t13823115967

智慧公安

看完这篇,保证让你真正明白:分布式系统的CAP理论、CAP如何三选二

四猿外

架构 分布式系统 CAP CAP原理 CAP理论

架构师训练营 1 期第 13 周:数据应用(二) - 作业

灵霄

极客大学架构师训练营

太平金科助力“开局之战”顺利启动,博睿数据“A+N”一体化解决方案全力护航

博睿数据

APM npm AIOPS

轮子虽好,也要知其所以然!(Lombok操作实例)

程序员小毕

Java 源码 架构 开发工具 lombok

测开之函数进阶· 第5篇《偏函数》

清菡

测试开发

架构师训练营第六周作业

Geek_xq

京东城市时空数据引擎JUST亮相中国数据库技术大会(附PPT链接)

京东科技开发者

数据库 nosql

接口测试-使用mock生产随机数据

测试人生路

接口测试

大数据ETL批量调度,这几款工具都需要去掌握了解

会飞的鱼

大数据处理 kettle 运维自动化 海豚调度 ETL算法

年前成功拿下35K+16薪美团Java架构师Offer!考点、面试题分享送给明年金三银四的你

Java架构追梦

Java 架构 面试 美团 offer

IDEA插件:多线程文件下载插件开发

Silently9527

Java 多线程 idea插件 文件传输

Devil Fruit恶魔果实APP系统软件开发

开發I852946OIIO

系统开发

互联网寒冬下,程序员如何化解危机?答案全在这份阿里Java知识地图里

比伯

Java 编程 程序员 面试 计算机

Istio控制面对接Consul注册中心-InfoQ