前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用容器进行应用程序路由

使用容器进行应用程序路由

作者头像
Techeek
发布2018-01-15 17:53:29
8560
发布2018-01-15 17:53:29
举报
文章被收录于专栏:云计算云计算

本文收录在DZone的容器编制与部署指南中。点击此处阅读更多富有洞察力的文章、行业统计数据等内容!

容器改变了我们对构建、打包和部署应用程序的思考方式。从开发人员的角度来看,它们帮助我们更轻松地将应用程序与其全套依赖库进行打包,并可以在另一个开发人员的工作站上可靠地重建这个应用程序。它还使我们能在经历了开发、测试、生成最终产品(可能使用了持续集成(Continuous Integration, CI)及持续交付(Continuous Delivery CD)管道)这整个过程之后,交付出可靠的应用程序。最后,在微服务盛行的今天,容器有助于将微服务提供给大规模的产品开发所用。

在开发云原生应用以及像微服务这样的服务体系结构时,我们能够更方便地部署或管理基础架构。但与传统程序设计相比,我们在开发这些应用程序时,需要考虑不同的设计原则:故障应对、水平缩放、不断变化的环境等。有趣的是,当我们使用这些原则来开发服务时,我们便会发现,服务间的交互总是比实现服务本身要来得复杂。

容器可以帮助解决这一问题吗?

服务交互是麻烦所在

首先,我们应该确定麻烦在哪,以及服务间交互的复杂性是如何体现的。服务间通信是必要的,毕竟各个服务相互协作才能产生商业价值。在云架构中,服务间通信将通过网络进行。这是第一个复杂性来源——传统应用程序的各个组件都运行在同一台机器上,因此不必考虑网络通信问题。

只要某一服务通过网络与其它服务进行了交互,错误就有可能产生。异步分组交换网络并不能保证预期的事情一定会发生,也不能保证计划外的事情一定不会发生。当我们把数据输送到网络上时,它会经过许多路由跳跃和队列等待才能到达预定目的地。这一路上,数据可能遭遇丢失、重复或延迟等情况。

而且,这样的特性使我们难以确定与另一端的协作服务的通信失败是因为网络不通或拥塞,还是因为另一端的服务出错或运行缓慢。这可能会导致不安全的后果,例如服务无法为客户提供服务、仅有一部分协作内容正确执行、服务之间数据不一致等等。

网络故障或退化(或是可感知到的故障或退化)会引发问题。相应地,我们需要思考:服务如何找到其协作者并与之通信?它如何在其协作者的多个实例之间进行负载均衡?当我们用容器来构建这些云原生服务时,我们需要考虑网络通信导致的复杂性。我们需要实现服务发现,负载平衡,断路器,超时和重试等特性,使得我们的服务具有“弹性”,能应对种种不确定的网络行为。

听起来,我们的应用程序担负了太多责任。我们可以创建可重用库来帮助解决这个问题。的确,这是许多大型互联网公司采取的方法。 Google投入了大量的工作来实现一个远程过程调用(Remote Procedure Call,RPC)库来帮助解决这些问题,即Stubby(现在是gRPC)。 Twitter的Finagle框架也是如此。 Netflix甚至好心地在它的Netflix OSS库中开源了如Ribbon,Hystrix等项目。

为了做到这一点,我们需要将我们的框架和语言限制在那些我们可以实现和维护这些横切关注点的领域。我们需要为每个我们想要支持的语言和框架重新实现这些模式。此外,每个开发人员都需要遵守这些规则,将这些库和惯用语法一致地应用到他们编写的所有代码中。可以说,以前,Netflix的程序员们不得不写这些工具,因为他们别无选择。他们的尝试是,在IaaS云基础架构之上构建弹性服务。那么,我们今天又有什么选择呢?

容器平台

利用容器平台,可以进行基本的服务发现和负载平衡。例如,如果您将应用程序打包为Docker容器,并且正在使用Kubernetes,那么负载平衡和基本服务发现的功能就已经被包含在其中了。在Kubernetes中,我们可以使用“Kubernetes服务”概念来定义应用程序集群(集群中的每个实例运行在容器中,或Kubernetes的“pod”中),并将网络(如虚拟IP)分配给这些集群。然后,我们可以使用基本的DNS来发现容器集群并与其进行交互,哪怕集群随着时间的推移而发生变化(加入新的容器等)。

容器化服务的服务网格

我们能否不依赖于特定的语言或框架实现,就在服务架构上解决种种服务弹性问题呢?这就是“服务网格”发挥效用之处。服务网格位于各个服务之间,且无需使用应用程序内部的框架或库就能解决这些问题。

使用服务网格,我们就可以引入应用程序代理,来代表应用程序处理与其他服务的通信。应用程序或服务直接与代理进行通信,并配置好适当的超时、重试、资源预算、断路器等,从而与上游服务进行通信。

这些代理既可以作为共享代理(多个服务使用单个代理),也可以作为“sidecar”代理(某一个应用程序专用)。使用sidecar代理时,代理就和服务的每个实例一起部署,由该代理来负责解决各种横切问题;也就是说,应用程序能够在不直接改动代码的情况下,获得各项功能。

Linkerd和Lyft Envoy是两个常见的代理示例,它们可以用来构建服务网格。Linkerd是来自初创公司Buoyant.io的开源项目,而Envoy则是来自打车公司Lyft的开源项目。在容器环境中,我们可以通过两种方式来实现sidecar代理。一是将代理和应用程序部署在同一个容器中。二是在您可以指定容器关联规则的情况下(例如在Kubernetes pods中),用额外的容器来实现一个sidecar代理。

在Kubernetes中,一个pod就是一个逻辑结构,它认为一个“实例”是一个或多个部署在一起的容器。因此在Kubernetes中实现sidecar代理非常简单。如果使用这些sidecar(或共享)代理,那么我们就可以可靠且统一地实现服务发现、负载平衡、断路器、重试和超时等特性,而不管容器中运行的是什么。

我们使用容器,并忽略其细节,以便统一部署和管理;我们又使用服务网格,以统一的方式,安全地引入容器之间的可靠性。由于这些应用程序代理负责了通信代理、负载平衡、重试等工作,我们还可以收集数据,使我们在网络层面了解服务之间发生的情况。我们可以将这些数据输送到一个中央监控解决方案(比如InfluxDB或Prometheus),并且统一跟踪。我们还可以使用这些代理来报告其他服务运行时的行为元数据,例如将分布式跟踪扩展到像Zipkin这样的可观测工具。

最后,我们可以引入一个控制面板来协助管理各服务网格中的应用程序代理。例如初创项目Istio.io,正提供了这一功能。通过控制面板,我们不仅能够理解并报告服务之间发生的情况,而且还可以控制通信流量。当我们想要部署应用程序的新版本,或是希望执行A/B测试或金丝雀发布(canary release)时,这一点十分有用。通过控制面板,我们可以配置细粒度的服务间路由规则来完成更高级的部署。

容器开创了一个崭新的云原生应用程序模式,而容器平台可以对这些容器进行管理和部署。但是从服务架构的角度来看,当前,我们需要解决的是服务间的复杂性。服务网格旨在解决这个问题,而应用程序代理则使我们无需在应用程序代码中编写那些用于解决种种横切问题的代码(也无需再使用它们的依赖库),以便我们专注于业务逻辑。容器和容器环境帮助我们自然地实现这个服务网格模式。

本文收录在DZone的容器编制与部署指南中。点击此处阅读更多富有洞察力的文章、行业统计数据等内容!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 服务交互是麻烦所在
  • 容器平台
  • 容器化服务的服务网格
相关产品与服务
容器镜像服务
容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档