什么是容器、微服务与服务网格?



前言

如你所知,已经有不少关于服务网格的资料,但这是另一篇。是的!可是为何会有这篇文章呢?由于我想给大家一些不一样的视角,他们但愿服务网格在10年前就已经存在,远早于Docker和Kubernetes这样的容器平台的兴起。我并非说这个视角比其余视角更好或更差,可是因为服务网格是至关复杂的“野兽”,因此我相信多种视角有助于更好地理解它们。
前端


我将讨论dotCloud平台,这是一个创建在100多个微服务之上的平台,支持数千个运行在容器中的生产应用程序;我将解释在构建和运行它时所面临的挑战;以及服务网格会(或不会)提供帮助。git


dotCloud的历史


我已经写过关于dotCloud平台的历史和它的一些设计选择,可是我没有过多地讨论它的网络层。若是你不想深刻了解我以前关于dotCloud的博客,你须要知道的是它是一个PaaS,容许客户运行各类应用程序(Java、PHP、Python等),支持普遍的数据服务(MongoDB、MySQL、Redis等)以及相似于Heroku的工做流程:你能够将代码推送到平台,平台将构建容器镜像,并部署这些容器镜像。

我将告诉你流量是如何在dotCloud平台上路由的;不是由于它是特别棒或其余什么(我认为如今是比较合适的时间),但主要是由于,若是一个普通的团队须要一种在一个微服务群或一个应用程序群之间路由流量的方法,那么这种设计能够在短期内用如今已有的工具轻松实现。所以,它将为咱们提供一个很好的比较点,“若是咱们破解它,咱们会获得什么”和“若是咱们使用现有的服务网格,咱们会获得什么”,也就是老生常谈的“构建与购买”的困境。

托管应用的流量路由


部署在dotCloud上的应用程序会暴露HTTP和TCP端点。

HTTP端点被动态地添加到负载平衡器集群的配置中。这与咱们今天使用Kubernetes Ingress资源和Traefik这样的负载平衡器能够实现的功能相似。

只要域名指向dotCloud的负载平衡器,客户端就可使用它们的关联域名链接到HTTP端点。这里没有什么特别的。

TCP端点与端口号相关联,而后端口号经过环境变量与该堆栈上的全部容器通讯。

客户端可使用指定的主机名(相似于gateway-X.dotcloud.com)和端口号链接到TCP端点。

该主机名将解析为一个“nats”服务器集群(与NATS没有任何关系),该集群将把传入的TCP链接路由到正确的容器(或者,在负载平衡服务的状况下,路由到正确的容器)。

若是你熟悉Kubernetes,这可能会让你想起NodePort服务。

dotCloud平台没有集群IP服务的等价物:为了简单起见,从内部和外部访问服务的方式是相同的。

这很是简单,最初的HTTP和TCP路由网格的实现可能都是几百行Python代码,使用至关简单(我敢说,很天真)的算法,可是随着时间的推移,它们不断发展,以处理平台的增加和额外的需求。

它不须要对现有应用程序代码进行大量重构。十二因素应用程序尤为能够直接使用经过环境变量提供的地址信息。

它与现代服务网络有何不一样?


可观察性有限。对于TCP路由网格根本没有度量标准。至于HTTP路由网格,后来的版本提供了详细的HTTP度量,显示错误状态码和响应时间;可是现代服务网格的功能远远不止于此,它还提供了与度量收集系统(例如Prometheus)的集成。

可观察性很是重要,不只从操做角度(帮助咱们解决问题),还能够提供安全的蓝/绿部署或金丝雀部署等功能。

路由效率也受到限制。在dotCloud路由网格中,全部流量都必须通过一组专用路由节点。这意味着可能跨越几个AZ(可用性区域)边界,并显著增长延迟。我记得对一些代码进行故障排除,这些代码发出100多个SQL请求来显示给定的页面,并为每一个请求打开了到SQL服务器的新链接。在本地运行时,页面会当即加载,但在dotCloud上运行时,须要几秒钟,由于每一个TCP链接(以及随后的SQL请求)都须要几十毫秒才能完成。在这种特定的状况下,使用持久链接起了做用。

现代服务网络作得更好。首先,经过确保链接在源位置路由。逻辑流仍然是客户端-->网格-->服务,可是如今网格在本地运行,而不是在远程节点上运行,所以客户端-->网格链接是本地链接,所以速度很是快(微秒而不是毫秒)。

现代服务网格还实现了更智能的负载平衡算法。经过监控后端的运行及健康情况,它们能够在更快的后端上发送更多的流量,从而提升总体性能。

随着现代服务网络的出现,安全性也愈来愈强。dotCloud路由网格彻底在EC2 Classic上运行,而且没有加密流量(假设若是有人设法嗅探EC2上的网络流量,那么不管如何都会遇到更大的问题)。现代服务网格能够透明地保护咱们全部的通讯,例如经过相互的TLS身份验证和随后的加密。

平台服务的流量路由


OK,咱们已经讨论了应用程序是如何通讯的,可是dotCloud平台自己呢?
平台自己由大约100个微服务组成,负责各类功能。其中一些服务接受来自其余服务的请求,而其中一些服务是后台工做应用,它们将链接到其余服务,但不能本身接收链接。不管哪一种方式,每一个服务都须要知道它须要链接到的地址的端点。

许多高级服务均可以使用上面描述的路由网格。事实上,dotCloud平台的100多个微服务中有很大一部分是做为常规应用程序部署在dotCloud平台上的。可是少数低级服务(特别是那些实现路由网格的服务)须要一些更简单的东西,须要更少的依赖关系(由于它们不能依靠本身来运行;这是一个老生常谈的“先有鸡仍是先有蛋”的问题)。

经过直接在几个关键节点上启动容器,而不是依赖于平台的构建器、调度程序和运行器服务,部署了这些底层的基本平台服务。若是你想要与现代容器平台进行比较,这就像直接在节点上运行Docker来启动咱们的控制平面,而不是让Kubernetes为咱们作这件事。这与kubeadm或bootkube在引导自托管集群时使用的静态Pod的概念很是类似。

这些服务以一种很是简单和粗糙的方式被公开:有一个YAML文件列出了这些服务,将它们的名称映射到它们的地址;做为其部署的一部分,这些服务的每一个使用者都须要一份该YAML文件的副本。

一方面,这是很是强大的,由于它不涉及像ZooKeeper那样维护外部键值存储(记住,etcd或Consul在那个时候不存在)。另外一方面,这使得服务难以移动。每次移动服务时,它的全部消费者都须要接收更新的YAML文件(而且可能会从新启动)。不太方便!

咱们开始实现的解决方案是让每一个消费者都链接到一个本地代理。使用者不须要知道服务的完整地址+端口,只须要知道它的端口号,并经过localhost进行链接。本地代理将处理该链接,并将其路由到实际后端。如今,当一个后端须要移动到另外一台机器上,或按比例放大或缩小,而不是更新它的全部消费者,咱们只须要更新全部这些本地代理;咱们再也不须要从新启动消费者。

还计划将流量封装在TLS链接中,并在接收端使用另外一个代理来打开TLS并验证证书,而不涉及接收服务,该服务将被设置为仅在本地主机上接受链接。稍后会详细介绍。

这与AirBNB的SmartStack很是类似;与SmartStack实现并部署到生产环境的显著区别是,当dotCloud转向Docker时,它的新的内部路由网格被搁置了。

我我的认为SmartStack是诸如Istio、Linkerd、Consul Connect等系统的先驱之一,由于全部这些系统都遵循这种模式:

  • 在每一个节点上运行代理github

  • 消费者链接到代理web

  • 后端改变时,控制平面更新代理的配置算法


今天实现一个服务网格


若是咱们今天必须实现相似的网格,咱们可使用相似的原则。例如,咱们能够设置一个内部域名系统区域,将服务名映射到127.0.0.0/8空间中的地址。而后在集群的每一个节点上运行HAProxy,接受每一个服务地址(在127.0.0.0/8子网中)上的链接,并将它们转发/负载平衡到适当的后端。HAProxy配置能够由confd管理,容许在etcd或Consul中存储后端信息,并在须要时自动将更新的配置推送到HAProxy。

这就是Istio的工做原理!可是有一些不一样之处:

  • 它使用Envoy Proxy而不是HAProxy数据库

  • 它使用Kubernetes API而不是etcd或Consul来存储后端配置后端

  • 服务在内部子网中分配地址(Kubernetes集群IP地址),而不是127.0.0.0/8api

  • 它有一个额外的组件(Citadel),用于在客户机和服务器之间添加相互的TLS身份验证安全

  • 它增长了对诸如断路、分布式跟踪、金丝雀部署等新特性的支持服务器


让咱们快速回顾一下这些差别。

Envoy Proxy


Envoy Proxy由Lyft撰写。它与其余代理(如HAProxy、NGINX、Traefik)有许多类似之处,但Lyft编写它是由于它们须要当时这些代理中不存在的功能,并且构建一个新的代理比扩展示有代理更有意义。

Envoy能够单独使用。若是有一组给定的服务须要链接到其余服务,能够把它链接到Envoy,而后动态地配置和从新配置其余服务的Envoy的位置,而获得不少漂亮的额外的功能,好比域的可观测性。这里,没有使用定制的客户端库,也没有在代码中添加跟踪调用,而是将流量定向到Envoy,让它为我收集指标。

但Envoy也能够用做服务网格的数据平面。这意味着如今将由该服务网格的控制平面配置Envoy。

控制平面


说到控制平面,Istio依赖于Kubernetes API。这与使用confd没有太大的不一样。confd依赖etcd或Consul来监视数据存储中的一组密钥。Istio依赖Kubernetes API来监视一组Kubernetes资源。

Aparte:我我的认为阅读Kubernetes API描述[1]很是有帮助。
Kubernetes API服务器是一个“哑服务器”,它提供API资源上的存储、版本控制、验证、更新和监视语义。
Istio是为与Kubernetes合做而设计的;若是你想在Kubernetes以外使用它,则须要运行Kubernetes API服务器的实例(以及支持的etcd服务)。

服务地址


Istio依赖Kubernetes分配的集群IP地址,所以Istio获得一个内部地址(不在127.0.0.1/8范围)。

在没有Istio的Kubernetes集群上,前往给定服务的ClusterIP地址的流量被kube-proxy拦截,并发送到该代理的后端。更具体地说,若是你想肯定技术细节:kube-proxy设置iptables规则(或IPVS负载平衡器,取决于它是如何设置的)来重写链接到集群IP地址的目标IP地址。

一旦Istio安装在Kubernetes集群上,就不会发生任何变化,直到经过将sidecar容器注入到使用者Pod中,显式地为给定的使用者甚至整个名称空间启用Istio。sidecar将运行一个Envoy实例,并设置一些iptables规则来拦截到其余服务的流量,并将这些流量重定向到Envoy。

结合Kubernetes DNS集成,这意味着咱们的代码能够链接到一个服务名,一切均可以正常工做。换句话说,好比咱们的代码向 http://api/v1/users/4242发起一个请求, api将解析到10.97.105.48,一条iptables规则将解释链接到10.97.105.48并重定向到本地Envoy代理,本地代理将这个请求路由到实际的API后端。

额外的铃声和哨声


Istio还能够经过名为Citadel的组件经过mTLS(双向TLS)提供端到端加密和身份验证。

它还包括混合器,Envoy组件能够查询每个请求,对请求进行一个临时的决定取决于各类因素,例如请求头、后端负载(别担忧,有丰富的规定以确保混合高度可用,即便它休息,Envoy能够继续代理流量)。

固然,我提到了可观察性。Envoy在提供分布式跟踪的同时收集大量的度量指标。微服务架构,若是单个API请求必须通过微服务A、B、C和D,分布式跟踪将添加一个唯一的标识符请求进入系统,并保留标识符在子请求中,全部这些微服务容许收集全部相关的调用、延迟等。

自建仍是购买


Istio以复杂著称。相比之下,使用咱们今天拥有的工具,构建像我在本文开头描述的那样的路由网格相对比较简单。那么,构建咱们本身的服务网格是否有意义呢?

若是咱们有适度的需求(若是咱们不须要可观察性,断路器,和其余细节),咱们可能想创建本身的。可是若是咱们正在使用Kubernetes,咱们甚至可能不须要这样作,由于Kubernetes已经提供了基本的服务发现和负载平衡。

如今,若是咱们有高级的需求,购买服务网格多是一个更好的选择。(因为Istio是开源的,因此它并不老是真正的购买,可是咱们仍然须要投入工程时间来理解它是如何工做、部署和运行的。)

如何选择Istio、Linkerd和Consul Connect


到目前为止,咱们只讨论了Istio,但它并非惟一的服务网格。Linkerd是另外一个流行的选择,还有Consul Connect。

咱们应该选哪个呢?

实际上在这一点上我也很差说,我不认为我有足够的了解可以帮助任何人作决策。不过,已经有一些有趣的文章[2]比较它们,甚至基准测试。

一种值得一提而且颇有潜力的方法是使用像SuperGloo这样的工具。SuperGloo提供了一个抽象层来简化和统一服务网格公开的API。咱们可使用SuperGloo提供的更简单的构造,并没有缝地从一个服务网格切换到另外一个服务网格,而不是学习各类服务网格的特定API(在我看来,相对复杂)。有点像咱们有一个描述HTTP前端和后端的中间配置格式,可以为NGINX、HAProxy、Traefik、Apache生成实际配置 我已经使用SuperGloo稍微涉足Istio,在将来的博客文章中,我想说明如何使用SuperGloo将Isio或Linkerd添加到现有的集群中,以及后者是否能实现它的承诺,即容许我在不重写配置的状况下从一个路由网格切换到另外一个。

若是你喜欢这篇文章,而且想让我尝试一些具体的场景,我很乐意听到你的消息!

相关连接:
  1. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/protobuf.md#proposal-and-motivation

  2. https://thenewstack.io/which-service-mesh-should-i-use/


原文连接:https://jpetazzo.github.io/2019/05/17/containers-microservices-service-meshes/

推荐阅读:

什么是Service Mesh?

基于SpringCloud的微服务架构演变史?

Spring Cloud中Hystrix、Ribbon及Feign的熔断关系是什么?

Spring Cloud微服务运维神器之Consul Template?

Python写的微服务如何融入Spring Cloud体系?

Spring Cloud微服务接口这么多怎么调试?

Spring Boot集成Flyway实现数据库版本控制?

Spring Cloud微服务如何实现熔断降级?

Spring Cloud微服务如何设计异常处理机制?

Spring Cloud微服务中网关服务是如何实现的?(Zuul篇)

Spring Cloud是怎么运行的?

Spring Boot究竟是怎么运行的,你知道吗?



—————END—————



识别图片二维码,关注“无敌码农”获取精彩内容

友情推广|第六届 Service Mesh Meetup 广州站

让各位久等了,第六届Service Mesh Meetup广州站开放报名了!涵盖 Kubernetes、微服务和 Service Mesh 话题,8 月 11 日(星期日),广州见!报名地址:https://tech.antfin.com/community/activities/781


本文分享自微信公众号 - 无敌码农(jiangqiaodege)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索