技术解读Rainbond ServiceMesh微服务架构_开源PaaS Rainbond

ServiceMeshgoodrain 发表了文章 • 0 个评论 • 228 次浏览 • 6 天前 • 来自相关话题

```
从技术实现的维度解读开源PaaS Rainbond如何支持ServiceMesh微服务架构
```
 
当我们谈论微服务架构时,我们在谈论什么?
 
服务发现和注册、弹性伸缩与负载均衡、容错处理(断路器与限流)、监控与报警、数据存储与共享、日志分析……
 
除了以上自然联想到的技术点,还有如Spring Cloud、Dubbo这样在过去几年受到广泛关注和应用的微服务架构框架,以及最近数个月内在国内外技术圈异军突起的Service Mesh。
 
## 什么是ServiceMesh
 
Service Mesh是一种非入侵、透明化的微服务治理框架。作为服务与服务直接通信的透明化管理框架,Service Mesh不限制服务开发语言、使用轻量级的通信协议(HTTP、gRPC等),并插件式的提供各类功能,如服务发现、负载均衡、智能路由、流量管控、性能分析等等,换而言之,用户通过Service Mesh得以用简单的方式获取高级的功能。
 


 
Rainbond原生支持Service Mesh,接下来我们将从服务发现和注册、弹性伸缩与负载均衡、容错处理(断路器与限流)、监控与报警、数据存储与共享、日志分析等方面进行解读。
 
## 服务发现和注册
 
服务注册是任何一个SOA/服务化/微服务框架必不可少的关键部分,与之密切相关的是一些强一致性分布式存储:Zookeeper、Etcd、Consul,其中Consul和Etcd基于Raft协议实现,Zookeeper基于PAXOS协议实现。
 
几乎所有的服务注册和发现都需要基于以上强一致性分布式存储实现,例如SpringCloud的两个重要的子项目Spring_Cloud_Consul/Spring_Cloud_Zookeeper。
 
对于Rainbond来说,通过应用/服务统一管理实现了所有部署应用/服务的自动注册。其原理在于Rainbond内部基于Kubernetes实现应用调度,注册于Kubernetes集群中的应用/服务信息,实际也是注册到了Etcd之中。应用实例每次重启,Rianbond都会为其分配不同的IP地址,服务注册信息将动态地改变。
 
我们知道,应用与应用直接通信之前必须首先发现对方,在这方面,Rainbond采用了声明式的发现机制,即当A服务需要与B服务通信,那么首先需要在A服务声明依赖B服务,而Rainbond应用运行时模块会基于用户声明发现对方服务地址,注入到A服务内部, 赋予A服务一个本地访问地址(127.0.0.1)访问B服务。
 


 
*平台服务间的依赖关系*
 
## 弹性伸缩与负载均衡
 
说到服务发现和注册,弹性伸缩与负载均衡也就不得不谈。
 
上文中A服务连接B服务,B服务可以是有状态的数据库服务,例如Mysql、MongoDB等,也可以是无状态的restfulAPI服务。
 
对于可以水平伸缩的应用(无状态应用或者分布式有状态应用),服务发现注入多个端点地址,必然需要负载均衡,因此A服务内部需要支持4层网络代理或者7层网络代理,通过应用运行时模块发现的后端地址注入到代理插件内部。
 
Rainbond默认的代理插件支持4层负载均衡,借助Service Mesh便于扩展得特性,我们可以再针对各种应用层协议匹配不同的网络治理插件,实现7层负载均衡,例如HTTP、gRPC、Redis等协议。
 
为什么需要7层负载均衡这样的高级功能?原因在于对于一些在线环境,我们希望可以对服务间调用实现热更改或者更好的容错,比方说A/B测试、灰度发布等等,必须要在7层负载均衡上完成。
 
Rainbond目前提供“基于envoy的7层网络治理插件”(envoy本身可以与安生运行于Rainbond插件体系之中),用户也可以选择和实现其他插件,Rainbond运行时将提供完善的基础服务。
 


 
*配置7层高级负载均衡的方式*
 
## 容错处理(断路器与限流)
 
能够容忍其中某些服务异常情况的微服务架构,才称得上是健壮的生产级微服务架构。
 
比方说某购物网站,订单页面会推荐其他相关商品,在大流量异常情况下,为了保证订单功能可用,将推荐功能(计算耗时,性能不好)限制可用,需要优雅的服务降级,将有限的资源用于关键服务的同时,保证整个系统稳定。
 
这里有两种方案:`限流`,将某个服务设置其最大的请求量或者连接数,硬性保护下游服务;`断路器`,当下游服务错误率到达一个阀值,将上游请求快速失败返回,保护上游服务稳定,同时又不给下游服务增加压力,做到快速失败、快速返回。
 
以上功能的实现对于业务系统来说相对复杂,而在上文提到的Rainbond高级负载均衡支持下,仅需为每个调用线路配置简单的限流参数或者熔断参数,即可实现断路器和限流机制开箱即用。
 
## 监控与报警
 
传统运维关注监控物理资源,例如内存、CPU、负载等指标数据。Rainbond在监控和警报方面,重点没有放在这些侧面体现运行状况的方式,除了基础的资源监控之外,Rainbond核心选择了能够直接体现服务运行情况的`吞吐率`和`响应时间`作为关键指标,如吞吐率异常降低,响应时间增大证明当前服务压力过大,就表示需要扩容了。
 
Rainbond的业务级监控分析如下图:
 


 
对于不同的服务协议,Rainbond使用不同的指标实时表现`吞吐率`、`响应时间`,例如HTTP协议,使用Path的请求量和相应时间表达,Mysql协议使用SQL执行量和响应时间表达。
 
后续Rainbond将支持除上述两种协议之外的更多的应用协议,包括gRPC、Redis、postgreSQL等。用户可以自动或手动在这些指标之上配置规则或自动学习规则,实现提供业务报警和自动伸缩。
 
 


 
## 数据存储与共享
 
分布式是微服务架构中不可缺少的部分,在运行多种不同类型应用、需求不同存储,并且不同数据中心和不同基础设施提供不同存储类型的情况下,实现和处理起来并不容易。
 
Rainbond的实现方式是将存储和应用进行解耦和,插件式支持不同的存储类型,例如基于NFS的分布式文件存储、块设备存储、内存虚拟存储等,
 
当然不同的存储具有不同的属性,Rainbond分布式无状态应用最常用的是共享文件存储,为每个应用分配的存储区域将挂载到所有实例之上,实时同步数据。用户可以自定义需要挂载的路径,应用到哪里,数据就跟到哪里。
 
## 日志分析
 
微服务架构中服务产生的日志处理也是一个难点,日志需要统一收集,同一个应用的多个实例产生的日志需要汇聚,然后需要分析和报警。
 
服务的日志一般会分为两部分:系统日志和访问日志,Rainbond推荐将两类日志区别处理。
 
对于系统日志,其主要作用是调试系统、记录异常,Rainbond提供基于应用级别的应用日志汇聚和实时展示,因此只需要将系统日志输出到标准输出(stdout),系统将自动收集和汇聚,以应用的维度存储。
 
对于访问日志,我们一般需要对其进行分析和监控,日志分析常用的方案是ELK系统,Rainbond建议的方式是将访问日志输出到指定文件,并安装Elasticsearch插件,以便将收集文件日志发送到指定Elasticsearch服务端(平台一键部署ELK完整服务)。如果使用其他分析系统,同样使用插件的形式将应用日志输送到指定服务端即可。
 
## 结语
 
总结来说,Rainbond在Service Mesh微服务架构方面,核心的原则在于开放,通过各类优秀解决方案标准化的接入,来为用户提供开箱即用、强大简单的微服务体验。
 
**进一步了解开源PaaS Rainbond**
 
* 网站: https://www.rainbond.com
* 试用Rainbond公有云: https://www.goodrain.com
* Github: https://github.com/goodrain/rainbond
* 码云: https://gitee.com/rainbond/Rainbond
* 微信群: 添加微信“zqg5258423”并接受邀请入群
 
  查看全部
```
从技术实现的维度解读开源PaaS Rainbond如何支持ServiceMesh微服务架构
```
 
当我们谈论微服务架构时,我们在谈论什么?
 
服务发现和注册、弹性伸缩与负载均衡、容错处理(断路器与限流)、监控与报警、数据存储与共享、日志分析……
 
除了以上自然联想到的技术点,还有如Spring Cloud、Dubbo这样在过去几年受到广泛关注和应用的微服务架构框架,以及最近数个月内在国内外技术圈异军突起的Service Mesh。
 
## 什么是ServiceMesh
 
Service Mesh是一种非入侵、透明化的微服务治理框架。作为服务与服务直接通信的透明化管理框架,Service Mesh不限制服务开发语言、使用轻量级的通信协议(HTTP、gRPC等),并插件式的提供各类功能,如服务发现、负载均衡、智能路由、流量管控、性能分析等等,换而言之,用户通过Service Mesh得以用简单的方式获取高级的功能。
 


 
Rainbond原生支持Service Mesh,接下来我们将从服务发现和注册、弹性伸缩与负载均衡、容错处理(断路器与限流)、监控与报警、数据存储与共享、日志分析等方面进行解读。
 
## 服务发现和注册
 
服务注册是任何一个SOA/服务化/微服务框架必不可少的关键部分,与之密切相关的是一些强一致性分布式存储:Zookeeper、Etcd、Consul,其中Consul和Etcd基于Raft协议实现,Zookeeper基于PAXOS协议实现。
 
几乎所有的服务注册和发现都需要基于以上强一致性分布式存储实现,例如SpringCloud的两个重要的子项目Spring_Cloud_Consul/Spring_Cloud_Zookeeper。
 
对于Rainbond来说,通过应用/服务统一管理实现了所有部署应用/服务的自动注册。其原理在于Rainbond内部基于Kubernetes实现应用调度,注册于Kubernetes集群中的应用/服务信息,实际也是注册到了Etcd之中。应用实例每次重启,Rianbond都会为其分配不同的IP地址,服务注册信息将动态地改变。
 
我们知道,应用与应用直接通信之前必须首先发现对方,在这方面,Rainbond采用了声明式的发现机制,即当A服务需要与B服务通信,那么首先需要在A服务声明依赖B服务,而Rainbond应用运行时模块会基于用户声明发现对方服务地址,注入到A服务内部, 赋予A服务一个本地访问地址(127.0.0.1)访问B服务。
 


 
*平台服务间的依赖关系*
 
## 弹性伸缩与负载均衡
 
说到服务发现和注册,弹性伸缩与负载均衡也就不得不谈。
 
上文中A服务连接B服务,B服务可以是有状态的数据库服务,例如Mysql、MongoDB等,也可以是无状态的restfulAPI服务。
 
对于可以水平伸缩的应用(无状态应用或者分布式有状态应用),服务发现注入多个端点地址,必然需要负载均衡,因此A服务内部需要支持4层网络代理或者7层网络代理,通过应用运行时模块发现的后端地址注入到代理插件内部。
 
Rainbond默认的代理插件支持4层负载均衡,借助Service Mesh便于扩展得特性,我们可以再针对各种应用层协议匹配不同的网络治理插件,实现7层负载均衡,例如HTTP、gRPC、Redis等协议。
 
为什么需要7层负载均衡这样的高级功能?原因在于对于一些在线环境,我们希望可以对服务间调用实现热更改或者更好的容错,比方说A/B测试、灰度发布等等,必须要在7层负载均衡上完成。
 
Rainbond目前提供“基于envoy的7层网络治理插件”(envoy本身可以与安生运行于Rainbond插件体系之中),用户也可以选择和实现其他插件,Rainbond运行时将提供完善的基础服务。
 


 
*配置7层高级负载均衡的方式*
 
## 容错处理(断路器与限流)
 
能够容忍其中某些服务异常情况的微服务架构,才称得上是健壮的生产级微服务架构。
 
比方说某购物网站,订单页面会推荐其他相关商品,在大流量异常情况下,为了保证订单功能可用,将推荐功能(计算耗时,性能不好)限制可用,需要优雅的服务降级,将有限的资源用于关键服务的同时,保证整个系统稳定。
 
这里有两种方案:`限流`,将某个服务设置其最大的请求量或者连接数,硬性保护下游服务;`断路器`,当下游服务错误率到达一个阀值,将上游请求快速失败返回,保护上游服务稳定,同时又不给下游服务增加压力,做到快速失败、快速返回。
 
以上功能的实现对于业务系统来说相对复杂,而在上文提到的Rainbond高级负载均衡支持下,仅需为每个调用线路配置简单的限流参数或者熔断参数,即可实现断路器和限流机制开箱即用。
 
## 监控与报警
 
传统运维关注监控物理资源,例如内存、CPU、负载等指标数据。Rainbond在监控和警报方面,重点没有放在这些侧面体现运行状况的方式,除了基础的资源监控之外,Rainbond核心选择了能够直接体现服务运行情况的`吞吐率`和`响应时间`作为关键指标,如吞吐率异常降低,响应时间增大证明当前服务压力过大,就表示需要扩容了。
 
Rainbond的业务级监控分析如下图:
 


 
对于不同的服务协议,Rainbond使用不同的指标实时表现`吞吐率`、`响应时间`,例如HTTP协议,使用Path的请求量和相应时间表达,Mysql协议使用SQL执行量和响应时间表达。
 
后续Rainbond将支持除上述两种协议之外的更多的应用协议,包括gRPC、Redis、postgreSQL等。用户可以自动或手动在这些指标之上配置规则或自动学习规则,实现提供业务报警和自动伸缩。
 
 


 
## 数据存储与共享
 
分布式是微服务架构中不可缺少的部分,在运行多种不同类型应用、需求不同存储,并且不同数据中心和不同基础设施提供不同存储类型的情况下,实现和处理起来并不容易。
 
Rainbond的实现方式是将存储和应用进行解耦和,插件式支持不同的存储类型,例如基于NFS的分布式文件存储、块设备存储、内存虚拟存储等,
 
当然不同的存储具有不同的属性,Rainbond分布式无状态应用最常用的是共享文件存储,为每个应用分配的存储区域将挂载到所有实例之上,实时同步数据。用户可以自定义需要挂载的路径,应用到哪里,数据就跟到哪里。
 
## 日志分析
 
微服务架构中服务产生的日志处理也是一个难点,日志需要统一收集,同一个应用的多个实例产生的日志需要汇聚,然后需要分析和报警。
 
服务的日志一般会分为两部分:系统日志和访问日志,Rainbond推荐将两类日志区别处理。
 
对于系统日志,其主要作用是调试系统、记录异常,Rainbond提供基于应用级别的应用日志汇聚和实时展示,因此只需要将系统日志输出到标准输出(stdout),系统将自动收集和汇聚,以应用的维度存储。
 
对于访问日志,我们一般需要对其进行分析和监控,日志分析常用的方案是ELK系统,Rainbond建议的方式是将访问日志输出到指定文件,并安装Elasticsearch插件,以便将收集文件日志发送到指定Elasticsearch服务端(平台一键部署ELK完整服务)。如果使用其他分析系统,同样使用插件的形式将应用日志输送到指定服务端即可。
 
## 结语
 
总结来说,Rainbond在Service Mesh微服务架构方面,核心的原则在于开放,通过各类优秀解决方案标准化的接入,来为用户提供开箱即用、强大简单的微服务体验。
 
**进一步了解开源PaaS Rainbond**
 
* 网站: https://www.rainbond.com
* 试用Rainbond公有云: https://www.goodrain.com
* Github: https://github.com/goodrain/rainbond
* 码云: https://gitee.com/rainbond/Rainbond
* 微信群: 添加微信“zqg5258423”并接受邀请入群
 
 

有没有一个可用的现成例子项目?

交流问答leo 回复了问题 • 8 人关注 • 6 个回复 • 1193 次浏览 • 2018-05-10 17:51 • 来自相关话题

如何用Istio做一个前后端分离的博客?

Istiosunshinexs 回复了问题 • 2 人关注 • 1 个回复 • 288 次浏览 • 2018-05-08 10:42 • 来自相关话题

纠错帖:Zuul & Spring Cloud Gateway & Linkerd性能对比

交流问答不战の约 回复了问题 • 4 人关注 • 3 个回复 • 1137 次浏览 • 2018-05-04 10:28 • 来自相关话题

istio 配置生效流程及源码简介

Istiofudali 发表了文章 • 0 个评论 • 337 次浏览 • 2018-04-24 13:13 • 来自相关话题

istio 配置生效流程及源码简介

使用Istio微服务框架,业务逻辑写在哪里?有规定用什么语言写吗?

IstioOnline 回复了问题 • 2 人关注 • 1 个回复 • 565 次浏览 • 2018-04-22 01:11 • 来自相关话题

微服务前方有雷,服务网格帮你趟过通信安全这个坑!

Istio小数 发表了文章 • 0 个评论 • 390 次浏览 • 2018-04-19 18:14 • 来自相关话题

翻译:狄卫华 (博客地址 : https://blog.do1618.com)

作者:Christian Posta

原文:How a Service Mesh Can Help With Microservices Security

地址:http://blog.christianposta.com ... rity/




导读:

我看到很多客户转向微服务(他们是否应该是另外一个帖子的主题(注1)),他们试图通过这种方式解决一些组织化的规模问题。但是,转向微服务架构的细节往往会为旧问题带来一些新问题。


我与之交谈的大多数客户采用一种策略:架构上既有内部部署,也有公有云部署。将应用程序分解为更小的服务并拥有多个部署站点/平台会带来一些更大的挑战。在我看来,像 Istio 这样的服务网格实现旨在解决这些挑战中的一些问题。对于 Istio 和 Service Mesh ,我确实有很多话要说(注2),所以请随时关注@christianposta(注3) 参与并跟踪最新状态。



在微服务化的过程中你将面临的一个挑战是:安全


我知道,作为开发人员,你可能已经对安全非常憎恨——微服务使其更加糟糕。当我们将应用程序分解为更小的服务时,我们会增加被攻击的范围。虽然这有很多安全方面的问题(应用程序漏洞,平台漏洞,数据保护,传输/网络等),但在本文中我将主要集中在微服务如何相互通信以及其出现的一些问题上。


传统上,我们认为网络边界足以保护我们;我们的应用程序在传输安全方面的问题不必考虑太多,因为我们处于 ”受保护的内部网络“。停下来思考一下,你是否使用 SSL/TLS 保护你的内部应用程序?


我们以前通过单体程序本地调用的所有通信都将暴露在开放的网络中。首先我们要做的就是加密所有的内部流量。如果你在实施微服务上没有使用 TLS 进行传输加密,那么你正在将面临着令人讨厌的安全问题。


部分成熟的客户已经实现了所有微服务通信加密,这并没有带来显著成本提升。搭建公钥基础设施、签发密钥和证书、安装、轮换等都是非常大的考验。尝试配置正确的信任库/密钥库(Java)、合适的SSL算法、确保拥有正确的证书链等都是让人感到头痛的事情。我个人试图让其能够正常工作浪费了很多天 。然后当其都能正常工作以后,你就不会再想去折腾它。


我也看到了开发人员使用了 SSL/TLS,然后将其代码部署到 IST/UAT 等测试环境中,但是最终发现相关的安全配置在底层环境中不能够正常工作;由于着急将产品部署到生产环境中,他们会执行诸如禁用 TLS 验证的操作。


像 Istio 这样的服务网格相当简化了这一点。借助 Istio,应用程序的所有实例都有自己的 Sidecar 容器。该 Sidecar 充当所有流入和流出网络通信的服务代理。


在使用服务代理可以获得的诸多好处(注4),与此文讨论相关的好处是能够透明地进行 TLS 加密。这意味着位于与应用程序请求路径中的代理承担了加密流量的责任。你的应用程序可以完全不用关心证书,信任库,密钥库等问题。 Istio 自动将证书和密钥关联到服务,代理使用它们来加密流量(提供双向TLS),并且 Istio 定期轮换密钥/证书,以减少泄露的风险。


举例来说,当 Istio 运行在 Kubernetes 上时(注5),无论你何时部署应用程序,只需要指定一个应用程序运行的服务帐户,之后,Istio 负责处理其余部分。Istio 将为你的服务帐户创建证书/密钥对,使用根 CA密钥 对证书签名,并在将证书/密钥作为 Kubernets 中的密码。密码将被挂载到你的应用程序和 Istio 服务代理运行的 Pod 中,代理将使用证书/密钥来建立双向 TLS。


微服务的另一个安全问题是责任混淆问题(注6)。在这种情况下,终端用户已经授权服务代表它做某件事。在这种情况下,服务可能被授权执行此操作,但特定用户可能不会。我们应该以某种方式将用户身份绑定,并基于身份来评估授权。方法之一就是使用像 JWT (注7) 的令牌。


相关的有以下几点:


首先,如果你传递明文的 JWT 令牌(不使用TLS/mTLS),那么你会遇到比较大的麻烦。令牌默认不进行加密(仅签名),他们很容易地被收集并重放(replay)到服务中。再次,这是 Istio mTLS 可以提供帮助的地方。但即使启用了 mTLS,令牌也可能以被其他的方式泄露(我看到令牌被硬编码到源代码中!)。如果你的所有服务都将 JWT 传递给其他所有服务,那么您将再次面临重放攻击问题。


其次,如果你试图在所有微服务器上进行 JWT 验证,则会遇到与弹性库相同的问题(注8)。每个服务都有自己的库和自己的 JWT 验证实现。尽管像 JBoss Keycloak(注9) 这样的项目提供了出色的多语言支持,但它对库维护人员以及依赖这些库的应用程序开发人员来说都是一种负担。确保它们全部实施正确,一致并统一是一个充满了问题的壮举。


值得庆幸的是,Istio 可以在这两个方面提供帮助。

首先,无论应用程序框架/语言如何,Istio 都可以为你自动进行 JWT 验证。你可以定义一个`EndUserAuthenticationPolicySpec`,它配置了将用于验证的身份/凭证提供者(注10):


---  apiVersion: config.istio.io/v1alpha2  kind: EndUserAuthenticationPolicySpec  metadata:        name: cars-api-auth-policy       namespace: tutorial  spec:        jwts:            - issuer: http://keycloak:8080/auth/realms/istio               jwks_uri: http://keycloak.tutorial:8080/ ... certs               audiences:                - cars-web然后你可以将它绑定到特定的服务:---   apiVersion: config.istio.io/v1alpha2  kind: EndUserAuthenticationPolicySpecBinding  metadata:       name: cars-api-auth-policy-binding       namespace: tutorial spec:       policies:         - name: cars-api-auth-policy             namespace: tutorial    services:         - name: cars-api             namespace: tutorial
 
注意:这个例子来自我的同事 Kamesh Sampath(注11)。在这个配置中,我们已经建立了 `Keycloak` 成为 JWT 令牌的身份管理者和发行者(遵循OpenID Connect)。有关更多信息,请参阅此博客(注12)。当请求进入服务时,如果它没有 JWT 持票人令牌,它将被拒绝。这个配置将安装 EnvoyJWT 过滤器(注13),该过滤器负责验证 JWT 的签名:



最后,JWT 令牌是如何地传播?


Istio 默认只会将 JWT 令牌传播一次,使用 JWT 令牌的主体,并将其传递到应用程序通过单独的 header 字段。 JWT 主体将通过 header 头部中的 `sec-istio-auth-userinfo` 携带信息。基于终端用户的身份和服务的身份,应用程序有责任重新提交新的令牌。通过这种方式,我们可以将令牌的范围限定为单次使用,而不是将 JWT 到处传播。对此的实施仍在发展中,我强烈建议遵循这里 (注14) 和这里(注15)。


现在就是这样。随着 Istio 内部安全性的加强,我会进一步跟进。关注我@christianposta (注16) 获取微服务,服务网格,Istio 等最新信息。



注:

1:http://blog.christianposta.com ... ices/

2:http://blog.christianposta.com/

3:https://twitter.com/christianposta

4:https://istio.io/docs/concepts ... .html

5:https://istio.io/docs/setup/ku ... .html

6:https://en.wikipedia.org/wiki/ ... oblem

7:https://jwt.io/

8:http://blog.christianposta.com ... ices/

9:http://www.keycloak.org/

10:https://istio.io/docs/referenc ... ySpec

11:https://twitter.com/kamesh_sampath

12:http://blog.keycloak.org/2018/ ... .html

13:https://github.com/istio/proxy ... ME.md

14:https://docs.google.com/docume ... lmyhf

15:https://docs.google.com/docume ... lmyhf

16:https://twitter.com/christianposta


  查看全部
翻译:狄卫华 (博客地址 : https://blog.do1618.com

作者:Christian Posta

原文:How a Service Mesh Can Help With Microservices Security

地址:http://blog.christianposta.com ... rity/




导读:

我看到很多客户转向微服务(他们是否应该是另外一个帖子的主题(注1)),他们试图通过这种方式解决一些组织化的规模问题。但是,转向微服务架构的细节往往会为旧问题带来一些新问题。


我与之交谈的大多数客户采用一种策略:架构上既有内部部署,也有公有云部署。将应用程序分解为更小的服务并拥有多个部署站点/平台会带来一些更大的挑战。在我看来,像 Istio 这样的服务网格实现旨在解决这些挑战中的一些问题。对于 Istio 和 Service Mesh ,我确实有很多话要说(注2),所以请随时关注@christianposta(注3) 参与并跟踪最新状态。



在微服务化的过程中你将面临的一个挑战是:安全


我知道,作为开发人员,你可能已经对安全非常憎恨——微服务使其更加糟糕。当我们将应用程序分解为更小的服务时,我们会增加被攻击的范围。虽然这有很多安全方面的问题(应用程序漏洞,平台漏洞,数据保护,传输/网络等),但在本文中我将主要集中在微服务如何相互通信以及其出现的一些问题上。


传统上,我们认为网络边界足以保护我们;我们的应用程序在传输安全方面的问题不必考虑太多,因为我们处于 ”受保护的内部网络“。停下来思考一下,你是否使用 SSL/TLS 保护你的内部应用程序?


我们以前通过单体程序本地调用的所有通信都将暴露在开放的网络中。首先我们要做的就是加密所有的内部流量。如果你在实施微服务上没有使用 TLS 进行传输加密,那么你正在将面临着令人讨厌的安全问题。


部分成熟的客户已经实现了所有微服务通信加密,这并没有带来显著成本提升。搭建公钥基础设施、签发密钥和证书、安装、轮换等都是非常大的考验。尝试配置正确的信任库/密钥库(Java)、合适的SSL算法、确保拥有正确的证书链等都是让人感到头痛的事情。我个人试图让其能够正常工作浪费了很多天 。然后当其都能正常工作以后,你就不会再想去折腾它。


我也看到了开发人员使用了 SSL/TLS,然后将其代码部署到 IST/UAT 等测试环境中,但是最终发现相关的安全配置在底层环境中不能够正常工作;由于着急将产品部署到生产环境中,他们会执行诸如禁用 TLS 验证的操作。


像 Istio 这样的服务网格相当简化了这一点。借助 Istio,应用程序的所有实例都有自己的 Sidecar 容器。该 Sidecar 充当所有流入和流出网络通信的服务代理。


在使用服务代理可以获得的诸多好处(注4),与此文讨论相关的好处是能够透明地进行 TLS 加密。这意味着位于与应用程序请求路径中的代理承担了加密流量的责任。你的应用程序可以完全不用关心证书,信任库,密钥库等问题。 Istio 自动将证书和密钥关联到服务,代理使用它们来加密流量(提供双向TLS),并且 Istio 定期轮换密钥/证书,以减少泄露的风险。


举例来说,当 Istio 运行在 Kubernetes 上时(注5),无论你何时部署应用程序,只需要指定一个应用程序运行的服务帐户,之后,Istio 负责处理其余部分。Istio 将为你的服务帐户创建证书/密钥对,使用根 CA密钥 对证书签名,并在将证书/密钥作为 Kubernets 中的密码。密码将被挂载到你的应用程序和 Istio 服务代理运行的 Pod 中,代理将使用证书/密钥来建立双向 TLS。


微服务的另一个安全问题是责任混淆问题(注6)。在这种情况下,终端用户已经授权服务代表它做某件事。在这种情况下,服务可能被授权执行此操作,但特定用户可能不会。我们应该以某种方式将用户身份绑定,并基于身份来评估授权。方法之一就是使用像 JWT (注7) 的令牌。


相关的有以下几点:


首先,如果你传递明文的 JWT 令牌(不使用TLS/mTLS),那么你会遇到比较大的麻烦。令牌默认不进行加密(仅签名),他们很容易地被收集并重放(replay)到服务中。再次,这是 Istio mTLS 可以提供帮助的地方。但即使启用了 mTLS,令牌也可能以被其他的方式泄露(我看到令牌被硬编码到源代码中!)。如果你的所有服务都将 JWT 传递给其他所有服务,那么您将再次面临重放攻击问题。


其次,如果你试图在所有微服务器上进行 JWT 验证,则会遇到与弹性库相同的问题(注8)。每个服务都有自己的库和自己的 JWT 验证实现。尽管像 JBoss Keycloak(注9) 这样的项目提供了出色的多语言支持,但它对库维护人员以及依赖这些库的应用程序开发人员来说都是一种负担。确保它们全部实施正确,一致并统一是一个充满了问题的壮举。


值得庆幸的是,Istio 可以在这两个方面提供帮助。

首先,无论应用程序框架/语言如何,Istio 都可以为你自动进行 JWT 验证。你可以定义一个`EndUserAuthenticationPolicySpec`,它配置了将用于验证的身份/凭证提供者(注10):


---  apiVersion: config.istio.io/v1alpha2  kind: EndUserAuthenticationPolicySpec  metadata:        name: cars-api-auth-policy       namespace: tutorial  spec:        jwts:            - issuer: http://keycloak:8080/auth/realms/istio               jwks_uri: http://keycloak.tutorial:8080/ ... certs               audiences:                - cars-web然后你可以将它绑定到特定的服务:---   apiVersion: config.istio.io/v1alpha2  kind: EndUserAuthenticationPolicySpecBinding  metadata:       name: cars-api-auth-policy-binding       namespace: tutorial spec:       policies:         - name: cars-api-auth-policy             namespace: tutorial    services:         - name: cars-api             namespace: tutorial
 
注意:这个例子来自我的同事 Kamesh Sampath(注11)。在这个配置中,我们已经建立了 `Keycloak` 成为 JWT 令牌的身份管理者和发行者(遵循OpenID Connect)。有关更多信息,请参阅此博客(注12)。当请求进入服务时,如果它没有 JWT 持票人令牌,它将被拒绝。这个配置将安装 EnvoyJWT 过滤器(注13),该过滤器负责验证 JWT 的签名:



最后,JWT 令牌是如何地传播?


Istio 默认只会将 JWT 令牌传播一次,使用 JWT 令牌的主体,并将其传递到应用程序通过单独的 header 字段。 JWT 主体将通过 header 头部中的 `sec-istio-auth-userinfo` 携带信息。基于终端用户的身份和服务的身份,应用程序有责任重新提交新的令牌。通过这种方式,我们可以将令牌的范围限定为单次使用,而不是将 JWT 到处传播。对此的实施仍在发展中,我强烈建议遵循这里 (注14) 和这里(注15)。


现在就是这样。随着 Istio 内部安全性的加强,我会进一步跟进。关注我@christianposta (注16) 获取微服务,服务网格,Istio 等最新信息。



注:

1:http://blog.christianposta.com ... ices/

2:http://blog.christianposta.com/

3:https://twitter.com/christianposta

4:https://istio.io/docs/concepts ... .html

5:https://istio.io/docs/setup/ku ... .html

6:https://en.wikipedia.org/wiki/ ... oblem

7:https://jwt.io/

8:http://blog.christianposta.com ... ices/

9:http://www.keycloak.org/

10:https://istio.io/docs/referenc ... ySpec

11:https://twitter.com/kamesh_sampath

12:http://blog.keycloak.org/2018/ ... .html

13:https://github.com/istio/proxy ... ME.md

14:https://docs.google.com/docume ... lmyhf

15:https://docs.google.com/docume ... lmyhf

16:https://twitter.com/christianposta


 

Service Mesh vs API Gateway,用途特征大相径庭?

ServiceMesh小数 发表了文章 • 0 个评论 • 1037 次浏览 • 2018-04-16 10:30 • 来自相关话题

作者:Kasun Indrasiri

翻译:赵化冰(博客链接:http://zhaohuabing.com/)

原文:Service Mesh vs API Gateway

地址:https://medium.com/microservic ... 9bf56




在我前一篇关于 Service Mesh 的文章中(注1)有几个关于 Service Mesh 和 API Gateway 之间关系的问题。因此在我打算在本篇文章中讨论 Service Mesh 和 API Gateway 的用途。


为了区分 API Gateway 和 Service Mesh,让我们先分别看看两者的主要特征。


API Gateway:将你的服务作为被管理的API暴露给外部系统

使用 API Gateway 的主要目的是将你的微服务作为被管理的 API 暴露给外部系统。因此,我们在 API Gateway 层开发的 API 或者边界服务对外提供了业务功能。

API/Edge 服务调用下游微服务,通过组合/混装多个下游微服务形成业务逻辑。

API/Edge 服务需要以一种可靠的方式调用下游服务,因此需要应用断路器,超时,负载均衡/故障转移等可靠性模式。因此大部分的 API Gateway解决方案都内置了这些特性。

API Gateway 也需要内置对以下特性的支持,包括:服务发现,分析(可见性:性能指标,监控,分布式日志,分布式调用追踪) 和安全。

API Gateway 和 API 管理生态系统的其他这些组件的关系紧密,比如: API 市场/商店, API 发布门户。




Service Mesh

现在我们来看看Service Mesh有哪些不同。

Service Mesh是一个网络通信基础设施, 可以用于将网络功能从你的服务代码中剥离出来。

采用 Service Mesh, 你不用在服务代码中实现用于可靠通信的模式如断路,超时等,类似地,Service Mesh 也提供了服务发现,服务可见性等其他功能。




API Gateway and Service Mesh实践

API Gateway 和 Service Mesh 之间的主要不同点在于 API Gateway 是暴露 API/Edge 服务的关键组件,而 Service Mesh 则仅仅是一个服务间通信的基础设施,并不了解你应用中的业务逻辑。

下图说明了 API Gateway 和 Service Mesh 的关系。如同我们上所说,他们之间也有一些重叠的部分(例如断路器等),但重要的是需要理解这两者是用于完全不同的用途。

图1: API Gateway和Service Mesh实践








如图所示,Service Mesh 作为 Sidecar 和服务一起部署,它是独立于服务的业务逻辑的。


另一方面,API Gateway host 了所有的 API 服务(这些API服务有明确定义的业务功能),它是你应用的业务逻辑的一部分。API Gateway 可以具有内建的服务间通信能力,但它也可以使用 Service Mesh 来调用下游服务。(API Gateway->Service Mesh->Microservices)。


在API管理层次,你可以使用API Gateway内建的服务间通信能力;也可以通过Service Mesh来调用下游服务,以将应用网络通信功能从应用程序转移到Service Mesh中。




译者按:

API Gateway 和 Service Mesh 的关系是我最近一直在思考的问题,也和同事及社区的朋友之间进行了一些讨论。这篇短文很清晰地总结了两者之间的相似之处以及这两者在微服务架构中的不同用途。


文章中提到 “可以使用API Gateway内建的服务间通信能力;也可以通过Service Mesh来调用下游服务”。在和同事讨论时,大家提到一个比较重要的考虑因素是在 API Gateway 处引入一个 Sidecar 可能带来的额外延迟。


API Gateway 作为微服务引用的流量入口,其对效率要求较高,如果随 API Gateway 部署一个 Sidecar,可能对效率有一定影响。


我对此未进行测试,但从理论上来说,服务发现,重试,断路等逻辑无论放到 API Gateway 还是 Service Mesh 中耗时应该是差不多的,部署 Sidecar 只是增加了创建一个本地链接的消耗,如下图所示:







将 API Gateway 和 Service Mesh 的功能进行清晰划分,API Gateway 负责应用逻辑,Service Mes h负责服务通讯,Metrics 收集等微服务基础设施,这样划分后在架构上更为清晰。对于效率问题,我们可以考虑对 API Gateway 进行水平扩展来解决。




注:

1、https://medium.com/microservic ... a3c9a 查看全部
作者:Kasun Indrasiri

翻译:赵化冰(博客链接:http://zhaohuabing.com/

原文:Service Mesh vs API Gateway

地址:https://medium.com/microservic ... 9bf56




在我前一篇关于 Service Mesh 的文章中(注1)有几个关于 Service Mesh 和 API Gateway 之间关系的问题。因此在我打算在本篇文章中讨论 Service Mesh 和 API Gateway 的用途。


为了区分 API Gateway 和 Service Mesh,让我们先分别看看两者的主要特征。


API Gateway:将你的服务作为被管理的API暴露给外部系统

使用 API Gateway 的主要目的是将你的微服务作为被管理的 API 暴露给外部系统。因此,我们在 API Gateway 层开发的 API 或者边界服务对外提供了业务功能。

API/Edge 服务调用下游微服务,通过组合/混装多个下游微服务形成业务逻辑。

API/Edge 服务需要以一种可靠的方式调用下游服务,因此需要应用断路器,超时,负载均衡/故障转移等可靠性模式。因此大部分的 API Gateway解决方案都内置了这些特性。

API Gateway 也需要内置对以下特性的支持,包括:服务发现,分析(可见性:性能指标,监控,分布式日志,分布式调用追踪) 和安全。

API Gateway 和 API 管理生态系统的其他这些组件的关系紧密,比如: API 市场/商店, API 发布门户。




Service Mesh

现在我们来看看Service Mesh有哪些不同。

Service Mesh是一个网络通信基础设施, 可以用于将网络功能从你的服务代码中剥离出来。

采用 Service Mesh, 你不用在服务代码中实现用于可靠通信的模式如断路,超时等,类似地,Service Mesh 也提供了服务发现,服务可见性等其他功能。




API Gateway and Service Mesh实践

API Gateway 和 Service Mesh 之间的主要不同点在于 API Gateway 是暴露 API/Edge 服务的关键组件,而 Service Mesh 则仅仅是一个服务间通信的基础设施,并不了解你应用中的业务逻辑。

下图说明了 API Gateway 和 Service Mesh 的关系。如同我们上所说,他们之间也有一些重叠的部分(例如断路器等),但重要的是需要理解这两者是用于完全不同的用途。

图1: API Gateway和Service Mesh实践


微信图片_20180416102911.jpg



如图所示,Service Mesh 作为 Sidecar 和服务一起部署,它是独立于服务的业务逻辑的。


另一方面,API Gateway host 了所有的 API 服务(这些API服务有明确定义的业务功能),它是你应用的业务逻辑的一部分。API Gateway 可以具有内建的服务间通信能力,但它也可以使用 Service Mesh 来调用下游服务。(API Gateway->Service Mesh->Microservices)。


在API管理层次,你可以使用API Gateway内建的服务间通信能力;也可以通过Service Mesh来调用下游服务,以将应用网络通信功能从应用程序转移到Service Mesh中。




译者按:

API Gateway 和 Service Mesh 的关系是我最近一直在思考的问题,也和同事及社区的朋友之间进行了一些讨论。这篇短文很清晰地总结了两者之间的相似之处以及这两者在微服务架构中的不同用途。


文章中提到 “可以使用API Gateway内建的服务间通信能力;也可以通过Service Mesh来调用下游服务”。在和同事讨论时,大家提到一个比较重要的考虑因素是在 API Gateway 处引入一个 Sidecar 可能带来的额外延迟。


API Gateway 作为微服务引用的流量入口,其对效率要求较高,如果随 API Gateway 部署一个 Sidecar,可能对效率有一定影响。


我对此未进行测试,但从理论上来说,服务发现,重试,断路等逻辑无论放到 API Gateway 还是 Service Mesh 中耗时应该是差不多的,部署 Sidecar 只是增加了创建一个本地链接的消耗,如下图所示:

微信图片_20180416102956.jpg



将 API Gateway 和 Service Mesh 的功能进行清晰划分,API Gateway 负责应用逻辑,Service Mes h负责服务通讯,Metrics 收集等微服务基础设施,这样划分后在架构上更为清晰。对于效率问题,我们可以考虑对 API Gateway 进行水平扩展来解决。




注:

1、https://medium.com/microservic ... a3c9a

Service Mesh第三梯队,不可忽略的Nginmesh

ServiceMesh小数 发表了文章 • 0 个评论 • 590 次浏览 • 2018-04-11 15:13 • 来自相关话题

作者简介:

      赵化冰是一名程序员及开源软件爱好者,目前在NFV&SDN编排开源社区ONAP担任MSB项目负责人,致力于高性能,高可用微服务架构在编排领域的应用。

      博客链接:http://zhaohuabing.com/


目录
前言安装Kubernetes Cluster安装Istio控制面和Bookinfo查看自动注入的sidecar关联阅读参考




1. 前言

Nginmesh 是 NGINX 的 Service Mesh 开源项目,用于 Istio 服务网格平台中的数据面代理。它旨在提供七层负载均衡和服务路由功能,与 Istio 集成作为 sidecar 部署,并将以“标准,可靠和安全的方式”使得服务间通信更容易。Nginmesh 在今年底已经连续发布了0.2和0.3版本,提供了服务发现,请求转发,路由规则,性能指标收集等功能。

备注:本文安装指南基于Ubuntu 16.04,在Centos上某些安装步骤的命令可能需要稍作改动。









2. 安装Kubernetes Cluster

Kubernetes Cluster 包含 etcd, api server, scheduler,controller manager 等多个组件,组件之间的配置较为复杂,如果要手动去逐个安装及配置各个组件,需要了解 kubernetes,操作系统及网络等多方面的知识,对安装人员的能力要求较高。kubeadm提供了一个简便,快速安装 Kubernetes Cluster 的方式,并且可以通过安装配置文件提供较高的灵活性,因此我们采用 kubeadm 安装 kubernetes cluster。

首先参照 kubeadm的说明文档(注1) 在计划部署 kubernetes cluster 的每个节点上安装 docker,kubeadm, kubelet 和 kubectl。

安装 docker

apt-get update
apt-get install -y docker.io

使用 google 的源安装 kubelet kubeadm 和 kubectl

apt-get update && apt-get install -y apt-transport-https
curl -s https://packages.cloud.google. ... y.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl

使用 kubeadmin 安装 kubernetes cluster

Nginmesh 使用 Kubernetes的 Initializer 机制 (注2)来实现 sidecar 的自动注入。Initializer 目前是 kubernetes 的一个 Alpha feature,缺省是未启用的,需要通过api server的参数(注3)打开。因此我们先创建一个 kubeadm-conf 配置文件,用于配置 api server的启动参数。

apiVersion: kubeadm.k8s.io/v1alpha1
kind: MasterConfiguration
apiServerExtraArgs:
 admission-control: Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ValidatingAdmissionWebhook,ResourceQuota,DefaultTolerationSeconds,MutatingAdmissionWebhook
 runtime-config: admissionregistration.k8s.io/v1alpha1

使用 kubeadmin init 命令创建 kubernetes master 节点。 可以先试用 –dry-run 参数验证一下配置文件。

kubeadm init --config kubeadm-conf --dry-run

如果一切正常,kubeadm 将提示:Finished dry-running successfully. Above are the resources that would be created.

下面再实际执行创建命令

kubeadm init --config kubeadm-conf

kubeadm 会花一点时间拉取 docker image,命令完成后,会提示如何将一个 work node 加入 cluster。如下所示:

kubeadm join --token fffbf6.13bcb3563428cf23 10.12.5.15:6443 --discovery-token-ca-cert-hash sha256:27ad08b4cd9f02e522334979deaf09e3fae80507afde63acf88892c8b72f143f

备注:目前 kubeadm 只能支持在一个节点上安装 master,支持高可用的安装将在后续版本实现。kubernetes 官方给出的 workaround 建议是定期备份 etcd 数据kubeadm limitations。

Kubeadm 并不会安装 Pod 需要的网络,因此需要手动安装一个 Pod 网络,这里采用的是 Calico

kubectl apply -f https://docs.projectcalico.org ... .yaml

使用 kubectl 命令检查 master 节点安装结果

ubuntu@kube-1:~$ kubectl get all
NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
svc/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   12m

在每台工作节点上执行上述 kubeadm join 命令,即可把工作节点加入集群中。使用kubectl 命令检查 cluster 中的节点情况。

ubuntu@kube-1:~$ kubectl get nodes
NAME      STATUS    ROLES     AGE       VERSION
kube-1    Ready     master    21m       v1.9.0
kube-2    Ready     <none>    47s       v1.9.0




3. 安装Istio控制面和Bookinfo

参考 Nginmesh文档 (注4)安装 Istio 控制面和 Bookinfo 该文档的步骤清晰明确,这里不再赘述。

需要注意的是,在 Niginmesh 文档中,建议通过 Ingress 的 External IP 访问 bookinfo应用程序。但 Loadbalancer 只在支持的云环境中才会生效(注5),并且还需要进行一定的配置。如我在 Openstack 环境中创建的 cluster,则需要参照该文档(注6)对Openstack 进行配置后,Openstack 才能够支持 kubernetes 的 Loadbalancer service。如未进行配置,通过命令查看 Ingress External IP 一直显示为 pending 状态。

NAME            TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                                                            AGE
istio-ingress   LoadBalancer   10.111.158.10   <pending>     80:32765/TCP,443:31969/TCP                                         11m
istio-mixer     ClusterIP      10.107.135.31   <none>        9091/TCP,15004/TCP,9093/TCP,9094/TCP,9102/TCP,9125/UDP,42422/TCP   11m
istio-pilot     ClusterIP      10.111.110.65   <none>        15003/TCP,443/TCP                                                  11m

如不能配置云环境提供 Loadbalancer 特性, 我们可以直接使用集群中的一个节点IP:Nodeport 访问 Bookinfo 应用程序。

http://10.12.5.31:32765/productpage

想要了解更多关于如何从集群外部进行访问的内容,可以参考如何从外部访问Kubernetes集群中的应用?(注7)




4. 查看自动注入的sidecar

使用 kubectl get pod reviews-v3-5fff595d9b-zsb2q -o yaml 命令查看 Bookinfo 应用的 reviews 服务的 Pod。

apiVersion: v1
kind: Pod
metadata:
 annotations:
   sidecar.istio.io/status: injected-version-0.2.12
 creationTimestamp: 2018-01-02T02:33:36Z
 generateName: reviews-v3-5fff595d9b-
 labels:
   app: reviews
   pod-template-hash: "1999151856"
   version: v3
 name: reviews-v3-5fff595d9b-zsb2q
 namespace: default
 ownerReferences:
 - apiVersion: extensions/v1beta1
   blockOwnerDeletion: true
   controller: true
   kind: ReplicaSet
   name: reviews-v3-5fff595d9b
   uid: 5599688c-ef65-11e7-8be6-fa163e160c7d
 resourceVersion: "3757"
 selfLink: /api/v1/namespaces/default/pods/reviews-v3-5fff595d9b-zsb2q
 uid: 559d8c6f-ef65-11e7-8be6-fa163e160c7d
spec:
 containers:
 - image: istio/examples-bookinfo-reviews-v3:0.2.3
   imagePullPolicy: IfNotPresent
   name: reviews
   ports:
   - containerPort: 9080
     protocol: TCP
   resources: {}
   terminationMessagePath: /dev/termination-log
   terminationMessagePolicy: File
   volumeMounts:
   - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
     name: default-token-48vxx
     readOnly: true
 - args:
   - proxy
   - sidecar
   - -v
   - "2"
   - --configPath
   - /etc/istio/proxy
   - --binaryPath
   - /usr/local/bin/envoy
   - --serviceCluster
   - reviews
   - --drainDuration
   - 45s
   - --parentShutdownDuration
   - 1m0s
   - --discoveryAddress
   - istio-pilot.istio-system:15003
   - --discoveryRefreshDelay
   - 1s
   - --zipkinAddress
   - zipkin.istio-system:9411
   - --connectTimeout
   - 10s
   - --statsdUdpAddress
   - istio-mixer.istio-system:9125
   - --proxyAdminPort
   - "15000"
   - --controlPlaneAuthPolicy
   - NONE
   env:
   - name: POD_NAME
     valueFrom:
       fieldRef:
         apiVersion: v1
         fieldPath: metadata.name
   - name: POD_NAMESPACE
     valueFrom:
       fieldRef:
         apiVersion: v1
         fieldPath: metadata.namespace
   - name: INSTANCE_IP
     valueFrom:
       fieldRef:
         apiVersion: v1
         fieldPath: status.podIP
   image: nginmesh/proxy_debug:0.2.12
   imagePullPolicy: Always
   name: istio-proxy
   resources: {}
   securityContext:
     privileged: true
     readOnlyRootFilesystem: false
     runAsUser: 1337
   terminationMessagePath: /dev/termination-log
   terminationMessagePolicy: File
   volumeMounts:
   - mountPath: /etc/istio/proxy
     name: istio-envoy
   - mountPath: /etc/certs/
     name: istio-certs
     readOnly: true
   - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
     name: default-token-48vxx
     readOnly: true
 dnsPolicy: ClusterFirst
 initContainers:
 - args:
   - -p
   - "15001"
   - -u
   - "1337"
   image: nginmesh/proxy_init:0.2.12
   imagePullPolicy: Always
   name: istio-init
   resources: {}
   securityContext:
     capabilities:
       add:
       - NET_ADMIN
     privileged: true
   terminationMessagePath: /dev/termination-log
   terminationMessagePolicy: File
   volumeMounts:
   - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
     name: default-token-48vxx
     readOnly: true
 nodeName: kube-2
 restartPolicy: Always
 schedulerName: default-scheduler
 securityContext: {}
 serviceAccount: default
 serviceAccountName: default
 terminationGracePeriodSeconds: 30
 tolerations:
 - effect: NoExecute
   key: node.kubernetes.io/not-ready
   operator: Exists
   tolerationSeconds: 300
 - effect: NoExecute
   key: node.kubernetes.io/unreachable
   operator: Exists
   tolerationSeconds: 300
 volumes:
 - emptyDir:
     medium: Memory
   name: istio-envoy
 - name: istio-certs
   secret:
     defaultMode: 420
     optional: true
     secretName: istio.default
 - name: default-token-48vxx
   secret:
     defaultMode: 420
     secretName: default-token-48vxx
status:
 conditions:
 - lastProbeTime: null
   lastTransitionTime: 2018-01-02T02:33:54Z
   status: "True"
   type: Initialized
 - lastProbeTime: null
   lastTransitionTime: 2018-01-02T02:36:06Z
   status: "True"
   type: Ready
 - lastProbeTime: null
   lastTransitionTime: 2018-01-02T02:33:36Z
   status: "True"
   type: PodScheduled
 containerStatuses:
 - containerID: docker://5d0c189b9dde8e14af4c8065ee5cf007508c0bb2b3c9535598d99dc49f531370
   image: nginmesh/proxy_debug:0.2.12
   imageID: docker-pullable://nginmesh/proxy_debug@sha256:6275934ea3a1ce5592e728717c4973ac704237b06b78966a1d50de3bc9319c71
   lastState: {}
   name: istio-proxy
   ready: true
   restartCount: 0
   state:
     running:
       startedAt: 2018-01-02T02:36:05Z
 - containerID: docker://aba3e114ac1aa87c75e969dcc1b0725696de78d3407c5341691d9db579429f28
   image: istio/examples-bookinfo-reviews-v3:0.2.3
   imageID: docker-pullable://istio/examples-bookinfo-reviews-v3@sha256:6e100e4805a8c10c47040ea7b66f10ad619c7e0068696032546ad3e35ad46570
   lastState: {}
   name: reviews
   ready: true
   restartCount: 0
   state:
     running:
       startedAt: 2018-01-02T02:35:47Z
 hostIP: 10.12.5.31
 initContainerStatuses:
 - containerID: docker://b55108625832a3205a265e8b45e5487df10276d5ae35af572ea4f30583933c1f
   image: nginmesh/proxy_init:0.2.12
   imageID: docker-pullable://nginmesh/proxy_init@sha256:f73b68839f6ac1596d6286ca498e4478b8fcfa834e4884418d23f9f625cbe5f5
   lastState: {}
   name: istio-init
   ready: true
   restartCount: 0
   state:
     terminated:
       containerID: docker://b55108625832a3205a265e8b45e5487df10276d5ae35af572ea4f30583933c1f
       exitCode: 0
       finishedAt: 2018-01-02T02:33:53Z
       reason: Completed
       startedAt: 2018-01-02T02:33:53Z
 phase: Running
 podIP: 192.168.79.138
 qosClass: BestEffort
 startTime: 2018-01-02T02:33:39Z

该命令行输出的内容相当长,我们可以看到 Pod 中注入了一个 nginmesh/proxy_debug container , 还增加了一个 initContainer nginmesh/proxy_init。这两个容器是通过kubernetes initializer 自动注入到 pod 中的。这两个 container 分别有什么作用呢?让我们看一下 Nginmesh 源代码中的说明(注8):

proxy_debug, which comes with the agent and NGINX.

proxy_init, which is used for configuring iptables rules for transparently injecting an NGINX proxy from the proxy_debug image into an application pod.

proxy_debug 就是 sidecar 代理,proxy_init 则用于配置 iptable 规则,以将应用的流量导入到 sidecar 代理中。

查看 proxy_init 的 Dockerfile 文件,可以看到 proxy_init 其实是调用了prepare_proxy.sh(注9)这个脚本来创建 iptable 规则。

proxy_debug Dockerfile

FROM debian:stretch-slim
RUN apt-get update && apt-get install -y iptables
ADD prepare_proxy.sh /
ENTRYPOINT ["/prepare_proxy.sh"]

prepare_proxy.sh节选

...omitted for brevity 

# Create a new chain for redirecting inbound and outbound traffic to
# the common Envoy port.
iptables -t nat -N ISTIO_REDIRECT                                             -m comment --comment "istio/redirect-common-chain"
iptables -t nat -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-port ${ENVOY_PORT}  -m comment --comment "istio/redirect-to-envoy-port"

# Redirect all inbound traffic to Envoy.
iptables -t nat -A PREROUTING -j ISTIO_REDIRECT                               -m comment --comment "istio/install-istio-prerouting"

# Create a new chain for selectively redirecting outbound packets to
# Envoy.
iptables -t nat -N ISTIO_OUTPUT                                               -m comment --comment "istio/common-output-chain"

...omitted for brevity





4. 关联阅读

Istio  及Bookinfo 示例程序安装试用笔记(注10)




5. 参考

Service Mesh with Istio and NGINX(注11)

Using kubeadm to Create a Cluster(注12)

Kubernetes Reference Documentation-Dynamic Admission Control(注13)



注:

1、https://kubernetes.io/docs/set ... beadm

2、https://kubernetes.io/docs/adm ... izers

3、https://kubernetes.io/docs/adm ... lpha-

4、https://github.com/nginmesh/nginmesh

5、https://kubernetes.io/docs/con ... ancer

6、https://docs.openstack.org/mag ... .html

7、http://zhaohuabing.com/2017/11 ... side/

8、https://github.com/nginmesh/ng ... agent

9、https://github.com/nginmesh/ng ... xy.sh

10、https://github.com/nginmesh/ng ... xy.sh

11、https://github.com/nginmesh/nginmesh/

12、https://kubernetes.io/docs/set ... hosts

13、https://kubernetes.io/docs/set ... hosts


  查看全部
作者简介:

      赵化冰是一名程序员及开源软件爱好者,目前在NFV&SDN编排开源社区ONAP担任MSB项目负责人,致力于高性能,高可用微服务架构在编排领域的应用。

      博客链接:http://zhaohuabing.com/


目录
  1. 前言
  2. 安装Kubernetes Cluster
  3. 安装Istio控制面和Bookinfo
  4. 查看自动注入的sidecar
  5. 关联阅读
  6. 参考





1. 前言

Nginmesh 是 NGINX 的 Service Mesh 开源项目,用于 Istio 服务网格平台中的数据面代理。它旨在提供七层负载均衡和服务路由功能,与 Istio 集成作为 sidecar 部署,并将以“标准,可靠和安全的方式”使得服务间通信更容易。Nginmesh 在今年底已经连续发布了0.2和0.3版本,提供了服务发现,请求转发,路由规则,性能指标收集等功能。

备注:本文安装指南基于Ubuntu 16.04,在Centos上某些安装步骤的命令可能需要稍作改动。


11.png




2. 安装Kubernetes Cluster

Kubernetes Cluster 包含 etcd, api server, scheduler,controller manager 等多个组件,组件之间的配置较为复杂,如果要手动去逐个安装及配置各个组件,需要了解 kubernetes,操作系统及网络等多方面的知识,对安装人员的能力要求较高。kubeadm提供了一个简便,快速安装 Kubernetes Cluster 的方式,并且可以通过安装配置文件提供较高的灵活性,因此我们采用 kubeadm 安装 kubernetes cluster。

首先参照 kubeadm的说明文档(注1) 在计划部署 kubernetes cluster 的每个节点上安装 docker,kubeadm, kubelet 和 kubectl。

安装 docker

apt-get update
apt-get install -y docker.io

使用 google 的源安装 kubelet kubeadm 和 kubectl

apt-get update && apt-get install -y apt-transport-https
curl -s https://packages.cloud.google. ... y.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl

使用 kubeadmin 安装 kubernetes cluster

Nginmesh 使用 Kubernetes的 Initializer 机制 (注2)来实现 sidecar 的自动注入。Initializer 目前是 kubernetes 的一个 Alpha feature,缺省是未启用的,需要通过api server的参数(注3)打开。因此我们先创建一个 kubeadm-conf 配置文件,用于配置 api server的启动参数。

apiVersion: kubeadm.k8s.io/v1alpha1
kind: MasterConfiguration
apiServerExtraArgs:
 admission-control: Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ValidatingAdmissionWebhook,ResourceQuota,DefaultTolerationSeconds,MutatingAdmissionWebhook
 runtime-config: admissionregistration.k8s.io/v1alpha1

使用 kubeadmin init 命令创建 kubernetes master 节点。 可以先试用 –dry-run 参数验证一下配置文件。

kubeadm init --config kubeadm-conf --dry-run

如果一切正常,kubeadm 将提示:Finished dry-running successfully. Above are the resources that would be created.

下面再实际执行创建命令

kubeadm init --config kubeadm-conf

kubeadm 会花一点时间拉取 docker image,命令完成后,会提示如何将一个 work node 加入 cluster。如下所示:

kubeadm join --token fffbf6.13bcb3563428cf23 10.12.5.15:6443 --discovery-token-ca-cert-hash sha256:27ad08b4cd9f02e522334979deaf09e3fae80507afde63acf88892c8b72f143f

备注:目前 kubeadm 只能支持在一个节点上安装 master,支持高可用的安装将在后续版本实现。kubernetes 官方给出的 workaround 建议是定期备份 etcd 数据kubeadm limitations。

Kubeadm 并不会安装 Pod 需要的网络,因此需要手动安装一个 Pod 网络,这里采用的是 Calico

kubectl apply -f https://docs.projectcalico.org ... .yaml

使用 kubectl 命令检查 master 节点安装结果

ubuntu@kube-1:~$ kubectl get all
NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
svc/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   12m

在每台工作节点上执行上述 kubeadm join 命令,即可把工作节点加入集群中。使用kubectl 命令检查 cluster 中的节点情况。

ubuntu@kube-1:~$ kubectl get nodes
NAME      STATUS    ROLES     AGE       VERSION
kube-1    Ready     master    21m       v1.9.0
kube-2    Ready     <none>    47s       v1.9.0




3. 安装Istio控制面和Bookinfo

参考 Nginmesh文档 (注4)安装 Istio 控制面和 Bookinfo 该文档的步骤清晰明确,这里不再赘述。

需要注意的是,在 Niginmesh 文档中,建议通过 Ingress 的 External IP 访问 bookinfo应用程序。但 Loadbalancer 只在支持的云环境中才会生效(注5),并且还需要进行一定的配置。如我在 Openstack 环境中创建的 cluster,则需要参照该文档(注6)对Openstack 进行配置后,Openstack 才能够支持 kubernetes 的 Loadbalancer service。如未进行配置,通过命令查看 Ingress External IP 一直显示为 pending 状态。

NAME            TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                                                            AGE
istio-ingress   LoadBalancer   10.111.158.10   <pending>     80:32765/TCP,443:31969/TCP                                         11m
istio-mixer     ClusterIP      10.107.135.31   <none>        9091/TCP,15004/TCP,9093/TCP,9094/TCP,9102/TCP,9125/UDP,42422/TCP   11m
istio-pilot     ClusterIP      10.111.110.65   <none>        15003/TCP,443/TCP                                                  11m

如不能配置云环境提供 Loadbalancer 特性, 我们可以直接使用集群中的一个节点IP:Nodeport 访问 Bookinfo 应用程序。

http://10.12.5.31:32765/productpage

想要了解更多关于如何从集群外部进行访问的内容,可以参考如何从外部访问Kubernetes集群中的应用?(注7)




4. 查看自动注入的sidecar

使用 kubectl get pod reviews-v3-5fff595d9b-zsb2q -o yaml 命令查看 Bookinfo 应用的 reviews 服务的 Pod。

apiVersion: v1
kind: Pod
metadata:
 annotations:
   sidecar.istio.io/status: injected-version-0.2.12
 creationTimestamp: 2018-01-02T02:33:36Z
 generateName: reviews-v3-5fff595d9b-
 labels:
   app: reviews
   pod-template-hash: "1999151856"
   version: v3
 name: reviews-v3-5fff595d9b-zsb2q
 namespace: default
 ownerReferences:
 - apiVersion: extensions/v1beta1
   blockOwnerDeletion: true
   controller: true
   kind: ReplicaSet
   name: reviews-v3-5fff595d9b
   uid: 5599688c-ef65-11e7-8be6-fa163e160c7d
 resourceVersion: "3757"
 selfLink: /api/v1/namespaces/default/pods/reviews-v3-5fff595d9b-zsb2q
 uid: 559d8c6f-ef65-11e7-8be6-fa163e160c7d
spec:
 containers:
 - image: istio/examples-bookinfo-reviews-v3:0.2.3
   imagePullPolicy: IfNotPresent
   name: reviews
   ports:
   - containerPort: 9080
     protocol: TCP
   resources: {}
   terminationMessagePath: /dev/termination-log
   terminationMessagePolicy: File
   volumeMounts:
   - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
     name: default-token-48vxx
     readOnly: true
 - args:
   - proxy
   - sidecar
   - -v
   - "2"
   - --configPath
   - /etc/istio/proxy
   - --binaryPath
   - /usr/local/bin/envoy
   - --serviceCluster
   - reviews
   - --drainDuration
   - 45s
   - --parentShutdownDuration
   - 1m0s
   - --discoveryAddress
   - istio-pilot.istio-system:15003
   - --discoveryRefreshDelay
   - 1s
   - --zipkinAddress
   - zipkin.istio-system:9411
   - --connectTimeout
   - 10s
   - --statsdUdpAddress
   - istio-mixer.istio-system:9125
   - --proxyAdminPort
   - "15000"
   - --controlPlaneAuthPolicy
   - NONE
   env:
   - name: POD_NAME
     valueFrom:
       fieldRef:
         apiVersion: v1
         fieldPath: metadata.name
   - name: POD_NAMESPACE
     valueFrom:
       fieldRef:
         apiVersion: v1
         fieldPath: metadata.namespace
   - name: INSTANCE_IP
     valueFrom:
       fieldRef:
         apiVersion: v1
         fieldPath: status.podIP
   image: nginmesh/proxy_debug:0.2.12
   imagePullPolicy: Always
   name: istio-proxy
   resources: {}
   securityContext:
     privileged: true
     readOnlyRootFilesystem: false
     runAsUser: 1337
   terminationMessagePath: /dev/termination-log
   terminationMessagePolicy: File
   volumeMounts:
   - mountPath: /etc/istio/proxy
     name: istio-envoy
   - mountPath: /etc/certs/
     name: istio-certs
     readOnly: true
   - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
     name: default-token-48vxx
     readOnly: true
 dnsPolicy: ClusterFirst
 initContainers:
 - args:
   - -p
   - "15001"
   - -u
   - "1337"
   image: nginmesh/proxy_init:0.2.12
   imagePullPolicy: Always
   name: istio-init
   resources: {}
   securityContext:
     capabilities:
       add:
       - NET_ADMIN
     privileged: true
   terminationMessagePath: /dev/termination-log
   terminationMessagePolicy: File
   volumeMounts:
   - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
     name: default-token-48vxx
     readOnly: true
 nodeName: kube-2
 restartPolicy: Always
 schedulerName: default-scheduler
 securityContext: {}
 serviceAccount: default
 serviceAccountName: default
 terminationGracePeriodSeconds: 30
 tolerations:
 - effect: NoExecute
   key: node.kubernetes.io/not-ready
   operator: Exists
   tolerationSeconds: 300
 - effect: NoExecute
   key: node.kubernetes.io/unreachable
   operator: Exists
   tolerationSeconds: 300
 volumes:
 - emptyDir:
     medium: Memory
   name: istio-envoy
 - name: istio-certs
   secret:
     defaultMode: 420
     optional: true
     secretName: istio.default
 - name: default-token-48vxx
   secret:
     defaultMode: 420
     secretName: default-token-48vxx
status:
 conditions:
 - lastProbeTime: null
   lastTransitionTime: 2018-01-02T02:33:54Z
   status: "True"
   type: Initialized
 - lastProbeTime: null
   lastTransitionTime: 2018-01-02T02:36:06Z
   status: "True"
   type: Ready
 - lastProbeTime: null
   lastTransitionTime: 2018-01-02T02:33:36Z
   status: "True"
   type: PodScheduled
 containerStatuses:
 - containerID: docker://5d0c189b9dde8e14af4c8065ee5cf007508c0bb2b3c9535598d99dc49f531370
   image: nginmesh/proxy_debug:0.2.12
   imageID: docker-pullable://nginmesh/proxy_debug@sha256:6275934ea3a1ce5592e728717c4973ac704237b06b78966a1d50de3bc9319c71
   lastState: {}
   name: istio-proxy
   ready: true
   restartCount: 0
   state:
     running:
       startedAt: 2018-01-02T02:36:05Z
 - containerID: docker://aba3e114ac1aa87c75e969dcc1b0725696de78d3407c5341691d9db579429f28
   image: istio/examples-bookinfo-reviews-v3:0.2.3
   imageID: docker-pullable://istio/examples-bookinfo-reviews-v3@sha256:6e100e4805a8c10c47040ea7b66f10ad619c7e0068696032546ad3e35ad46570
   lastState: {}
   name: reviews
   ready: true
   restartCount: 0
   state:
     running:
       startedAt: 2018-01-02T02:35:47Z
 hostIP: 10.12.5.31
 initContainerStatuses:
 - containerID: docker://b55108625832a3205a265e8b45e5487df10276d5ae35af572ea4f30583933c1f
   image: nginmesh/proxy_init:0.2.12
   imageID: docker-pullable://nginmesh/proxy_init@sha256:f73b68839f6ac1596d6286ca498e4478b8fcfa834e4884418d23f9f625cbe5f5
   lastState: {}
   name: istio-init
   ready: true
   restartCount: 0
   state:
     terminated:
       containerID: docker://b55108625832a3205a265e8b45e5487df10276d5ae35af572ea4f30583933c1f
       exitCode: 0
       finishedAt: 2018-01-02T02:33:53Z
       reason: Completed
       startedAt: 2018-01-02T02:33:53Z
 phase: Running
 podIP: 192.168.79.138
 qosClass: BestEffort
 startTime: 2018-01-02T02:33:39Z

该命令行输出的内容相当长,我们可以看到 Pod 中注入了一个 nginmesh/proxy_debug container , 还增加了一个 initContainer nginmesh/proxy_init。这两个容器是通过kubernetes initializer 自动注入到 pod 中的。这两个 container 分别有什么作用呢?让我们看一下 Nginmesh 源代码中的说明(注8):

proxy_debug, which comes with the agent and NGINX.

proxy_init, which is used for configuring iptables rules for transparently injecting an NGINX proxy from the proxy_debug image into an application pod.

proxy_debug 就是 sidecar 代理,proxy_init 则用于配置 iptable 规则,以将应用的流量导入到 sidecar 代理中。

查看 proxy_init 的 Dockerfile 文件,可以看到 proxy_init 其实是调用了prepare_proxy.sh(注9)这个脚本来创建 iptable 规则。

proxy_debug Dockerfile

FROM debian:stretch-slim
RUN apt-get update && apt-get install -y iptables
ADD prepare_proxy.sh /
ENTRYPOINT ["/prepare_proxy.sh"]

prepare_proxy.sh节选

...omitted for brevity 

# Create a new chain for redirecting inbound and outbound traffic to
# the common Envoy port.
iptables -t nat -N ISTIO_REDIRECT                                             -m comment --comment "istio/redirect-common-chain"
iptables -t nat -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-port ${ENVOY_PORT}  -m comment --comment "istio/redirect-to-envoy-port"

# Redirect all inbound traffic to Envoy.
iptables -t nat -A PREROUTING -j ISTIO_REDIRECT                               -m comment --comment "istio/install-istio-prerouting"

# Create a new chain for selectively redirecting outbound packets to
# Envoy.
iptables -t nat -N ISTIO_OUTPUT                                               -m comment --comment "istio/common-output-chain"

...omitted for brevity





4. 关联阅读

Istio  及Bookinfo 示例程序安装试用笔记(注10)




5. 参考

Service Mesh with Istio and NGINX(注11)

Using kubeadm to Create a Cluster(注12)

Kubernetes Reference Documentation-Dynamic Admission Control(注13)



注:

1、https://kubernetes.io/docs/set ... beadm

2、https://kubernetes.io/docs/adm ... izers

3、https://kubernetes.io/docs/adm ... lpha-

4、https://github.com/nginmesh/nginmesh

5、https://kubernetes.io/docs/con ... ancer

6、https://docs.openstack.org/mag ... .html

7、http://zhaohuabing.com/2017/11 ... side/

8、https://github.com/nginmesh/ng ... agent

9、https://github.com/nginmesh/ng ... xy.sh

10、https://github.com/nginmesh/ng ... xy.sh

11、https://github.com/nginmesh/nginmesh/

12、https://kubernetes.io/docs/set ... hosts

13、https://kubernetes.io/docs/set ... hosts


 

Service Mesh深度思考 | DreamMesh抛砖引玉(3)-艰难的过渡

ServiceMesh小数 发表了文章 • 0 个评论 • 444 次浏览 • 2018-04-11 15:10 • 来自相关话题

作者:

       敖小剑,资深码农,十六年软件开发经验,微服务专家,Service Mesh布道师。专注于基础架构,Cloud Native 拥护者,敏捷实践者,坚守开发一线打磨匠艺的架构师。机缘巧合下对基础架构和微服务有过深入研究和实践。

        博客链接:https://skyao.io



在上一篇中,我们讨论的话题是:如果没有做好Cloud Native的准备,该怎么上Service Mesh。本章继续讨论,假定Cloud Native已经准备好,看看Service Mesh的道路是否就一帆风顺。



问题所在


如何从非Service Mesh体系过渡到Service Mesh?


我们需要考虑的是:

即使一切准备就绪,对于一个有存量应用的系统而言,绝无可能将所有应用都一起改为Service Mesh,然后一夜之间上线。


必然会有一个中间过渡状态,一部分应用开始搬迁到 Service Mesh,一部分还停留在原有体系。


那么,在过渡阶段,Service Mesh 内的服务和 Service Mesh 外的服务在通讯时会遇到哪些问题?



场景分析


我们来看一个具体的例子,有三个服务,调用关系分别是 A->B->C,然后在最前面架设 API Gateway。非常典型的微服务体系:






这里可以是 spring cloud/dubbo/motan 等各种侵入式微服务架构,左边的注册中心/registry 的实现也可以有多种,服务间通讯的方式也不尽相同。但是,都不影响我们的讨论。


上图可以看到,在标准的微服务框架中,处理这样一个请求,调用方式是清晰明了的。


如果开始转向 Service Mesh 体系,无论是 Istio/Conduit,都会引入一个新的 K8S 体系。为了充分演示,我们选择将服务B转移到 Service Mesh。调用关系就一下变成复杂:






这里我们引入两个术语(TBD:应该是业界通用术语吧?待确认):


东西向通讯:指微服务间相互调用。

南北向通讯:指外界访问微服务体系,通常是通过API Gateway。


当B被迁移后,B原有的上游调用(A调用B)和下游调用(B调用C),虽然业务语意上依然还是东西向通讯,但是由于跨了体系导致原有的调用方式被打破。只能另想办法,目前看通常的做法都是改走南北向通讯。



影响


而这个改变会带来巨大的工作量:


   1. B的所有上游服务都要修改

原有的标准服务间通讯(通过sdk进行服务发现/负载均衡等)都废弃,需要改为对k8s体系入口如Ingress的调用。然后在Ingress这边也要做好对服务B的配置。

  2. B对所有下游服务的调用方式都要修改


同样,原有的标准服务间通讯都废弃,需要改为对API Gateway的调用。然后在API Gateway这边也要做好对下游服务的配置。


而通讯机制改变带来的工作量不是唯一的问题,还有一个内部服务对外暴露的问题:

在原有体系中,服务B和服务C都是内部服务,完全可以不对外暴露,API Gateway访问的只是服务A;

迁移之后,为了让服务B的上游服务能够访问到服务B,就不得不将服务B暴露出来;

同样,为了让服务B能够访问它的下游服务,就不得不将服务C暴露出来。

原体系中只有服务A对外暴露,现在服务B和服务C也不得不暴露。而对外暴露服务,就意味着必然还会有一堆相关的工作需要完成:

认证

授权

加密

……


而这些都意味着:工作量/复杂度/更多的开发测试上线。






后续影响

随着应用往 Service Mesh 体系的逐渐迁移,我们开始迁移服务C和服务A。


先看服务C迁移到来的变化:







此时服务B到服务C的调用从原来的走 API Gateway 改变为 Service Mesh 体系内的服务间调用。然后 API Gateway 不再需要调用服务C,可以去除和服务C相关的内容。


再看服务A的迁移:








此时服务B不再需要暴露,而服务A的暴露方式发生变化,另外服务A调用服务B的方式也有改变。


我们抛开细节,只看整体:在服务 A/B/C 迁移到 Service Mesh 体系的过程中,服务间调用方式和对外暴露方式的变化,带来了一系列的工作量。而耗费这些工作量的中间环节,在整体迁移完成之后都会消失。换言之,都是迫不得已的临时投入,对最后的系统不产生增益。


直白一点:在过渡阶段的这诸多折腾,只是完成了服务迁移,而不能带来任何收益。这一点,无疑是令人沮丧的。


问题本质

反思一下:为何服务只是体系间迁移一下,就需要增加这么多不带来实际收益的工作量和复杂度?到底我们上面这些折腾是在做什么?

很明显,在这个过程中,我们没有任何业务改动,三个服务的实现也没有发生任何变化。

那么,改变的东西是什么?


是服务间通讯:


迁移过程中,服务A/B/C之间的通讯在业务语意上虽然依然属于东西向的服务间通讯机制,但是在实现上,却不得不临时转为南北向的网关到服务的通讯机制。


这个转变是无奈的,两个体系之间存在以下问题导致无法继续走东西向服务间通讯机制:


1. 没有共同的registry,因此无法相互感知;

2. 没有可以直接连通的网络通道,原有的服务间通讯被迫走公开的API Gateway和Ingress通道;

3. 两个体系的服务间通讯机制也可能不同,导致迁移之后不得不重新实现服务间通讯机制;

4. API Gateway和Ingress对于服务暴露的方式也不尽相同,各种特性如认证/加密/服务路由等方式也很可能完全不同。

这就如同江河中的淡水鱼,如果要随波汇入大海,就必须要能适应海水。


然后我们的问题在于,在过渡阶段,不得不花费大量投入来的完成被两个体系分割的服务间通讯,增加了大量额外的工作。



后记

有没有办法解决这个问题,或者部分减轻工作量,为将来的 Service Mesh 转型做好准备?

后续章节会深入探讨这个话题,给出部分解决方案,也欢迎大家给出意见或者参与讨论。

有兴趣的朋友,请添加小数微信:xiaoshu062,加入service mesh内部讨论群。



讨论和反馈

冉启春:任何两个架构体系的迁移都是痛苦的

于文涛:运维团队负责容器化和k8s,基础架构部负责数据库拆分和分库分表以及底层中间件,业务平台部门参与微服务业务改造,其实路径没有统一的,得看不同团队的执行结果和如何协调了。谁强势先突破可能会有主导权。不过一般的路径是先底层后业务层。


  查看全部
作者:

       敖小剑,资深码农,十六年软件开发经验,微服务专家,Service Mesh布道师。专注于基础架构,Cloud Native 拥护者,敏捷实践者,坚守开发一线打磨匠艺的架构师。机缘巧合下对基础架构和微服务有过深入研究和实践。

        博客链接:https://skyao.io



在上一篇中,我们讨论的话题是:如果没有做好Cloud Native的准备,该怎么上Service Mesh。本章继续讨论,假定Cloud Native已经准备好,看看Service Mesh的道路是否就一帆风顺。



问题所在


如何从非Service Mesh体系过渡到Service Mesh?


我们需要考虑的是:

即使一切准备就绪,对于一个有存量应用的系统而言,绝无可能将所有应用都一起改为Service Mesh,然后一夜之间上线。


必然会有一个中间过渡状态,一部分应用开始搬迁到 Service Mesh,一部分还停留在原有体系。


那么,在过渡阶段,Service Mesh 内的服务和 Service Mesh 外的服务在通讯时会遇到哪些问题?



场景分析


我们来看一个具体的例子,有三个服务,调用关系分别是 A->B->C,然后在最前面架设 API Gateway。非常典型的微服务体系:

1.png


这里可以是 spring cloud/dubbo/motan 等各种侵入式微服务架构,左边的注册中心/registry 的实现也可以有多种,服务间通讯的方式也不尽相同。但是,都不影响我们的讨论。


上图可以看到,在标准的微服务框架中,处理这样一个请求,调用方式是清晰明了的。


如果开始转向 Service Mesh 体系,无论是 Istio/Conduit,都会引入一个新的 K8S 体系。为了充分演示,我们选择将服务B转移到 Service Mesh。调用关系就一下变成复杂:

2.png


这里我们引入两个术语(TBD:应该是业界通用术语吧?待确认):


东西向通讯:指微服务间相互调用。

南北向通讯:指外界访问微服务体系,通常是通过API Gateway。


当B被迁移后,B原有的上游调用(A调用B)和下游调用(B调用C),虽然业务语意上依然还是东西向通讯,但是由于跨了体系导致原有的调用方式被打破。只能另想办法,目前看通常的做法都是改走南北向通讯。



影响


而这个改变会带来巨大的工作量:


   1. B的所有上游服务都要修改

原有的标准服务间通讯(通过sdk进行服务发现/负载均衡等)都废弃,需要改为对k8s体系入口如Ingress的调用。然后在Ingress这边也要做好对服务B的配置。

  2. B对所有下游服务的调用方式都要修改


同样,原有的标准服务间通讯都废弃,需要改为对API Gateway的调用。然后在API Gateway这边也要做好对下游服务的配置。


而通讯机制改变带来的工作量不是唯一的问题,还有一个内部服务对外暴露的问题:

在原有体系中,服务B和服务C都是内部服务,完全可以不对外暴露,API Gateway访问的只是服务A;

迁移之后,为了让服务B的上游服务能够访问到服务B,就不得不将服务B暴露出来;

同样,为了让服务B能够访问它的下游服务,就不得不将服务C暴露出来。

原体系中只有服务A对外暴露,现在服务B和服务C也不得不暴露。而对外暴露服务,就意味着必然还会有一堆相关的工作需要完成:

认证

授权

加密

……


而这些都意味着:工作量/复杂度/更多的开发测试上线。






后续影响

随着应用往 Service Mesh 体系的逐渐迁移,我们开始迁移服务C和服务A。


先看服务C迁移到来的变化:

3.png



此时服务B到服务C的调用从原来的走 API Gateway 改变为 Service Mesh 体系内的服务间调用。然后 API Gateway 不再需要调用服务C,可以去除和服务C相关的内容。


再看服务A的迁移:


4.png



此时服务B不再需要暴露,而服务A的暴露方式发生变化,另外服务A调用服务B的方式也有改变。


我们抛开细节,只看整体:在服务 A/B/C 迁移到 Service Mesh 体系的过程中,服务间调用方式和对外暴露方式的变化,带来了一系列的工作量。而耗费这些工作量的中间环节,在整体迁移完成之后都会消失。换言之,都是迫不得已的临时投入,对最后的系统不产生增益。


直白一点:在过渡阶段的这诸多折腾,只是完成了服务迁移,而不能带来任何收益。这一点,无疑是令人沮丧的。


问题本质

反思一下:为何服务只是体系间迁移一下,就需要增加这么多不带来实际收益的工作量和复杂度?到底我们上面这些折腾是在做什么?

很明显,在这个过程中,我们没有任何业务改动,三个服务的实现也没有发生任何变化。

那么,改变的东西是什么?


是服务间通讯:


迁移过程中,服务A/B/C之间的通讯在业务语意上虽然依然属于东西向的服务间通讯机制,但是在实现上,却不得不临时转为南北向的网关到服务的通讯机制。


这个转变是无奈的,两个体系之间存在以下问题导致无法继续走东西向服务间通讯机制:


1. 没有共同的registry,因此无法相互感知;

2. 没有可以直接连通的网络通道,原有的服务间通讯被迫走公开的API Gateway和Ingress通道;

3. 两个体系的服务间通讯机制也可能不同,导致迁移之后不得不重新实现服务间通讯机制;

4. API Gateway和Ingress对于服务暴露的方式也不尽相同,各种特性如认证/加密/服务路由等方式也很可能完全不同。

这就如同江河中的淡水鱼,如果要随波汇入大海,就必须要能适应海水。


然后我们的问题在于,在过渡阶段,不得不花费大量投入来的完成被两个体系分割的服务间通讯,增加了大量额外的工作。



后记

有没有办法解决这个问题,或者部分减轻工作量,为将来的 Service Mesh 转型做好准备?

后续章节会深入探讨这个话题,给出部分解决方案,也欢迎大家给出意见或者参与讨论。

有兴趣的朋友,请添加小数微信:xiaoshu062,加入service mesh内部讨论群。



讨论和反馈

冉启春:任何两个架构体系的迁移都是痛苦的

于文涛:运维团队负责容器化和k8s,基础架构部负责数据库拆分和分库分表以及底层中间件,业务平台部门参与微服务业务改造,其实路径没有统一的,得看不同团队的执行结果和如何协调了。谁强势先突破可能会有主导权。不过一般的路径是先底层后业务层。