Kubernetes与Istio微服务架构
详细介绍了什么是istio,在微服务中解决了什么问题,并且使用较新版本的k8s与istio部署Bookinfo示例作为参考。
Last updated
详细介绍了什么是istio,在微服务中解决了什么问题,并且使用较新版本的k8s与istio部署Bookinfo示例作为参考。
Last updated
官方对 istio 的介绍浓缩成了一句话:
An open platform to connect, secure, control and observe services.
翻译过来,就是”连接、安全加固、控制和观察服务的开放平台“。开放平台就是指它本身是开源的,服务对应的是微服务,也可以粗略地理解为单个应用。中间的四个动词就是 istio 的主要功能,官方也各有一句话的说明。这里再阐释一下: 连接(Connect):智能控制服务之间的调用流量,能够实现灰度升级、AB 测试和红黑部署等功能安全加固(Secure):自动为服务之间的调用提供认证、授权和加密控制(Control):应用用户定义的 policy,保证资源在消费者中公平分配观察(Observe):查看服务运行期间的各种数据,比如日志、监控和 tracing,了解服务的运行情况
连接(Connect):智能控制服务之间的调用流量,能够实现灰度升级、AB 测试和红黑部署等功能
安全加固(Secure):自动为服务之间的调用提供认证、授权和加密
控制(Control):应用用户定义的 policy,保证资源在消费者中公平分配
观察(Observe):查看服务运行期间的各种数据,比如日志、监控和 tracing,了解服务的运行情况
虽然听起来非常高级,功能非常强大,但是一股脑出现这么多名词,还都是非常虚的概念,说了跟没说一样。要想理解上面这几句话的含义,我们还是从头说起,先聊聊 service mesh。
NOTE:其实 istio 的源头是微服务,但这又是一个比较大的话题,目前可以参考网络上各种文章。如果有机会,我们再来聊聊微服务。
一般介绍 service mesh 的文章都会从网络层的又一个抽象说起,把 service mesh 看做建立在 TCP 层之上的微服务层。我这次换个思路,从 service mesh 的技术根基——网络代理来分析。 说起网络代理,我们会想到翻墙,如果对软件架构比较熟悉的会想到 Nginx 等反向代理软件。其实网络代理的范围比较广,可以肯定的说,有网络访问的地方就会有代理的存在。 Wikipedia 对代理的定义如下:
In computer networks, a proxy server is a server (a computer system or an application) that acts as an intermediary for requests from clients seeking resources from other servers.
NOTE:代理可以是嵌套的,也就是说通信双方 A、B 中间可以多多层代理,而这些代理的存在有可能对 A、B 是透明的。 简单来说,网络代理可以简单类比成现实生活中的中介,本来需要通信的双方因为各种原因在中间再加上一道关卡。本来双方就能完成的通信,为何非要多此一举呢?那是因为代理可以为整个通信带来更多的功能,比如: 拦截:代理可以选择性拦截传输的网络流量,比如一些公司限制员工在上班的时候不能访问某些游戏或者电商网站,再比如把我们和世界隔离开来的 GFW,还有在数据中心中拒绝恶意访问的网关统计:既然所有的流量都经过代理,那么代理也可以用来统计网络中的数据信息,比如了解哪些人在访问哪些网站,通信的应答延迟等缓存:如果通信双方比较”远“,访问比较慢,那么代理可以把最近访问的数据缓存在本地,后面的访问不用访问后端来做到加速。CDN 就是这个功能的典型场景分发:如果某个通信方有多个服务器后端,代理可以根据某些规则来选择如何把流量发送给多个服务器,也就是我们常说的负载均衡功能。比如著名的 Nginx 软件跳板:如果 A、B 双方因为某些原因不能直接访问,而代理可以和双方通信,那么通过代理,双方可以绕过原来的限制进行通信。这应该广大中国网民比较熟悉的场景注入:既然代理可以看到流量,那么它也可以修改网络流量,可以自动在收到的流量中添加一些数据,比如有些宽带提供商的弹窗广告……
不是要讲 service mesh 吗?为什么扯了一堆代理的事情?因为 service mesh 可以看做是传统代理的升级版,用来解决现在微服务框架中出现的问题,可以把 service mesh 看做是分布式的微服务代理。 在传统模式下,代理一般是集中式的单独的服务器,所有的请求都要先通过代理,然后再流入转发到实际的后端。而在 service mesh 中,代理变成了分布式的,它常驻在了应用的身边(最常见的就是 kubernetes sidecar 模式,每一个应用的 pod 中都运行着一个代理,负责流量相关的事情)。这样的话,应用所有的流量都被代理接管,那么这个代理就能做到上面提到的所有可能的事情,从而带来无限的想象力。
此外,原来的代理都是基于网络流量的,一般都是工作在 IP 或者 TCP 层,很少关心具体的应用逻辑。但是 service mesh 中,代理会知道整个集群的所有应用信息,并且额外添加了热更新、注入服务发现、降级熔断、认证授权、超时重试、日志监控等功能,让这些通用的功能不必每个应用都自己实现,放在代理中即可。换句话说,service mesh 中的代理对微服务中的应用做了定制化的改进!
就这样,借着微服务和容器化的东风,传统的代理摇身一变,成了如今炙手可热的 service mesh。应用微服务之后,每个单独的微服务都会有很多副本,而且可能会有多个版本,这么多微服务之间的相互调用和管理非常复杂,但是有了 service mesh,我们可以把这块内容统一在代理层。 有了看起来四通八达的分布式代理,我们还需要对这些代理进行统一的管理。手动更新每个代理的配置,对代理进行升级或者维护是个不可持续的事情,在前面的基础上,在加上一个控制中心,一个完整的 service mesh 就成了。管理员只需要根据控制中心的 API 来配置整个集群的应用流量、安全规则即可,代理会自动和控制中心打交道根据用户的期望改变自己的行为。
NOTE:所以你也可以理解 service mesh 中的代理会抢了 Nginx 的生意,这也是为了 Nginx 也要开始做 NginMesh 的原因。
虽然看起来非常炫酷,功能也很强大,但是一个架构和产品出来都是要解决具体的问题。所以这部分我们来看看微服务架构中的难题以及 istio 给出的答案。 首先,原来的单个应用拆分成了许多分散的微服务,它们之间相互调用才能完成一个任务,而一旦某个过程出错(组件越多,出错的概率也就越大),就非常难以排查。 用户请求出现问题无外乎两个问题:错误和响应慢。如果请求错误,那么我们需要知道那个步骤出错了,这么多的微服务之间的调用怎么确定哪个有调用成功?哪个没有调用成功呢?如果是请求响应太慢,我们就需要知道到底哪些地方比较慢?整个链路的调用各阶段耗时是多少?哪些调用是并发执行的,哪些是串行的?这些问题需要我们能非常清楚整个集群的调用以及流量情况。
此外,微服务拆分成这么多组件,如果单个组件出错的概率不变,那么整体有地方出错的概率就会增大。服务调用的时候如果没有错误处理机制,那么会导致非常多的问题。比如如果应用没有配置超时参数,或者配置的超时参数不对,则会导致请求的调用链超时叠加,对于用户来说就是请求卡住了;如果没有重试机制,那么因为各种原因导致的偶发故障也会导致直接返回错误给用户,造成不好的用户体验;此外,如果某些节点异常(比如网络中断,或者负载很高),也会导致应用整体的响应时间变成,集群服务应该能自动避开这些节点上的应用;最后,应用也是会出现 bug 的,各种 bug 会导致某些应用不可访问。这些问题需要每个应用能及时发现问题,并做好对应的处理措施。
应用数量的增多,对于日常的应用发布来说也是个难题。应用的发布需要非常谨慎,如果应用都是一次性升级的,出现错误会导致整个线上应用不可用,影响范围太大;而且,很多情况我们需要同时存在不同的版本,使用 AB 测试验证哪个版本更好;如果版本升级改动了 API,并且互相有依赖,那么我们还希望能自动地控制发布期间不同版本访问不同的地址。这些问题都需要智能的流量控制机制。
为了保证整个系统的安全性,每个应用都需要实现一套相似的认证、授权、HTTPS、限流等功能。一方面大多数的程序员对安全相关的功能并不擅长或者感兴趣,另外这些完全相似的内容每次都要实现一遍是非常冗余的。这个问题需要一个能自动管理安全相关内容的系统。
上面提到的这些问题是不是非常熟悉?它们就是 istio 尝试解决的问题,如果把上面的问题和 istio 提供的功能做个映射,你会发现它们是非常匹配,毕竟 istio 就是为了解决微服务的这些问题才出现的。
虽然 istio 能解决那么多的问题,但是引入 istio 并不是没有代价的。最大的问题是 istio 的复杂性,强大的功能也意味着 istio 的概念和组件非常多,要想理解和掌握 istio ,并成功在生产环境中部署需要非常详细的规划。一般情况下,集群管理团队需要对 kubernetes 非常熟悉,了解常用的使用模式,然后采用逐步演进的方式把 istio 的功能分批掌控下来。
第一步
,自然是在测试环境搭建一套 istio 的集群,理解所有的核心概念和组件。了解 istio 提供的接口和资源,知道它们的用处,思考如何应用到自己的场景中,然后是熟悉 istio 的源代码,跟进社区的 issues,了解目前还存在的 issues 和 bug,思考如何规避或者修复。这一步是基础,需要积累到 istio 安装部署、核心概念、功能和缺陷相关的知识,为后面做好准备。
第二步
,可以考虑接入 istio 的观察性功能,包括 logging、tracing、metrics 数据。应用部署到集群中,选择性地(一般是流量比较小,影响范围不大的应用)为一些应用开启 istio 自动注入功能,接管应用的流量,并安装 prometheus 和 zipkin 等监控组件,收集系统所有的监控数据。这一步可以试探性地了解 istio 对应用的性能影响,同时建立服务的性能测试基准,发现服务的性能瓶颈,帮助快速定位应用可能出现的问题。此时,这些功能可以是对应用开发者透明的,只需要集群管理员感知,这样可以减少可能带来的风险。
第三步
,为应用配置 timeout 超时参数、自动重试、熔断和降级等功能,增加服务的容错性。这样可以避免某些应用错误进行这些配置导致问题的出现,这一步完成后需要通知所有的应用开发者删除掉在应用代码中对应的处理逻辑。这一步需要开发者和集群管理员同时参与。
第四步
,和 ingress、helm、应用上架等相关组件和流程对接,使用 istio 接管应用的升级发布流程。让开发者可以配置应用灰度发布升级的策略,支持应用的蓝绿发布、金丝雀发布以及 AB 测试。
第五步
,接入安全功能。配置应用的 TLS 互信,添加 RBAC 授权,设置应用的流量限制,提升整个集群的安全性。因为安全的问题配置比较繁琐,而且优先级一般会比功能性相关的特性要低,所以这里放在了最后。
当然这个步骤只是一个参考,每个公司需要根据自己的情况、人力、时间和节奏来调整,找到适合自己的方案。
在Service Mesh中,我们需要了解Data Plane和Control Plane两个概念:
Data Plane:作用是处理网格内服务间的通信,并完成服务发现、负载均衡、流量管理、健康检查等功能;
Control Plane:作用是管理和配置智能代理用于路由流量,同时配置Mixers来应用策略、收集指标。
Istio相关Core组件
Envoy:Istio 使用 Envoy调解服务网格中所有服务的入站和出站流量。属于数据平面。
Mixer:负责在服务网格上执行访问控制和使用策略,以及收集从Envoy和其他服务自动监控到的数据。
Pilot:为 Envoy sidecar 提供服务发现功能,为智能路由(例如 A/B 测试、金丝雀部署等)和弹性(超时、重试、熔断器等)提供流量管理功能。属于控制平面。
Citadel:提供访问控制和用户身份认证功能。
Istio可视化管理组件
Vistio:用于近乎实时地监控应用程序和集群之间的网络流量。 可以参考:https://www.yangcs.net/posts/vistio-visualize-your-istio-mesh-using-netflixs-vizceral/
Kiali:提供可视化服务网格拓扑、断路器和请求率等功能。Kiali还包括 Jaeger Tracing,可以提供开箱即用的分布式跟踪功能。 可以参考:https://jimmysong.io/istio-handbook/setup/istio-observability-tool-kiali.html
jaeger:用于展示istio微服务调用链关系,以及微服务工作状态监测。注意,在生产环境中,你应当使用Elasticsearch或cassandra持久化存储jaeger数据。 可以参考:https://blog.csdn.net/ywq935/article/details/80599297 https://mathspanda.github.io/2018/09/19/jaeger-deploy/ https://blog.frognew.com/2017/12/opentracing-jaeger-3.html
Kiali、Jaeger、prometheus、grafana管理工具,将和Istio一并部署
使用Helm部署Istio
依赖环境
Helm 2.14.2
Kubernetes 1.15.2
Istio 1.2.7
下载helm2.14.2安装包,解压后移动到bin目录下
下载并解压缩istio的发布包
Istio的Chart在istio-1.2.7/install/kubernetes/helm目录中,这个Chart包含了下面的代码文件
我安装的Helm版本高于2.10的2.14,所以就不再需要手动使用kubectl安装Istio的CRD。如果低于2.10,那么,则需要执行如下命令安装。
查看安装的CRD
通过各个组件在vaule file的enabled flag启用或禁用,下面创建名称为istio.yaml的vaule file,将几个默认禁用的组件也启用
创建Service account
安装 Tiller 并为其配置 Service account
注: 这里修改了另外两点:
1.设置 Tiller 的安装源为阿里云源
2.设置 Helm 的稳定存储库为阿里云的仓库
设置并创建namespace: istio
创建名称为kiali的secret。
执行helm安装Istio命令
确认一下各个组件的Pod正常运行
Istio 以一个项目的形式部署到 Kubernetes 集群中。我们可以看到,部署好的 pods 中,除了有 istio-citadel、istio-egressgateway、istio-ingressgateway、istio-pilot 等 Istio 本身的功能组件,还集成了微服务相关的监控工具,如:grafana、jaeger-agent、kiali、prometheus。正是这些功能丰富且强大的监控工具,帮助 Istio实现了微服务的可视化管理。
运行示例Bookinfo
您可以部署自己的应用或者示例应用程序如 Bookinfo。注意:应用程序必须使用 HTTP/1.1 或 HTTP/2.0 协议来传递 HTTP 流量,因为 HTTP/1.0 已经不再支持。
如果运行 Pod 的 namespace 被标记为 istio-injection=enabled 的话,Istio-Initializer 会向应用程序的 Pod 中自动注入 Envoy 容器:
如果您没有安装 Istio-initializer-injector 的话,您必须使用 istioctl kube-inject 命令在部署应用之前向应用程序的 Pod 中手动注入 Envoy 容器:
Bookinfo 应用由四个单独的微服务构成,用来演示多种 Istio 特性,包含:
productpage :productpage 微服务会调用 details 和 reviews 两个微服务,用来生成页面。
details :这个微服务包含了书籍的信息。
reviews :这个微服务包含了书籍相关的评论。它还会调用 ratings 微服务。
ratings :ratings 微服务中包含了由书籍评价组成的评级信息。
reviews 微服务有 3 个版本:
v1 版本不会调用 ratings 服务。
v2 版本会调用 ratings 服务,并使用 1 到 5 个黑色星形图标来显示评分信息。
v3 版本会调用 ratings 服务,并使用 1 到 5 个红色星形图标来显示评分信息。
下图展示了这个应用的端到端架构。
运行示例bookinfo,并开启Sidecar自动注入。
访问productpage http://172.16.0.180:31380/productpage
31380端口可以通过命令获取
使用Ingress暴露管理服务
完成Istio的安装后,可以看到安装的组件除了Istio架构中的数据平面和控制平面的各个核心组件,还部署了 Prometheus、Grafana、Jaeger、Kiali等辅助组件。在云原生生态中,我们已经对这些组件很熟悉了。
Prometheus:监控系统,收集Istio的监控数据
Grafana:监控信息的图表展现,Istio部署的Grafana为我们内置了各个组件相关的Dashboard
Jaeger:分布式跟踪系统,Istio中集成Jaeger可以对基于Istio的微服务实现调用链跟踪、依赖分析,为性能优化和故障排查提供支持
kiali:kiali作为Istio的可视化管理工具,可以认为是Istio的UI,可以展现服务的网络拓扑、服务的容错情况(超时、重试、短路等)、分布式跟踪等 这些辅助组件都有自己的web界面,这里我们使用ingress的方式将这些组件暴露到集群外,以便在集群外部访问。Istio支持使用自带的istio-ingressgateway将服务暴露到集群外部,这个和Kubernetes中暴露Ingress Controller类似,有很多种方式,如NodePort,LoadBalancer,或直接开启hostNetwork: true等等。为了便于统一管理K8s集群中的服务暴露,笔者更倾向使用Traefik Ingress。
使用Ingress暴露istio服务 编写ingress yaml文件,如下 istio-ingress.yaml
执行部署命令
外部客户端,配置hosts地址解析,如下
访问jaeger 浏览器访问Jaeger之前可以多次刷新productpage页面以便产生访问请求等。选择productpage.default可以查看整个调用链。使用istio.jaeger-query.com域名访问,结果展示:
访问kiali 使用域名istio.kiali.com访问kiali页面。用户名admin,密码:。
访问prometheus 使用域名istio.prometheus.com访问prometheus页面。
访问grafana 使用域名istio.grafana.com访问prometheus页面。
要成为服务网格的一部分,Kubernetes 集群中的 Pod 和服务必须满足以下几个要求:
需要给端口正确命名:服务端口必须进行命名。端口名称只允许是<协议>[-<后缀>-]模式;
Pod必须关联到 Kubernetes服务:如果一个 Pod 属于多个服务,这些服务不能在同一端口上使用不同协议,例如 HTTP 和 TCP。
Deployment应带有app以及version标签:每个 Deployment 都应该有一个有意义的 app 标签和一个用于标识 Deployment 版本的 version 标签。Istio 会用 app 和 version 标签来给监控指标数据加入上下文信息。
本文实践了使用istio官方提供的helm chart在Kubernetes上部署Istio 1.0.6的过程,并使用traefik ingress将Istio集成的Prometheus、Grafana、Jaeger、Kiali等辅助组件暴露到集群外部,并对进入集群的流量进行管理。
在生产环境中,如果是基于公有云,如阿里云、AWS等运行Istio,建议Ingress的IP地址使用ELB地址;如果是自建的平台,则建议使用HAproxy+Keepalived提供的VIP地址,作为Ingress的IP地址,实现高可用。
如果Ingress服务,需要暴露在公网,应当使用CA认证机构颁发的证书https化(如使用cert-manager)。此外建议使用NFS、Ceph等方案实现Istio监控以及微服务应用的数据持久化存储。
Istio 的架构在数据中心和集群管理中非常常见,每个 agent 分布在各个节点上(可以是服务器、虚拟机、pod、容器)负责接收指令并执行,以及汇报信息;控制中心负责汇聚整个集群的信息,并提供 API 让用户对集群进行管理。kubernetes 也是类似的架构,SDN(Software Defined Network) 也是如此。相信以后会有更多类似架构的出现,这是因为数据中心要管理的节点越来越多,我们需要把任务执行分布到各节点(agent 负责的功能),同时也需要对整个集群进行管理和控制(control plane 的功能),完全去中心化的架构是无法满足后面这个要求的。
Istio 的出现为负责的微服务架构减轻了很多的负担,开发者不用关心服务调用的超时、重试、rate limit 的实现,服务之间的安全、授权也自动得到了保证;集群管理员也能够很方便地发布应用(AB 测试和灰度发布),并且能清楚看到整个集群的运行情况。
但是这并不表明有了 istio 就可以高枕无忧了,istio 只是把原来分散在应用内部的复杂性统一抽象出来放到了统一的地方,并没有让原来的复杂消失不见。因此我们需要维护 istio 整个集群,而 istio 的架构比较复杂,尤其是它一般还需要架在 kubernetes 之上,这两个系统都比较复杂,而且它们的稳定性和性能会影响到整个集群。因此在采用 isito 之前,必须做好清楚的规划,权衡它带来的好处是否远大于额外维护它的花费,需要有相关的人才对整个网络、kubernetes 和 istio 都比较了解才行。
istio参考资料
https://istio.io/zh/docs/
https://jimmysong.io/istio-handbook/
http://www.servicemesher.com/
如果你对k8s很感兴趣,可以加Q群或者微信群与k8s大拿一起交流。
搜索k8stech关注本订阅号,也将会对k8s生态监控Prometheus不定期更新。
欢迎关注~
Kubernetes文档:https://docs.k8stech.net(持续更新)
Prometheus文档:https://prometheus.wang(持续更新)