专题 | A Service Mesh for Kubernetes第4期:轻松预发微服务

小数 发表了文章 • 0 个评论 • 72 次浏览 • 2018-02-09 10:24 • 来自相关话题

作者:RISHA MARS

翻译:蔡悦

转自:容器时代(公众号 CaaSOne)

原文:A Service Mesh for Kubernetes, Part VI : Staging microservices without the tears



概述

在将新代码发布到生产环境之前, 预发布操作是构建一个可靠的、低宕机时间的软件系统的关键组成部分。但是,在微服务体系下,由于拆分出来的许许多多的微服务之间的依赖关系随着微服务数量成指数倍增长,从而增加了预发布操作的复杂性。在这篇文章里,我们将为您介绍 linkerd 的最强大的功能之一,单个请求路由(per-request routing),通过它,您将可以非常轻松的处理这个问题。


注意:这是关于 Linkerd、Kubernetes 和 Service Mesh 的系列文章其中一篇,其余部分包括:
Top-line service metricsPods are great, until they’re notEncrypting all the thingsContinuous deployment via traffic shiftingDogfood environments, ingress, and edge routingStaging microservices without the tears (本文)Distributed tracing made easyLinkerd as an ingress controllergRPC for fun and profitThe Service Mesh APIEgressRetry budgets, deadline propagation, and failing gracefullyAutoscaling by top-line metrics


Linkerd 是云原生应用的一种服务网格(Service Mesh)。它作为对应用透明的网络代理层通过封装服务间的调用为应用提供如:低延迟负载均衡(latency-aware load balancing)、链接重试(retry budgets)及终止(deadlines)、熔断机制(circuit breaking)等特性来提高应用的适应性(application resilience)。


除了能够提高应用的适应性,Linkerd 也能够提供强大的路由语言来改变服务在运行时请求流的方式。这篇文章我们将为您展示 Linkerd 如何做到这一点,不仅仅是全局范围,更精细到每一个基础请求。也将为您展示每一个请求路由如何被用来创建临时的预发布环境,从而允许在生产环境上下文中测试新代码而不用真正将其发布到生产环境里。最后,将为您介绍(in contrast to staging with a dedicated staging environment)临时的预发布环境如何做到既不需要与其他团队的协调工作,也不需要花费时间精力来同时保持多个部署环境。


为什么要预发布

为什么预发布如此重要?在现代软件开发当中,代码需要经过一系列预先设计好的实践路线来保证正确性:代码走查(code review),单元测试(unit tests),集成测试(integration tests)等等。经过这些流程之后,需要开始估算代码的表现了:新代码运行的速度如何?高负载下的表现如何?在运行时与其他服务以及相关依赖的交互表现如何?


预发布系统就可以回答这些问题。预发布的基本原则就是越接近生产环境,系统就越切实可行。因此,就像测试环节中的 mocks 和 stub 一样,对于预发布,我们期望能够运行真实的服务。最好的预发布环境就是和生产环境完全一样。



为什么微服务的预发布很难
如果你的应用由许多微服务构成,那么微服务之间的通信交互就会变成像端到端应用行为一样的重要组成部分。其实,应用拆分的越细,那么在运行时应用之间的交互就会越复杂,而此时应用的表现已经不仅仅是每个微服务自己的问题了,很大程度上取决于微服务之间的交互。

实际上,增加微服务的数量不仅仅增加了正确预发布的重要性,也同时增加了实现这一点的难度。我们来看几个常用的预发布方法,以及为什么在微服务环境下这些方法都会变得比较困难。


预发布的常规方法是共享预发布集群,而在这个集群里,除了你的预发布服务之外其他人的预发布服务也在这里。这种方式的弊端就是没有隔离。如下图展示,如果 Alex 把他的服务发布了上去但是出了点问题,整个链条中就很难判断出问题源的所在--因为问题可能出现在 Alex、Alice 或者 Bob 的服务上,又或者干脆就是数据库里的数据有问题。这样预发布环境与生产环境的同步就会非常困难,尤其是当服务、团队以及发行版本数量庞大的时候。


另一种共享环境称为“私人”或者单个开发者的预发布集群,可以解决隔离的问题。在这个例子中,每一个开发者可以根据需要来操作预发布集群。预发布一个服务需要同时预发布这个服务的上游以及下游服务也包括相关的依赖,从而可以保证预发布的有效性。(比如,在下图中,Alex 必须先发布 Web FE 和 API 服务来保证他的 Foo 服务可以正常运行。)然而,根据需要来维护以及部署部分应用拓扑结构会非常复杂,尤其是当应用拓扑结构非常大而且服务又有独立的部署模型。

上面说的是一种极其简单的部署新代码到生产环境并且有问题时可以回滚的方式。当然了,这种方式很有风险,而且不能处理部分应用类型,比如:金融事务。虽然还有很多其他的部署方法,但是本文我们将介绍一种直接的、轻松的方式。


一种更好的方式

使用 Linkerd 创建临时的预发布环境,就可以很好的避免以上提到的弊端。实际上,在 Twitter 里 Finagle 路由层作为linkerd 的底层,  他的主要动机就是解决这个问题。

我们来看一下 Alex 的 Foo 服务。如果,我们不另外部署一个隔离的环境,而是仅仅使用 Foo 的预发布版本替代 Foo 的生产版本,然后通过一个特殊的请求来访问它呢?针对生产环境,这将能够确保 Foo 的预发布版本的安全性,而且除了 Foo 预发布版本之外也不需要部署其他的任何东西。这就是临时预发布环境的本质。而此时,开发者身上的任务一下就轻松了:Alex 只需要预发布他的新代码,然后在 ingress 请求的 header 上设置一个标记就可以了,就这么简单!

Linkered 的单个请求路由可以帮助我们实现这种方式。通过 linkerd 的请求代理,可以给特定的请求上设置一个 l5d-dtab 的 header 。这个 header 可以允许你设置路由规则(叫做  in Finagle parlance, Dtabs)。比如,dtab 规则 /s/foo => /srv/alex-foo 可以覆盖 Foo 服务生产环境的规则。给单个请求添加这个可以使得请求直接到达 Alex 的 Foo 服务,也仅仅作用与这一个请求。Linkerd 可以拦截这个规则,所以生产环境里任何使用 Alex 的 Foo 服务的地方都可以正确的处理。



试一下这个功能吧

Service Mesh for Kubernetes 系列文章的读者应该已经知道我们有一个 demo our dogfood blog post。我们部署过一个 world-v2 服务,并且可以通过设置重定向路由规则发送单个的 dogfood 请求。现在我们可以使用相同机制来做些别的事情:创建一个临时的预发布环境。

部署一个服务的两个版本,再使用 linkerd 的路由功能在部署到生产环境之前来测试新服务。我们先部署 hello 和 world-v1 服务来作为我们的生产环境服务,然后再创建一个临时的预发布环境来测试 world 服务的新版本 world-v2。


1部署LINKERD和HELLO-WORLD服务


我们使用前一篇文章里部署的 hello world 服务。它由 hello 服务调用 world 服务组成。这些应用通过 Kubernetes downward API 提供的根据 nodeName 来找到 Linkerd 。如果你不确定你的集群是否支持 nodeName, 你可以运行如下命令:kubectl apply -f https://raw.githubusercontent. ... t.yml


然后查看一下日志:kubectl logs node-name-test


如果你看到了 ip 就表示成功了。然后再通过如下命令部署 hello world 应用:kubectl apply -f https://raw.githubusercontent. ... d.yml


如果你看到了 “server can’t find …” 错误,那就部署 hello-world 的 legacy 版本,这个版本依赖 hostIP 而不是 nodeName:kubectl apply -f https://raw.githubusercontent. ... y.yml


然后我们来部署生产环境(linkerd 和 hellow 以及 world 服务):$ kubectl apply -f https://raw.githubusercontent. ... s.yml


再来部署 linkerd 和预发布版本的服务 world-v2 ,这个服务会返回 "earth" 而不是 “world”。$ kubectl apply -f https://raw.githubusercontent. ... s.yml $ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/world-v2.yml 
 

2在临时预发布环境里使用单个请求覆盖

现在,我们运行了 world-v2 服务,来测试一下是否通了。我们期望的是请求到达的是 `world-v2` 而不是 `world-v1`。首先,先运行一个没有更改的请求,这个请求会走默认的路径。(你可能需要等待 l5d 的 external IP 出现):$ INGRESS_LB=$(kubectl get svc l5d -o jsonpath="{.status.loadBalancer.ingress[0].*}") $ curl -H "Host: www.hello.world" $INGRESS_LB Hello (10.196.2.232) world (10.196.2.233)!!


如果外部负载均衡不起作用,可以使用 hostIP:INGRESS_LB=$(kubectl get po -l app=l5d -o jsonpath="{.items[0].status.hostIP}"):$(kubectl get svc l5d -o 'jsonpath={.spec.ports[0].nodePort}') $ curl -H "Host: www.hello.world" $INGRESS_LB Hello (10.196.2.232) world (10.196.2.233)!!


如我们所料,返回了 `Hello (......) World (.....)`,这说明走的是生产环境。


那如何来请求预发布环境呢?我们需要做的就是发送给一个带有覆盖 header 的请求到生产环境中去,它就会访问到 `world-v2` 服务!由于 header 的设置,请求会走 `/srv/world-v2` 而不是`/host/world`。$ curl -H "Host: www.hello.world" -H "l5d-dtab: /host/world => /srv/world-v2;" $INGRESS_LB Hello (10.196.2.232) earth (10.196.2.234)!!我们看到了 "earch" 而不是 “world”! 这个请求已经成功的到达了 world-v2 服务,而且是在生产环境里,并且没有任何代码变更或者额外的部署工作。就是这样,预发布就变的 so easy 了。

Linkerd 的 Dtabs 和 routing 的文档非常健全。在开发中,你可以使用 linkerd 的 “dtab playground” http://$INGRESS_LB:9990/delegator。By going to the “outgoing” router and testing a request name like /http/1.1/GET/world, you can see linkerd’s routing policy in action.



实践
、在实践中,这种方式有一些需要注意的地方。首先,往生产环境的数据库里写东西时必须要小心。相同的 dtab 覆盖机制可以用来发送任何写预发布数据库的请求,或者在一些应用级别里直接 /dev/null。强烈建议,这些覆盖规则不能手动生成,以免发生不必要的错误,毕竟是在生产环境里!


其次,你的应用需要参考 linkerd's context headers。

最后非常重要的一点,避免外界可以设置 l5d-dtab 请求头。setting up a dogfood environment in Kubernetes 这篇文章里我们阐述了一个 nginx 的 ingress 样例配置,可以有效的去掉不认识的请求头。



结尾


我们举例了如何通过 linkerd 设置单个请求路由规则来达到创建临时预发布环境的问题。通过这种方式,我们可以在生产环境里预发布服务,而不需要更改现有代码,也不需要其他额外的预发布环境资源(当然除了预发布服务自己),同时也不需要处理预发布与生产这两个平行环境。对于微服务众多的应用来说,这种方式提供了一种发布到生产环境之前的简单、高效的预发布方式。


原文链接:https://buoyant.io/2017/01/06/a-service-mesh-for-kubernetes-part-vi-staging-microservices-without-the-tears/


推荐阅读:
 
4大维度3大预测,基于容器生态扩张的DevSecOps为啥引关注?
最佳实践 | 7大维度看国外企业为啥选择gRPC打造高性能微服务?
微服务迁移前,来听听这6个思考和经验 查看全部
作者:RISHA MARS

翻译:蔡悦

转自:容器时代(公众号 CaaSOne)

原文:A Service Mesh for Kubernetes, Part VI : Staging microservices without the tears



概述

在将新代码发布到生产环境之前, 预发布操作是构建一个可靠的、低宕机时间的软件系统的关键组成部分。但是,在微服务体系下,由于拆分出来的许许多多的微服务之间的依赖关系随着微服务数量成指数倍增长,从而增加了预发布操作的复杂性。在这篇文章里,我们将为您介绍 linkerd 的最强大的功能之一,单个请求路由(per-request routing),通过它,您将可以非常轻松的处理这个问题。


注意:这是关于 Linkerd、Kubernetes 和 Service Mesh 的系列文章其中一篇,其余部分包括:
  1. Top-line service metrics
  2. Pods are great, until they’re not
  3. Encrypting all the things
  4. Continuous deployment via traffic shifting
  5. Dogfood environments, ingress, and edge routing
  6. Staging microservices without the tears (本文)
  7. Distributed tracing made easy
  8. Linkerd as an ingress controller
  9. gRPC for fun and profit
  10. The Service Mesh API
  11. Egress
  12. Retry budgets, deadline propagation, and failing gracefully
  13. Autoscaling by top-line metrics



Linkerd 是云原生应用的一种服务网格(Service Mesh)。它作为对应用透明的网络代理层通过封装服务间的调用为应用提供如:低延迟负载均衡(latency-aware load balancing)、链接重试(retry budgets)及终止(deadlines)、熔断机制(circuit breaking)等特性来提高应用的适应性(application resilience)。


除了能够提高应用的适应性,Linkerd 也能够提供强大的路由语言来改变服务在运行时请求流的方式。这篇文章我们将为您展示 Linkerd 如何做到这一点,不仅仅是全局范围,更精细到每一个基础请求。也将为您展示每一个请求路由如何被用来创建临时的预发布环境,从而允许在生产环境上下文中测试新代码而不用真正将其发布到生产环境里。最后,将为您介绍(in contrast to staging with a dedicated staging environment)临时的预发布环境如何做到既不需要与其他团队的协调工作,也不需要花费时间精力来同时保持多个部署环境。


为什么要预发布

为什么预发布如此重要?在现代软件开发当中,代码需要经过一系列预先设计好的实践路线来保证正确性:代码走查(code review),单元测试(unit tests),集成测试(integration tests)等等。经过这些流程之后,需要开始估算代码的表现了:新代码运行的速度如何?高负载下的表现如何?在运行时与其他服务以及相关依赖的交互表现如何?


预发布系统就可以回答这些问题。预发布的基本原则就是越接近生产环境,系统就越切实可行。因此,就像测试环节中的 mocks 和 stub 一样,对于预发布,我们期望能够运行真实的服务。最好的预发布环境就是和生产环境完全一样。



为什么微服务的预发布很难
如果你的应用由许多微服务构成,那么微服务之间的通信交互就会变成像端到端应用行为一样的重要组成部分。其实,应用拆分的越细,那么在运行时应用之间的交互就会越复杂,而此时应用的表现已经不仅仅是每个微服务自己的问题了,很大程度上取决于微服务之间的交互。

实际上,增加微服务的数量不仅仅增加了正确预发布的重要性,也同时增加了实现这一点的难度。我们来看几个常用的预发布方法,以及为什么在微服务环境下这些方法都会变得比较困难。


预发布的常规方法是共享预发布集群,而在这个集群里,除了你的预发布服务之外其他人的预发布服务也在这里。这种方式的弊端就是没有隔离。如下图展示,如果 Alex 把他的服务发布了上去但是出了点问题,整个链条中就很难判断出问题源的所在--因为问题可能出现在 Alex、Alice 或者 Bob 的服务上,又或者干脆就是数据库里的数据有问题。这样预发布环境与生产环境的同步就会非常困难,尤其是当服务、团队以及发行版本数量庞大的时候。


另一种共享环境称为“私人”或者单个开发者的预发布集群,可以解决隔离的问题。在这个例子中,每一个开发者可以根据需要来操作预发布集群。预发布一个服务需要同时预发布这个服务的上游以及下游服务也包括相关的依赖,从而可以保证预发布的有效性。(比如,在下图中,Alex 必须先发布 Web FE 和 API 服务来保证他的 Foo 服务可以正常运行。)然而,根据需要来维护以及部署部分应用拓扑结构会非常复杂,尤其是当应用拓扑结构非常大而且服务又有独立的部署模型。

上面说的是一种极其简单的部署新代码到生产环境并且有问题时可以回滚的方式。当然了,这种方式很有风险,而且不能处理部分应用类型,比如:金融事务。虽然还有很多其他的部署方法,但是本文我们将介绍一种直接的、轻松的方式。


一种更好的方式

使用 Linkerd 创建临时的预发布环境,就可以很好的避免以上提到的弊端。实际上,在 Twitter 里 Finagle 路由层作为linkerd 的底层,  他的主要动机就是解决这个问题。

我们来看一下 Alex 的 Foo 服务。如果,我们不另外部署一个隔离的环境,而是仅仅使用 Foo 的预发布版本替代 Foo 的生产版本,然后通过一个特殊的请求来访问它呢?针对生产环境,这将能够确保 Foo 的预发布版本的安全性,而且除了 Foo 预发布版本之外也不需要部署其他的任何东西。这就是临时预发布环境的本质。而此时,开发者身上的任务一下就轻松了:Alex 只需要预发布他的新代码,然后在 ingress 请求的 header 上设置一个标记就可以了,就这么简单!

Linkered 的单个请求路由可以帮助我们实现这种方式。通过 linkerd 的请求代理,可以给特定的请求上设置一个 l5d-dtab 的 header 。这个 header 可以允许你设置路由规则(叫做  in Finagle parlance, Dtabs)。比如,dtab 规则 /s/foo => /srv/alex-foo 可以覆盖 Foo 服务生产环境的规则。给单个请求添加这个可以使得请求直接到达 Alex 的 Foo 服务,也仅仅作用与这一个请求。Linkerd 可以拦截这个规则,所以生产环境里任何使用 Alex 的 Foo 服务的地方都可以正确的处理。



试一下这个功能吧

Service Mesh for Kubernetes 系列文章的读者应该已经知道我们有一个 demo our dogfood blog post。我们部署过一个 world-v2 服务,并且可以通过设置重定向路由规则发送单个的 dogfood 请求。现在我们可以使用相同机制来做些别的事情:创建一个临时的预发布环境。

部署一个服务的两个版本,再使用 linkerd 的路由功能在部署到生产环境之前来测试新服务。我们先部署 hello 和 world-v1 服务来作为我们的生产环境服务,然后再创建一个临时的预发布环境来测试 world 服务的新版本 world-v2。


1部署LINKERD和HELLO-WORLD服务


我们使用前一篇文章里部署的 hello world 服务。它由 hello 服务调用 world 服务组成。这些应用通过 Kubernetes downward API 提供的根据 nodeName 来找到 Linkerd 。如果你不确定你的集群是否支持 nodeName, 你可以运行如下命令:kubectl apply -f https://raw.githubusercontent. ... t.yml


然后查看一下日志:kubectl logs node-name-test


如果你看到了 ip 就表示成功了。然后再通过如下命令部署 hello world 应用:kubectl apply -f https://raw.githubusercontent. ... d.yml


如果你看到了 “server can’t find …” 错误,那就部署 hello-world 的 legacy 版本,这个版本依赖 hostIP 而不是 nodeName:kubectl apply -f https://raw.githubusercontent. ... y.yml


然后我们来部署生产环境(linkerd 和 hellow 以及 world 服务):$ kubectl apply -f https://raw.githubusercontent. ... s.yml


再来部署 linkerd 和预发布版本的服务 world-v2 ,这个服务会返回 "earth" 而不是 “world”。$ kubectl apply -f https://raw.githubusercontent. ... s.yml $ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/world-v2.yml 
 

2在临时预发布环境里使用单个请求覆盖

现在,我们运行了 world-v2 服务,来测试一下是否通了。我们期望的是请求到达的是 `world-v2` 而不是 `world-v1`。首先,先运行一个没有更改的请求,这个请求会走默认的路径。(你可能需要等待 l5d 的 external IP 出现):$ INGRESS_LB=$(kubectl get svc l5d -o jsonpath="{.status.loadBalancer.ingress[0].*}") $ curl -H "Host: www.hello.world" $INGRESS_LB Hello (10.196.2.232) world (10.196.2.233)!!


如果外部负载均衡不起作用,可以使用 hostIP:INGRESS_LB=$(kubectl get po -l app=l5d -o jsonpath="{.items[0].status.hostIP}"):$(kubectl get svc l5d -o 'jsonpath={.spec.ports[0].nodePort}') $ curl -H "Host: www.hello.world" $INGRESS_LB Hello (10.196.2.232) world (10.196.2.233)!!


如我们所料,返回了 `Hello (......) World (.....)`,这说明走的是生产环境。


那如何来请求预发布环境呢?我们需要做的就是发送给一个带有覆盖 header 的请求到生产环境中去,它就会访问到 `world-v2` 服务!由于 header 的设置,请求会走 `/srv/world-v2` 而不是`/host/world`。$ curl -H "Host: www.hello.world" -H "l5d-dtab: /host/world => /srv/world-v2;" $INGRESS_LB Hello (10.196.2.232) earth (10.196.2.234)!!我们看到了 "earch" 而不是 “world”! 这个请求已经成功的到达了 world-v2 服务,而且是在生产环境里,并且没有任何代码变更或者额外的部署工作。就是这样,预发布就变的 so easy 了。

Linkerd 的 Dtabs 和 routing 的文档非常健全。在开发中,你可以使用 linkerd 的 “dtab playground” http://$INGRESS_LB:9990/delegator。By going to the “outgoing” router and testing a request name like /http/1.1/GET/world, you can see linkerd’s routing policy in action.



实践
、在实践中,这种方式有一些需要注意的地方。首先,往生产环境的数据库里写东西时必须要小心。相同的 dtab 覆盖机制可以用来发送任何写预发布数据库的请求,或者在一些应用级别里直接 /dev/null。强烈建议,这些覆盖规则不能手动生成,以免发生不必要的错误,毕竟是在生产环境里!


其次,你的应用需要参考 linkerd's context headers。

最后非常重要的一点,避免外界可以设置 l5d-dtab 请求头。setting up a dogfood environment in Kubernetes 这篇文章里我们阐述了一个 nginx 的 ingress 样例配置,可以有效的去掉不认识的请求头。



结尾


我们举例了如何通过 linkerd 设置单个请求路由规则来达到创建临时预发布环境的问题。通过这种方式,我们可以在生产环境里预发布服务,而不需要更改现有代码,也不需要其他额外的预发布环境资源(当然除了预发布服务自己),同时也不需要处理预发布与生产这两个平行环境。对于微服务众多的应用来说,这种方式提供了一种发布到生产环境之前的简单、高效的预发布方式。


原文链接:https://buoyant.io/2017/01/06/a-service-mesh-for-kubernetes-part-vi-staging-microservices-without-the-tears/


推荐阅读:
 
4大维度3大预测,基于容器生态扩张的DevSecOps为啥引关注?
最佳实践 | 7大维度看国外企业为啥选择gRPC打造高性能微服务?
微服务迁移前,来听听这6个思考和经验

实测 | 转型微服务,这4大工具谁是API网关性能最优?

小数 发表了文章 • 2 个评论 • 296 次浏览 • 2018-02-08 10:44 • 来自相关话题

 
 作者:Turgay Çelik

翻译:钟毅(Drew Zhong)

原文:Comparing API Gateway Performances: NGINX vs. ZUUL vs. Spring Cloud Gateway vs. Linkerd

不管是从团队人数,还是从公司产品的特性的角度来看,我们 OpsGenie 都处于快速成长的过程中。举例来说,仅就去年一年,我们的工程师团队人数由15人增长到50人。同时我们遵从了 Two Pizza team rule ,将工程师团队每8人分成一组,以更好地适应团队总人数的迅速增长。


你可能也猜到,目前 OpsGenie 的产品已经有点类似巨石应用了。由于多个团队共同开发维护同一个产品 以及 CI/CD ( Continuous Integration/Continuous Delivery ) 流程等原因,产品的开发和维护已经变得极具挑战。因此,我们不得不紧随当下的趋势,将巨石应用向分布式架构转变。读者可以从 Martin Fowler 的文章中,了解更多关于微服务架构和它的优点。


在对微服务概念的实践中,有一些值得推荐的架构模式。而 API 网关就是这些模式中的一个。简单来说,API 网关就是所有客户端的统一入口。它通过两种方式来处理客户端请求:一是作为代理,将请求路由给某一个特定的服务;二是将请求分散给多个服务。 API 网关是微服务框架的一个很好的开端,因为一个巨石应用微服务化后能够得到多个不同的服务,而API 网关能将特定的请求路由给特定的服务。


实际上,API 网关对我们来说并不是一个新的概念。我们用 Nginx 来作为我们巨石应用的 API 网关已经很长一段时间了,但是既然我们已经打算向微服务转型,那我们就不得不重新评估 Nginx 是不是一个好的选择。性能、可扩展性以及像限流等其它特性,都是我们需要考虑的。当然网关的性能,尤其是在高并发场景下能否满足我们的需求,才是我们最在意的。


在本篇博文中,我们将阐述如何搭建我们的测试环境,并比较 Zuul 1、Nginx、Spring Cloud Gateway 和 Linkerd。事实上,我们还有像 Lyft 的 Envoy 和 UnderTow 等其它备用方案。我们会对这些工具进行同样的测试,然后在以后的博文中再分享结果。


Zuul 1 对我们团队而言是一个不错的选择。因为它是由 Java 开发的,而且也完美兼容 Spring 框架。目前,已经有一些博客是进行 Zuul 和 Nginx 的比较的。但我们同时也想要比较 Spring Cloud 网关和 Linkerd,另外,我们也希望进行更一步的压力测试。所以,我们决定搭建我们自己的环境来进行测试。


为了客观地评估各个 API 网关自身的性能,我们创建了一个独立于 OpsGenie 产品之外的 隔离的测试环境。我们使用 Apache Http Server Benchmarking tool — ab 来搭建我们的测试环境。


首先,我们根据 Nginx 的官方文档,在 AWS EC2 t2.micro 实例上部署 Nginx 。这是我们的初始测试环境。然后我们在这个环境之上,又部署了 Zuul 和 Spring Cloud Gateway。Nginx web 服务器中放置了一些静态资源,然后我们分别在 Nginx、Zuul 和 Spring Cloud Gateway 上定义一些指向 web 服务器的反向代理。然后我们将另一个 t2.micro EC2 作为客户端,来发起一些请求。









图中带箭头的虚线就是我们测试用的路径。主要有以下五种方式:

· 直连

· 通过 Nginx 反向代理请求

· 通过 Zuul 请求

· 通过 Spring Cloud Gateway 请求

· 通过 Linkerd 请求


鉴于读者往往更关心结果,所以接下来我们会先给出测试结果,然后再进行详细的解释。


Benchmark性能总数



测试策略

我们使用 Apache 的 HTTP 服务器 Benchmark 工具。每一轮,我们用200个线进行10000次请求。


ab -n 10000 -c 200 HTTP://<server-address>/<path to resource>

我们在三种不同配置的 AWS EC2 上进行测试。为了更好地说明真实的请求, 我们对每一轮测试都进行了细分:

· 为了了解代理本身所需要的开销,我们首先对直连方式进行了额外的单独测试。但介于直连并不是我们的待选方案,因此后面的几轮就不再对直连进行测试。


· 介于 Spring Cloud Gateway 至今还没有正式发版,因此我们只会在最后一轮对它进行测试。


· Zuul 在调用过一次之后的性能表现会更好。我们认为这是 JIT 优化 (Just In Time) 的效果。所以我们形象地将 Zuul 的第一次运行称作是“热身”。当然,下面各个表中的数值都是 Zuul“热身”之后的性能。


· 我们都知道,Linkerd 是一种很吃资源的代理方式,因此我们就只在最后一轮,即性能配置最佳的方案中才会进行对它的比较。



测试用配置

T2.Micro --单核、1g内存:我们在这个配置上进行直连、Nginx 反向代理和 Zuul (热身后)三种代理方式的测试 M4.Large --双核、8g内存:我们在这个配置上进行 Nginx 反向代理和 Zuul (热身后)两种代理方式的测试 M4.2xLarge --八核、32g内存:我们在这个配置上进行 Nginx 反向代理、Zuul(热身后)、Spring Cloud Gateway 和 Linkerd 四种代理方式的测试



测试结果

以下是性能测试结果的概要:













测试的细节


直连

首先,我们在不使用任何代理的情况下直接访问静态资源。结果如下图所示。每次请求所需要的响应时间是30ms。 









通过 Nginx 反向代理连接


在第二次测试中,我们通过Nginx反向代理访问资源。每次请求的响应时间为40ms。我们发现,和上一部分不使用任何代理的直连方式相比,Nginx反向代理平均增加了33%的耗时。 








通过 Zuul 反向代理的连接

首先,我们创建了一个如下 Spring Boot 应用程序:







以下是我们的 application.yml 配置文件 







Zuul“热身”测试的结果如下: 






直连和通过 Nginx 反向代理的方式分别耗时30ms和40ms。在 Zuul 的首轮测试中,每一次请求响应耗时为388ms。正如其它博客中提到的那样,JVM 热身会有所帮助。我们又重新对 Zuul 进行一轮测试,结果如下: 

Zuul在“热身”之后的性能确实有所提高,每一次请求的响应时间下降到了200ms,但是和 Nginx 反向代理平均40ms的耗时相比,还是有比较大的差距的。


将服务器升级到m4.large

正如图一所示,t2.micro ec2 仅仅是单核 1G 内存。Nginx 是 c++ 程序而 Zuul 是 Java 语言实现的。众所周知,Java 应用程序对性能的要求会更高一些。因此我们使用 m4.large 服务器(双核,8G)来进行测试。 我们再一次对 Nginx 和 Zuul 两种反向代理方式分别进行测试,结果如下: 












正如以上两幅图所示,Nginx 和 Zuul 的请求响应时间分别是32ms和95ms。结果要远好于在 t2.micro 服务器进行测试时的结果。 当然,以上测试还有一个明显值得争议的问题:我们是通过 Spring Boot 应用程序来使用 Zuu l的,这自然会带来额外的性能消耗。如果我们单独对 Zuul 来进行测试,那么测试的性能结果可能还会更好。




将服务器升级到m4.2xlarge?

我们也在 m4.2xlarge 的机器(8核,32G内存)上进行了测试,Nginx 和 Zuul 的结果分别如下: 













在 m4.2xlarge 的机器上,Zuul 的性能要好于 Nginx。我们想要知道 Netflix 公司是使用的哪一种 EC2 来运行 Zuul 实例的,但是却找不到对应的答案。在其它的一些博文中会有人抱怨 Zuul 的性能,然后也在询问 Netflix 公司扩展它的方式,我们觉得这次的测试结果就是答案:Zuul 的性能受限于 CPU,所以必须加 CPU。


Linkerd的测试

Linkerd 是一个云原生计算基金会的项目。它是一个 Scala 语言实现的 Service Mesh / 服务网格 应用程序,提供如服务发现等能力,但它同时也提供了反向代理的能力。我们测试了 Linkerd 的性能,结果如下图所示。Linkerd 的性能非常接近 Zuul。 







Spring Cloud Gateway的测试

Spring Cloud 社区也在开发一个网关组件。虽然官方还没有正式发布这款组件,但我们认为还是需要将它和其他的可选组件一同来进行比较。因此,我们根据我们的测试环境修改了 Spring Cloud Gateway 应用程序的范例。 我们对它进行了同样的性能测试,通过 Apache Http 服务器性能测试工具,用200个并发线程进行10000次请求。结果如下: 此处输入链接的描述 如图所示,Spring Cloud Gateway 每秒处理873个请求,每个请求的响应时间是229ms。从我们测试的结果看来,Spring Cloud Gateway 并达不到 Zuul、Linkerd 和 Nginx 的水平,至少从它们当前各自 Github 上的代码是可以得到这样子的结论的。


接下来的工作

在本篇博客中,我们用Apache Http服务器性能测试工具对Zuul、Nginx、Linkerd和Spring Cloud Gateway进行了测试。以下是我们接下来的一些计划:

我们准备对 Envoy 进行评估。实际上 Envoy 不仅仅是一个 API 网关,它同时也是 Service Mesh/服务网格应用。

Undertow 也提供了反向代理的能力,也是我们接下来需要评估的。

Netflix 重新设计了 Zuul,将它设计成基于 Netty 的非阻塞应用。这个新版本叫作 "Zuul 2".我们准备在其开源版本正式发布后对其进行性能测试,然后再分享这一新 Zuul 的测试结果。

Spring Cloud Gateway 尚未开发完成,它是一个 Java 语言的基于 Netty 的非阻塞网关,因此它对于我们来说也是一个不错的选择。我们同样会对其官网版本进行性能测试。

API 网关中,一些是阻塞的,比如 Nginx 和 Zuul 1,另外一些是非阻塞的,比如 Zuul 2、Linkerd、Envoy。阻塞架构的好处在于开发简单,易于请求的追踪,但同时也会导致扩展方面的问题。非阻塞架构在开发和追踪方面会复杂一些,但是它的扩展能力和弹性伸缩能力要更加出色。因此我们加下来也会对这两种架构方案做出选择我们也会对 Gatling 进行一些测试,并在下一篇博客中分享测试结果。


我们会在接下来的每一篇博文中都对我们所取得的进展和发现进行分享,敬请期待。
 
 
推荐阅读:
 
4大维度3大预测,基于容器生态扩张的DevSecOps为啥引关注?
4大维度3大预测,基于容器生态扩张的DevSecOps为啥引关注?
微服务迁移前,来听听这6个思考和经验
  查看全部

0_DJgZyCP0LbCsyuhA_.png

 
 作者:Turgay Çelik

翻译:钟毅(Drew Zhong)

原文:Comparing API Gateway Performances: NGINX vs. ZUUL vs. Spring Cloud Gateway vs. Linkerd

不管是从团队人数,还是从公司产品的特性的角度来看,我们 OpsGenie 都处于快速成长的过程中。举例来说,仅就去年一年,我们的工程师团队人数由15人增长到50人。同时我们遵从了 Two Pizza team rule ,将工程师团队每8人分成一组,以更好地适应团队总人数的迅速增长。


你可能也猜到,目前 OpsGenie 的产品已经有点类似巨石应用了。由于多个团队共同开发维护同一个产品 以及 CI/CD ( Continuous Integration/Continuous Delivery ) 流程等原因,产品的开发和维护已经变得极具挑战。因此,我们不得不紧随当下的趋势,将巨石应用向分布式架构转变。读者可以从 Martin Fowler 的文章中,了解更多关于微服务架构和它的优点。


在对微服务概念的实践中,有一些值得推荐的架构模式。而 API 网关就是这些模式中的一个。简单来说,API 网关就是所有客户端的统一入口。它通过两种方式来处理客户端请求:一是作为代理,将请求路由给某一个特定的服务;二是将请求分散给多个服务。 API 网关是微服务框架的一个很好的开端,因为一个巨石应用微服务化后能够得到多个不同的服务,而API 网关能将特定的请求路由给特定的服务。


实际上,API 网关对我们来说并不是一个新的概念。我们用 Nginx 来作为我们巨石应用的 API 网关已经很长一段时间了,但是既然我们已经打算向微服务转型,那我们就不得不重新评估 Nginx 是不是一个好的选择。性能、可扩展性以及像限流等其它特性,都是我们需要考虑的。当然网关的性能,尤其是在高并发场景下能否满足我们的需求,才是我们最在意的。


在本篇博文中,我们将阐述如何搭建我们的测试环境,并比较 Zuul 1、Nginx、Spring Cloud Gateway 和 Linkerd。事实上,我们还有像 Lyft 的 Envoy 和 UnderTow 等其它备用方案。我们会对这些工具进行同样的测试,然后在以后的博文中再分享结果。


Zuul 1 对我们团队而言是一个不错的选择。因为它是由 Java 开发的,而且也完美兼容 Spring 框架。目前,已经有一些博客是进行 Zuul 和 Nginx 的比较的。但我们同时也想要比较 Spring Cloud 网关和 Linkerd,另外,我们也希望进行更一步的压力测试。所以,我们决定搭建我们自己的环境来进行测试。


为了客观地评估各个 API 网关自身的性能,我们创建了一个独立于 OpsGenie 产品之外的 隔离的测试环境。我们使用 Apache Http Server Benchmarking tool — ab 来搭建我们的测试环境。


首先,我们根据 Nginx 的官方文档,在 AWS EC2 t2.micro 实例上部署 Nginx 。这是我们的初始测试环境。然后我们在这个环境之上,又部署了 Zuul 和 Spring Cloud Gateway。Nginx web 服务器中放置了一些静态资源,然后我们分别在 Nginx、Zuul 和 Spring Cloud Gateway 上定义一些指向 web 服务器的反向代理。然后我们将另一个 t2.micro EC2 作为客户端,来发起一些请求。


图片1.png




图中带箭头的虚线就是我们测试用的路径。主要有以下五种方式:

· 直连

· 通过 Nginx 反向代理请求

· 通过 Zuul 请求

· 通过 Spring Cloud Gateway 请求

· 通过 Linkerd 请求



鉴于读者往往更关心结果,所以接下来我们会先给出测试结果,然后再进行详细的解释。


Benchmark性能总数



测试策略

我们使用 Apache 的 HTTP 服务器 Benchmark 工具。每一轮,我们用200个线进行10000次请求。


ab -n 10000 -c 200 HTTP://<server-address>/<path to resource>

我们在三种不同配置的 AWS EC2 上进行测试。为了更好地说明真实的请求, 我们对每一轮测试都进行了细分:

· 为了了解代理本身所需要的开销,我们首先对直连方式进行了额外的单独测试。但介于直连并不是我们的待选方案,因此后面的几轮就不再对直连进行测试。


· 介于 Spring Cloud Gateway 至今还没有正式发版,因此我们只会在最后一轮对它进行测试。


· Zuul 在调用过一次之后的性能表现会更好。我们认为这是 JIT 优化 (Just In Time) 的效果。所以我们形象地将 Zuul 的第一次运行称作是“热身”。当然,下面各个表中的数值都是 Zuul“热身”之后的性能。


· 我们都知道,Linkerd 是一种很吃资源的代理方式,因此我们就只在最后一轮,即性能配置最佳的方案中才会进行对它的比较。



测试用配置

T2.Micro --单核、1g内存:我们在这个配置上进行直连、Nginx 反向代理和 Zuul (热身后)三种代理方式的测试 M4.Large --双核、8g内存:我们在这个配置上进行 Nginx 反向代理和 Zuul (热身后)两种代理方式的测试 M4.2xLarge --八核、32g内存:我们在这个配置上进行 Nginx 反向代理、Zuul(热身后)、Spring Cloud Gateway 和 Linkerd 四种代理方式的测试



测试结果

以下是性能测试结果的概要:

图片2.png


图片3.png




测试的细节


直连

首先,我们在不使用任何代理的情况下直接访问静态资源。结果如下图所示。每次请求所需要的响应时间是30ms。 


图片4.png




通过 Nginx 反向代理连接


在第二次测试中,我们通过Nginx反向代理访问资源。每次请求的响应时间为40ms。我们发现,和上一部分不使用任何代理的直连方式相比,Nginx反向代理平均增加了33%的耗时。 


图片5.png



通过 Zuul 反向代理的连接

首先,我们创建了一个如下 Spring Boot 应用程序:

图片6.png



以下是我们的 application.yml 配置文件 

图片7.png



Zuul“热身”测试的结果如下: 

图片8.png


直连和通过 Nginx 反向代理的方式分别耗时30ms和40ms。在 Zuul 的首轮测试中,每一次请求响应耗时为388ms。正如其它博客中提到的那样,JVM 热身会有所帮助。我们又重新对 Zuul 进行一轮测试,结果如下: 

Zuul在“热身”之后的性能确实有所提高,每一次请求的响应时间下降到了200ms,但是和 Nginx 反向代理平均40ms的耗时相比,还是有比较大的差距的。


将服务器升级到m4.large

正如图一所示,t2.micro ec2 仅仅是单核 1G 内存。Nginx 是 c++ 程序而 Zuul 是 Java 语言实现的。众所周知,Java 应用程序对性能的要求会更高一些。因此我们使用 m4.large 服务器(双核,8G)来进行测试。 我们再一次对 Nginx 和 Zuul 两种反向代理方式分别进行测试,结果如下: 

图片9.png


图片10.png



正如以上两幅图所示,Nginx 和 Zuul 的请求响应时间分别是32ms和95ms。结果要远好于在 t2.micro 服务器进行测试时的结果。 当然,以上测试还有一个明显值得争议的问题:我们是通过 Spring Boot 应用程序来使用 Zuu l的,这自然会带来额外的性能消耗。如果我们单独对 Zuul 来进行测试,那么测试的性能结果可能还会更好。




将服务器升级到m4.2xlarge?

我们也在 m4.2xlarge 的机器(8核,32G内存)上进行了测试,Nginx 和 Zuul 的结果分别如下: 


图片11.png


图片12.png



在 m4.2xlarge 的机器上,Zuul 的性能要好于 Nginx。我们想要知道 Netflix 公司是使用的哪一种 EC2 来运行 Zuul 实例的,但是却找不到对应的答案。在其它的一些博文中会有人抱怨 Zuul 的性能,然后也在询问 Netflix 公司扩展它的方式,我们觉得这次的测试结果就是答案:Zuul 的性能受限于 CPU,所以必须加 CPU。


Linkerd的测试

Linkerd 是一个云原生计算基金会的项目。它是一个 Scala 语言实现的 Service Mesh / 服务网格 应用程序,提供如服务发现等能力,但它同时也提供了反向代理的能力。我们测试了 Linkerd 的性能,结果如下图所示。Linkerd 的性能非常接近 Zuul。 

图片13.png



Spring Cloud Gateway的测试

Spring Cloud 社区也在开发一个网关组件。虽然官方还没有正式发布这款组件,但我们认为还是需要将它和其他的可选组件一同来进行比较。因此,我们根据我们的测试环境修改了 Spring Cloud Gateway 应用程序的范例。 我们对它进行了同样的性能测试,通过 Apache Http 服务器性能测试工具,用200个并发线程进行10000次请求。结果如下: 此处输入链接的描述 如图所示,Spring Cloud Gateway 每秒处理873个请求,每个请求的响应时间是229ms。从我们测试的结果看来,Spring Cloud Gateway 并达不到 Zuul、Linkerd 和 Nginx 的水平,至少从它们当前各自 Github 上的代码是可以得到这样子的结论的。


接下来的工作

在本篇博客中,我们用Apache Http服务器性能测试工具对Zuul、Nginx、Linkerd和Spring Cloud Gateway进行了测试。以下是我们接下来的一些计划:

我们准备对 Envoy 进行评估。实际上 Envoy 不仅仅是一个 API 网关,它同时也是 Service Mesh/服务网格应用。

Undertow 也提供了反向代理的能力,也是我们接下来需要评估的。

Netflix 重新设计了 Zuul,将它设计成基于 Netty 的非阻塞应用。这个新版本叫作 "Zuul 2".我们准备在其开源版本正式发布后对其进行性能测试,然后再分享这一新 Zuul 的测试结果。

Spring Cloud Gateway 尚未开发完成,它是一个 Java 语言的基于 Netty 的非阻塞网关,因此它对于我们来说也是一个不错的选择。我们同样会对其官网版本进行性能测试。

API 网关中,一些是阻塞的,比如 Nginx 和 Zuul 1,另外一些是非阻塞的,比如 Zuul 2、Linkerd、Envoy。阻塞架构的好处在于开发简单,易于请求的追踪,但同时也会导致扩展方面的问题。非阻塞架构在开发和追踪方面会复杂一些,但是它的扩展能力和弹性伸缩能力要更加出色。因此我们加下来也会对这两种架构方案做出选择我们也会对 Gatling 进行一些测试,并在下一篇博客中分享测试结果。


我们会在接下来的每一篇博文中都对我们所取得的进展和发现进行分享,敬请期待。
 
 
推荐阅读:
 
4大维度3大预测,基于容器生态扩张的DevSecOps为啥引关注?
4大维度3大预测,基于容器生态扩张的DevSecOps为啥引关注?
微服务迁移前,来听听这6个思考和经验
 

专题 | A Service Mesh for Kubernetes第3期:DogFood环境,Ingress和Edge路由

小数 发表了文章 • 0 个评论 • 126 次浏览 • 2018-01-22 15:15 • 来自相关话题

 概述

在这篇文章中,我们将向您展示如何使用Linkerd实现的Service Mesh来处理Kubernetes上的入口流量,在Service Mesh中的每个实例上分发流量。我们还将通过一个完整的例子来介绍Linkerd的高级路由功能:如何将特定的请求路由到较新版本的应用实例上,比如用于内部测试的、预发布的应用版本。

这篇文章是关于使用Linkerd作为到Kubernetes网络流量的入口点。 从0.9.1开始,Linkerd直接支持Kubernetes的Ingress资源,这对于本文中的一些用例来说是一个可替代的,也是更简单的起点。

注意: 这是关于Linkerd、Kubernetes和service mesh的系列文章其中一篇,其余部分包括:

1.Top-line service metrics
2.Pods are great, until they’re not
3.Encrypting all the things
4.Continuous deployment via traffic shifting
5.Dogfood environments, ingress, and edge routing(本文)
6.Staging microservices without the tears
7.Distributed tracing made easy
8.Linkerd as an ingress controller
9.gRPC for fun and profit
10.The Service Mesh API
11.Egress
12.Retry budgets, deadline propagation, and failing gracefully
13.Autoscaling by top-line metrics

在本系列的前几个部分,我们向您展示了如何使用Linkerd来捕获top-line的服务指标,在服务中透明地添加TLS以及执行蓝绿发布。这些文章展示了如Kubernetes这样的环境中如何使用Linkerd作为Service Mesh的组件,为内部服务到服务调用中添加了一层弹性和性能的保障,在本篇文章中,我们将这个模型扩展到入口路由。

虽然这篇文章以Kubernetes为例,但我们不会使用Kubernetes内置的Ingress资源对象。虽然Ingress提供了一种便捷的基于宿主机和基本路径的路由方法,但在本文撰写时,Kubernetes Ingress的功能是相当有限的。在下面的例子中,我们将远远超出Ingress提供的范围。



1、发布Linkerd Service Mesh

从以前文章中基本的Linkerd Service Mesh配置开始,我们进行两个更改来支持Ingress:我们将修改Linkerd的配置用以添加一个额外的逻辑路由器,我们在Kubernetes Service资源对象中调整VIP在Linkerd中的范围。

在Linkerd的实例提供了一个新的逻辑路由器,用于处理入口流量并将其路由到相应的服务:
yaml routers: - protocol: http  label: ingress  dtab: |    /srv                    => /#/io.l5d.k8s/default/http ;    /domain/world/hello/www => /srv/hello ;    /domain/world/hello/api => /srv/api ;    /host                  => /$/io.buoyant.http.domainToPathPfx/domain ;    /svc                    => /host ;  interpreter:    kind: default    transformers:    - kind: io.l5d.k8s.daemonset      namespace: default      port: incoming      service: l5d  servers:  - port: 4142    ip: 0.0.0.0在这个配置中,我们使用Linkerd的路由语法,dtabs将请求从域名传递到服务——在这种情况下从api.hello.world传递到api服务,从www.hello.world到hello服务。为了简单起见,我们已经为每个域添加了一个规则,但是对于更复杂的设置,也可以轻松地生成映射规则。

我们已经将这个入口路由器添加到每个Linkerd实例中 - 以真正Service Mesh的方式,我们将在这些实例中完全分配入口流量,使得应用不存在单点故障。

我们还需要修改Kubernetes Service对象,以在端口80上用非入口VIP替换出口的VIP——这将允许我们直接将出口流量发送到Linkerd的Service Mesh中,主要是用于调试的目的,因为这个流量在到达Linkerd之前不会被审查(在下一步,我们将解决这个问题)。

对Kubernetes Service修改如下:
apiVersion: v1 kind: Service metadata:  name: l5d spec:  selector:    app: l5d  type: LoadBalancer  ports:  - name: ingress    port: 80    targetPort: 4142  - name: incoming    port: 4141  - name: admin    port: 9990
以上所有的修改都可以通过简单运行一个命令就能生效,细节请查看:
$ kubectl apply -f https://raw.githubusercontent. ... s.yml





2、部署服务

对于此例中的Service,我们将使用早先发布的博客使用到的例子hello and world configs,并且我们会添加两个新的service:一个api service,其用来调用hello和world,还有world service的新版本:world-v2,其将会返回一个“earth”而非“world”——我们扩大黑客团队已经向我们保证,他们的A/B测试显示这一变化将使参与度提高10倍。

下面的命令将会把hello world services部署在default命名空间下。这些应用依赖于Kubernetes downward API提供的节点名来发现Linkerd。为了检查你的集群是否支持节点名,你可以运行该测试任务:k
ubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/node-name-test.yml 
然后看它的日志信息:kubectl logs node-name-test如果你看到了IP,那就非常棒,接着使用如下命令部署hello world应用:$ kubectl apply -f https://raw.githubusercontent. ... d.yml $ kubectl apply -f https://raw.githubusercontent. ... i.yml $ kubectl apply -f https://raw.githubusercontent. ... 2.yml如果你看到的是“server can’t find…”这样的报错信息,请部署hello-world遗留版本,该版本依赖于hostIP而不是节点名:$ kubectl apply -f https://raw.githubusercontent. ... y.yml $ kubectl apply -f https://raw.githubusercontent. ... y.yml $ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/world-v2.yml 
 
这时我们应该能够通过入口Kubernetes VIP发送流量来测试设备,在没有使用DNS的情况下,我们将在请求中手动设置一个Host Header:
$ INGRESS_LB=$(kubectl get svc l5d -o jsonpath="{.status.loadBalancer.ingress[0].*}") $ curl -s -H "Host: www.hello.world" $INGRESS_LB Hello (10.0.5.7) world (10.0.4.7)!! $ curl -s -H "Host: api.hello.world" $INGRESS_LB {"api_result":"api (10.0.3.6) Hello (10.0.5.4) world (10.0.1.5)!!"}
或者如果集群不支持外部负载均衡器,请使用hostIP:$ INGRESS_LB=$(kubectl get po -l app=l5d -o jsonpath="{.items[0].status.hostIP}"):$(kubectl get svc l5d -o 'jsonpath={.spec.ports[0].nodePort}')成功了!
我们已经将Linkerd设置为入口控制器,并且我们已经使用它将不同域中收到的请求路由到不同的服务。正如您所见,生产流量正冲击world-v1服务——我们还没准备要将world-v2推出。



3、Nginx层

至此ingress已经可以使用了。但还不能用于生产环境中。因为我们的ingress路由器不能将header从请求中提取出来。这就意味着我们不能接收包含header的外部请求。例如,Linkerd允许设置15d-dtab头部以按请求应用路由规则,这对于新服务的临时分级是一个有用的功能,但这可能不适合于来自外部的请求。

例如,我们可以使用15d-dtab请求头覆盖路由逻辑来使用world-v2而不是world-v1来服务外部请求:$ curl -H "Host: www.hello.world" -H "l5d-dtab: /host/world => /srv/world-v2;" $INGRESS_LB Hello (10.100.4.3) earth (10.100.5.5)!!当earth作为响应,意味着这是world-v2服务的结果。

我们通过添加nginx来解决这个问题(或者其他问题如服务静态文件)。如果我们在代理请求到linkerd ingress路由之前配置nginx来提取输入的header,我们将会两全其美:有能力安全处理外部流量的ingress层并且Linkerd做动态的、基于服务的路由。

让我们添加nginx到集群中。使用this nginx conf来配置它。我们将在www.hello.world和api.hello.world虚拟服务器下使用proxy_pass命令来发送请求给Linkerd实例,并且我们将使用Headers More模块提供的more_clear_input_headers命令来提取linkerd's context headers。

对于linkerd 0.9.0,我们可以通过在ingress路由器服务器上设置clearContext:true来清除输入的15d-*请求头。然而,nginx有许多我们可以使用到的特性,所以使用nginx连接Linkerd很有价值。

我们已经发布了一个安装了Headers More模块的Docker镜像:buoyantio/nginx:1.11.5。
我们用该配置部署这个镜像:
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/nginx.yml 
 
在等待外部IP出现后,我们可以通过点击nginx.conf中的简单测试端点来测试nginx是否启动:$ INGRESS_LB=$(kubectl get svc nginx -o jsonpath="{.status.loadBalancer.ingress[0].*}") $ curl $INGRESS_LB 200 OK
或者如果集群的外部负载均衡器不可用,使用
hostIP:$ INGRESS_LB=$(kubectl get po -l app=nginx -o jsonpath="{.items[0].status.hostIP}"):$(kubectl get svc nginx -o 'jsonpath={.spec.ports[0].nodePort}')
 
我们现在应用已经可以通过nginx发送流量给我们的服务了:$ curl -s -H "Host: www.hello.world" $INGRESS_LB Hello (10.0.5.7) world (10.0.4.7)!! $ curl -s -H "Host: api.hello.world" $INGRESS_LB {"api_result":"api (10.0.3.6) Hello (10.0.5.4) world (10.0.1.5)!!"}
 
最后,让我们尝试直接与world-v2服务通信:$ curl -H "Host: www.hello.world" -H "l5d-dtab: /host/world => /srv/world-v2;" $INGRESS_LB Hello (10.196.1.8) world (10.196.2.13)!!没有earth,Nginx正在净化外部流量。



4、简述Dogfood

好了,到了重点部分:让我们使用world-v1服务来配置dogfood的环境,不过这仅针对一些流量。

为简化问题,我们只关注设置了特殊cookiespecial_employee_cookie的流量。在实践中,你可能想要比这更复杂的情况如验证它,要求它来自公司网络IP范围等。

用nginx和Linkerd安装,完成这个相当简单。我们将会使用nginx来检查该cookie是否存在,为linkerd设置一个dtab覆盖头来调整其路由。有关的nginx配置如下:
if ($cookie_special_employee_cookie ~* "dogfood") {  set $xheader "/host/world => /srv/world-v2;"; } proxy_set_header 'l5d-dtab' $xheader;
如果你已经按以上步骤做了,被部署的nginx已经包含了这个配置。我们可以用如下来进行测试:
$ curl -H "Host: www.hello.world" --cookie "special_employee_cookie=dogfood" $INGRESS_LB Hello (10.196.1.8) earth (10.196.2.13)!!
系统已经工作了。当这个cookie被设置了,你将置于dogfood模式下。如果没有它,你将置于常规生产流量模式。最重要的是,dogfood模式可以包含在service stack到处出现的service的新版本,甚至很多层——只要服务代码转发Linkerd的上下文头,Linkerd服务网格将负责其余部分。



结束语

在本文中,我们看到了如何使用Linkerd给Kubernetes集群提供有力而又灵活的入口。我们已经演示了如何部署名义上的生产就绪设置,使用Linkerd进行服务路由。我们已经演示了如何使用Linkerd的一些高级路由功能来将流量服务拓扑从部署拓扑结构中分离出来,从而允许创建dogfood环境而不需要单独的集群或部署时间复杂性。 查看全部
 概述

在这篇文章中,我们将向您展示如何使用Linkerd实现的Service Mesh来处理Kubernetes上的入口流量,在Service Mesh中的每个实例上分发流量。我们还将通过一个完整的例子来介绍Linkerd的高级路由功能:如何将特定的请求路由到较新版本的应用实例上,比如用于内部测试的、预发布的应用版本。

这篇文章是关于使用Linkerd作为到Kubernetes网络流量的入口点。 从0.9.1开始,Linkerd直接支持Kubernetes的Ingress资源,这对于本文中的一些用例来说是一个可替代的,也是更简单的起点。

注意: 这是关于Linkerd、Kubernetes和service mesh的系列文章其中一篇,其余部分包括:

1.Top-line service metrics
2.Pods are great, until they’re not
3.Encrypting all the things
4.Continuous deployment via traffic shifting
5.Dogfood environments, ingress, and edge routing(本文)
6.Staging microservices without the tears
7.Distributed tracing made easy
8.Linkerd as an ingress controller
9.gRPC for fun and profit
10.The Service Mesh API
11.Egress
12.Retry budgets, deadline propagation, and failing gracefully
13.Autoscaling by top-line metrics

在本系列的前几个部分,我们向您展示了如何使用Linkerd来捕获top-line的服务指标,在服务中透明地添加TLS以及执行蓝绿发布。这些文章展示了如Kubernetes这样的环境中如何使用Linkerd作为Service Mesh的组件,为内部服务到服务调用中添加了一层弹性和性能的保障,在本篇文章中,我们将这个模型扩展到入口路由。

虽然这篇文章以Kubernetes为例,但我们不会使用Kubernetes内置的Ingress资源对象。虽然Ingress提供了一种便捷的基于宿主机和基本路径的路由方法,但在本文撰写时,Kubernetes Ingress的功能是相当有限的。在下面的例子中,我们将远远超出Ingress提供的范围。



1、发布Linkerd Service Mesh

从以前文章中基本的Linkerd Service Mesh配置开始,我们进行两个更改来支持Ingress:我们将修改Linkerd的配置用以添加一个额外的逻辑路由器,我们在Kubernetes Service资源对象中调整VIP在Linkerd中的范围。

在Linkerd的实例提供了一个新的逻辑路由器,用于处理入口流量并将其路由到相应的服务:
yaml routers: - protocol: http  label: ingress  dtab: |    /srv                    => /#/io.l5d.k8s/default/http ;    /domain/world/hello/www => /srv/hello ;    /domain/world/hello/api => /srv/api ;    /host                  => /$/io.buoyant.http.domainToPathPfx/domain ;    /svc                    => /host ;  interpreter:    kind: default    transformers:    - kind: io.l5d.k8s.daemonset      namespace: default      port: incoming      service: l5d  servers:  - port: 4142    ip: 0.0.0.0在这个配置中,我们使用Linkerd的路由语法,dtabs将请求从域名传递到服务——在这种情况下从api.hello.world传递到api服务,从www.hello.world到hello服务。为了简单起见,我们已经为每个域添加了一个规则,但是对于更复杂的设置,也可以轻松地生成映射规则。

我们已经将这个入口路由器添加到每个Linkerd实例中 - 以真正Service Mesh的方式,我们将在这些实例中完全分配入口流量,使得应用不存在单点故障。

我们还需要修改Kubernetes Service对象,以在端口80上用非入口VIP替换出口的VIP——这将允许我们直接将出口流量发送到Linkerd的Service Mesh中,主要是用于调试的目的,因为这个流量在到达Linkerd之前不会被审查(在下一步,我们将解决这个问题)。

对Kubernetes Service修改如下:
apiVersion: v1 kind: Service metadata:  name: l5d spec:  selector:    app: l5d  type: LoadBalancer  ports:  - name: ingress    port: 80    targetPort: 4142  - name: incoming    port: 4141  - name: admin    port: 9990
以上所有的修改都可以通过简单运行一个命令就能生效,细节请查看:
$ kubectl apply -f https://raw.githubusercontent. ... s.yml





2、部署服务

对于此例中的Service,我们将使用早先发布的博客使用到的例子hello and world configs,并且我们会添加两个新的service:一个api service,其用来调用hello和world,还有world service的新版本:world-v2,其将会返回一个“earth”而非“world”——我们扩大黑客团队已经向我们保证,他们的A/B测试显示这一变化将使参与度提高10倍。

下面的命令将会把hello world services部署在default命名空间下。这些应用依赖于Kubernetes downward API提供的节点名来发现Linkerd。为了检查你的集群是否支持节点名,你可以运行该测试任务:k
ubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/node-name-test.yml 
然后看它的日志信息:kubectl logs node-name-test如果你看到了IP,那就非常棒,接着使用如下命令部署hello world应用:$ kubectl apply -f https://raw.githubusercontent. ... d.yml $ kubectl apply -f https://raw.githubusercontent. ... i.yml $ kubectl apply -f https://raw.githubusercontent. ... 2.yml如果你看到的是“server can’t find…”这样的报错信息,请部署hello-world遗留版本,该版本依赖于hostIP而不是节点名:$ kubectl apply -f https://raw.githubusercontent. ... y.yml $ kubectl apply -f https://raw.githubusercontent. ... y.yml $ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/world-v2.yml 
 
这时我们应该能够通过入口Kubernetes VIP发送流量来测试设备,在没有使用DNS的情况下,我们将在请求中手动设置一个Host Header:
$ INGRESS_LB=$(kubectl get svc l5d -o jsonpath="{.status.loadBalancer.ingress[0].*}") $ curl -s -H "Host: www.hello.world" $INGRESS_LB Hello (10.0.5.7) world (10.0.4.7)!! $ curl -s -H "Host: api.hello.world" $INGRESS_LB {"api_result":"api (10.0.3.6) Hello (10.0.5.4) world (10.0.1.5)!!"}
或者如果集群不支持外部负载均衡器,请使用hostIP:$ INGRESS_LB=$(kubectl get po -l app=l5d -o jsonpath="{.items[0].status.hostIP}"):$(kubectl get svc l5d -o 'jsonpath={.spec.ports[0].nodePort}')成功了!
我们已经将Linkerd设置为入口控制器,并且我们已经使用它将不同域中收到的请求路由到不同的服务。正如您所见,生产流量正冲击world-v1服务——我们还没准备要将world-v2推出。



3、Nginx层

至此ingress已经可以使用了。但还不能用于生产环境中。因为我们的ingress路由器不能将header从请求中提取出来。这就意味着我们不能接收包含header的外部请求。例如,Linkerd允许设置15d-dtab头部以按请求应用路由规则,这对于新服务的临时分级是一个有用的功能,但这可能不适合于来自外部的请求。

例如,我们可以使用15d-dtab请求头覆盖路由逻辑来使用world-v2而不是world-v1来服务外部请求:$ curl -H "Host: www.hello.world" -H "l5d-dtab: /host/world => /srv/world-v2;" $INGRESS_LB Hello (10.100.4.3) earth (10.100.5.5)!!当earth作为响应,意味着这是world-v2服务的结果。

我们通过添加nginx来解决这个问题(或者其他问题如服务静态文件)。如果我们在代理请求到linkerd ingress路由之前配置nginx来提取输入的header,我们将会两全其美:有能力安全处理外部流量的ingress层并且Linkerd做动态的、基于服务的路由。

让我们添加nginx到集群中。使用this nginx conf来配置它。我们将在www.hello.world和api.hello.world虚拟服务器下使用proxy_pass命令来发送请求给Linkerd实例,并且我们将使用Headers More模块提供的more_clear_input_headers命令来提取linkerd's context headers。

对于linkerd 0.9.0,我们可以通过在ingress路由器服务器上设置clearContext:true来清除输入的15d-*请求头。然而,nginx有许多我们可以使用到的特性,所以使用nginx连接Linkerd很有价值。

我们已经发布了一个安装了Headers More模块的Docker镜像:buoyantio/nginx:1.11.5。
我们用该配置部署这个镜像:
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/nginx.yml 
 
在等待外部IP出现后,我们可以通过点击nginx.conf中的简单测试端点来测试nginx是否启动:$ INGRESS_LB=$(kubectl get svc nginx -o jsonpath="{.status.loadBalancer.ingress[0].*}") $ curl $INGRESS_LB 200 OK
或者如果集群的外部负载均衡器不可用,使用
hostIP:$ INGRESS_LB=$(kubectl get po -l app=nginx -o jsonpath="{.items[0].status.hostIP}"):$(kubectl get svc nginx -o 'jsonpath={.spec.ports[0].nodePort}')
 
我们现在应用已经可以通过nginx发送流量给我们的服务了:$ curl -s -H "Host: www.hello.world" $INGRESS_LB Hello (10.0.5.7) world (10.0.4.7)!! $ curl -s -H "Host: api.hello.world" $INGRESS_LB {"api_result":"api (10.0.3.6) Hello (10.0.5.4) world (10.0.1.5)!!"}
 
最后,让我们尝试直接与world-v2服务通信:$ curl -H "Host: www.hello.world" -H "l5d-dtab: /host/world => /srv/world-v2;" $INGRESS_LB Hello (10.196.1.8) world (10.196.2.13)!!没有earth,Nginx正在净化外部流量。



4、简述Dogfood

好了,到了重点部分:让我们使用world-v1服务来配置dogfood的环境,不过这仅针对一些流量。

为简化问题,我们只关注设置了特殊cookiespecial_employee_cookie的流量。在实践中,你可能想要比这更复杂的情况如验证它,要求它来自公司网络IP范围等。

用nginx和Linkerd安装,完成这个相当简单。我们将会使用nginx来检查该cookie是否存在,为linkerd设置一个dtab覆盖头来调整其路由。有关的nginx配置如下:
if ($cookie_special_employee_cookie ~* "dogfood") {  set $xheader "/host/world => /srv/world-v2;"; } proxy_set_header 'l5d-dtab' $xheader;
如果你已经按以上步骤做了,被部署的nginx已经包含了这个配置。我们可以用如下来进行测试:
$ curl -H "Host: www.hello.world" --cookie "special_employee_cookie=dogfood" $INGRESS_LB Hello (10.196.1.8) earth (10.196.2.13)!!
系统已经工作了。当这个cookie被设置了,你将置于dogfood模式下。如果没有它,你将置于常规生产流量模式。最重要的是,dogfood模式可以包含在service stack到处出现的service的新版本,甚至很多层——只要服务代码转发Linkerd的上下文头,Linkerd服务网格将负责其余部分。



结束语

在本文中,我们看到了如何使用Linkerd给Kubernetes集群提供有力而又灵活的入口。我们已经演示了如何部署名义上的生产就绪设置,使用Linkerd进行服务路由。我们已经演示了如何使用Linkerd的一些高级路由功能来将流量服务拓扑从部署拓扑结构中分离出来,从而允许创建dogfood环境而不需要单独的集群或部署时间复杂性。

专题 | A Service Mesh for Kubernetes 第二期:K8S+Linkerd

小数 发表了文章 • 0 个评论 • 293 次浏览 • 2018-01-04 20:45 • 来自相关话题

 专题 | A Service Mesh for Kubernetes 第二期:K8S+Linkerd 查看全部

专题 | Kubernetes+Linkerd 第一期

小数 发表了文章 • 0 个评论 • 397 次浏览 • 2018-01-03 16:58 • 来自相关话题

作者:ALEX LEONG


翻译:平凡

转自:容器时代(CaaSOne)
 
Service Mesh,一个为云平台而设计的应用,云平台的本地应用该如何使用它?本文中,我们将讲述在Kubernetes中如何应用Linkerd作为Service Mesh,如何捕获和报告顶层服务指标如成功率、请求量和延迟,而不需要更改应用的代码。


注意:这是关于Linkerd、Kubernetes和Service Mesh的系列文章其中一篇,其余部分包括:
Top-line service metrics (本文)Pods are great, until they’re notEncrypting all the thingsContinuous deployment via traffic shiftingDogfood environments, ingress, and edge routingStaging microservices without the tearsDistributed tracing made easyLinkerd as an ingress controllergRPC for fun and profitThe Service Mesh APIEgressRetry budgets, deadline propagation, and failing gracefullyAutoscaling by top-line metrics



使用service mesh的必要性

关于Linkerd最常见的一个疑问就是,到底什么是Service Mesh?当Kubernetes已经提供了如Service资源对象、负载均衡这样的基本功能后,为什么Service Mesh要作为云本地应用程序的关键组件。


简单来说,Service Mesh这一层管理着应用之间的通信(或者部分应用之间的通信如微服务)。传统应用中,这个逻辑直接构建到应用程序本身中:重试和超时,监控/可见性,追踪,服务发现等等。这些都被硬编码到每个应用程序中。

然而,随着应用程序架构被越来越多的分割成服务,将通信逻辑从应用中移出到底层基础设施中变得越来越重要。就像是应用程序不应该写它自己的TCP栈,他们也不应该管理自己的负载均衡逻辑,或他们自己的服务发现管理程序,以及他们自己的重试和超时逻辑。

像Linkerd这样的Service Mesh为大规模多服务应用程序提供关键的部件:

基本的适应性功能:重试预算,deadline,熔断器模式

顶层的服务指标:成功率,请求量,延迟

延迟和失败容忍度:感应失败和延迟的负载均衡,它可以绕过缓慢的或者损坏的服务实例

分发追踪:如Zipkin和OpenTracing

服务发现:找到目标实例

协议升级:在TLS中包装跨网络通信,或将HTTP/1.1转换为HTTP/2.0

路由:不同版本的服务之间的路由请求,集群之间的故障转移等



在这部分中,我们仅重点关注可见性:Service Mesh是如何自动捕获并报告如成功率等顶层服务指标的,我们将展示一个Kubernetes的小例子以此来引导你。
 
在Kubernetes中使用Linkerd作为Service的检测器
 
在请求层进行操作的一个优势是Service Mesh可以访问成功和失败的协议级语义。举个例子,如果你正在运行一个HTTP服务,Linkerd可以理解200 、400、500响应的含义,从而可以自动计算如成功率这样的指标。

让我们通过一个小例子讲解如何在Kubernetes中安装Linkerd,从而自动的捕获顶层服务成功率而不需要更改应用程序。
 

安装Linkerd
使用Kubernetes配置文件安装Linkerd。它会将Linkerd作为DaemonSet安装,且运行在Kubernetes的default命名空间:
kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/linkerd.yml 
 
你可以通过查看Linkerd的管理页面确认是否安装成功:
INGRESS_LB=$(kubectl get svc l5d -o jsonpath="{.status.loadBalancer.ingress[0].*}") open http://$INGRESS_LB:9990 # on OS X
 
如果集群不支持外部负载均衡,使用hostIP:
HOST_IP=$(kubectl get po -l app=l5d -o jsonpath="{.items[0].status.hostIP}") open http://$HOST_IP:$(kubectl get svc l5d -o 'jsonpath={.spec.ports[2].nodePort}') # on OS X








安装样例应用程序
在default命名空间下安装两个Service,“hello”和“world”。这些应用程序依赖于Kubernetes downward API提供的nodeName来发现Linkerd。为了检测你的集群是否支持nodeName,你可以运行:
kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/node-name-test.yml 
 
然后看它的日志:kubectl logs node-name-test
 
如果你看到了一个IP就说明支持。接下来继续部署hello world应用程序如下:
kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world.yml 
 
如果你看到报错“server can’t find…”,就部署旧版本hello-world,它依赖于hostIP而非nodeName:kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world-legacy.yml 
 
这两个Service——“hello”和“world”——功能在一起使得高度可扩展,“hello world”微服务(“hello”Service调用“world”Service完成这个请求)。

你可以通过给Linkerd的外部IP发送请求来查看此操作:
http_proxy=$INGRESS_LB:4140 curl -s http://hello或者直接使用hostIP:http_proxy=$HOST_IP:$(kubectl get svc l5d -o 'jsonpath={.spec.ports[0].nodePort}') curl -s http://hello 
 
你应该可以看到字符串“Hello world”。
 

安装Linkerd-viz
最后,通过安装Linkerd-viz,让我们可以看看Service正在做什么。Linkerd-viz是一个附加包,它包括一个简单的Prometheus和Grafana设置,并可以自动发现Linkerd。
下面的命令会将Linkerd-viz安装到default命名空间下:
kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-viz/master/k8s/linkerd-viz.yml 
 
访问Linkerd-viz的外部IP查看dashboard:
VIZ_INGRESS_LB=$(kubectl get svc linkerd-viz -o jsonpath="{.status.loadBalancer.ingress[0].*}") open http://$VIZ_INGRESS_LB # on OS X
 
如果集群不支持外部负载均衡,使用hostIP:
VIZ_HOST_IP=$(kubectl get po -l name=linkerd-viz -o jsonpath="{.items[0].status.hostIP}") open http://$VIZ_HOST_IP:$(kubectl get svc linkerd-viz -o 'jsonpath={.spec.ports[0].nodePort}') # on OS X
 
你应该在dashboard上看到包括Service与实例的选择器,所有图表都反映了这些Service和实例的选择器。
 






Linkerd-viz的dashboard包括三部分:

顶层:集群范围的成功率与请求量

Service指标:每个已部署应用的指标,包括成功率、请求量和延迟

单个实例指标:集群上每一个node的成功率、请求量和延迟

用三个简单的命令我们就可以将Linkerd安装在集群上,安装应用,并且使用Linkerd了解应用程序Service的健康状况。当然,Linkerd提供的不仅仅是可见性,还提供了延迟感应负载均衡,自动重试和断路,分发追踪等功能。
 
 
 
第二部分:导言
 
在第一部分里我们提到了Linkerd是使用DaemonSet而非Sidecar来安装的。在第二部分中,我们将解释我们为什么(怎么样)这么做。

注意:这是关于Linkerd、Kubernetes和Service ,esh的系列文章其中一篇,其余部分包括:

Top-line service metrics

Pods are great, until they’re not(本文)

Encrypting all the things

Continuous deployment via traffic shifting

Dogfood environments, ingress, and edge routing

Staging microservices without the tears

Distributed tracing made easy

Linkerd as an ingress controller

gRPC for fun and profit

The Service Mesh API

Egress

Retry budgets, deadline propagation, and failing gracefully

Autoscaling by top-line metrics
 

Linkerd以DaemonSet方式运行


作为Service Mesh,Linkerd设计为与应用程序代码一起运行。它管理和监控service的内部通信,包括服务发现、重试、负载均衡与协议升级。

初次听闻,都会觉得这非常适合在Kubernetes中以Sidecar的方式部署。毕竟,Kubernetes的定义特征之一就是它的pod模型。作为Sidecar部署理论上简单,有清晰的失败语义,我们花了大量时间用于针对该用例的Linkerd优化。

然而,Sidecar模型有其缺陷:部署一个pod就要用掉部署一个pod的资源。如果你的Service较轻量并且跑了许多的应用实例,这样使用Sidecar来部署就会代价极高。

我们可以通过每一个host而非每一个pod部署一个Linkerd来减少资源的开销。它对每个主机进行扩展而消耗资源,这通常是比pod数量要显著更慢的增长的指标。并且很幸运,Kubernetes为此目的提供了DaemonSets。

但美中不足的是,对于Linkerd来说,按每个host部署比仅仅使用DaemonSets要复杂一些。我们如何解决Service Mesh这个问题?请继续阅读下文。
 

Kubernetes的Service 
MeshService Mesh的定义特征之一是它将应用通信与传输通信分离开的能力。例如,如果Service A与B使用HTTP协议通信,Service Mesh也许会通过电缆将之转换为HTTPS,而且应用程序并不知晓。Service Mesh也可以做连接池、权限控制,或其它的传输层特性,并且是以对应用程序透明的方式。

为了完美的做到这些,Linkerd必须作为本地实例的代理处于请求的发送端与接收端。例如HTTP升级为HTTPS,Linkerd一定要在传输层协议的开始与结束。在DaemonSet的世界,一个通过Linkerd的请求路线看起来如下图所示:





 
正如你所见,一个从Host 1中Pod A发起的目标为Host 2中Pod B的请求必须通过Pod A的本地Linkerd实例,然后到达Host 2的Linkerd实例,最后到达Pod J。这个路径引入了Linkerd必须解决的三个问题:


应用如何定位它的本地Linkerd

Linkerd如何将传出请求路由到目标Linkerd

Linkerd如何将传入请求路由到目标应用

接下来就讲述我们如何解决这三个问题的技术细节。
 
 

应用程序如何定位它的本地Linkerd
因为DaemonSet使用Kubernetes的host端口,我们就知道Linkerd运行于host IP的一个固定端口。因此,为了发送一个请求给运行于同一宿主机的Linkerd进程,我们需要确定这个主机的IP地址。

在Kubernetes 1.4及其以后的版本,此信息可通过底层API直接获取到。以下是来自hello-world.yaml的摘要,显示了如何将节点名称传递到应用程序中:
env: - name: NODE_NAME  valueFrom:    fieldRef:      fieldPath: spec.nodeName - name: http_proxy  value: $(NODE_NAME):4140 args: - "-addr=:7777" - "-text=Hello" - "-target=world"
 
(请注意,此例设置http_proxy环境变量以引导通过本地Linkerd实例的所有HTTP调用。然而此方法仅适用于大多数的HTTP应用,非HTTP应用需要做一些不同的工作)

Kubernetes 1.4之前的版本这些信息仍旧可用,但是方式要间接一些。

以下是hello-world-legacy.yml的一部分,显示如何将主机IP传递到应用程序中。
env: - name: POD_NAME  valueFrom:    fieldRef:      fieldPath: metadata.name - name: NS  valueFrom:    fieldRef:      fieldPath: metadata.namespace command: - "/bin/sh" - "-c" - "http_proxy=`hostIP.sh`:4140 helloworld -addr=:7777 -text=Hello -target=world"
 
请注意,hostIP.sh脚本需要将pod名和命名空间以环境变量的方式注入pod中。



Linkerd如何将传出请求路由到目标Linkerd
在我们的Service Mesh部署中,传出请求不应当直接发送给目标应用,而应当发送给运行于应用程序所在主机的Linkerd。为了做到这点,我们可以利用Linkerd 0.8.0引入的被称为transformer的新特性,它可以对Linker路由到的目标地址进行任意的后期处理。在这种情况下,我们可以使用DaemonSet transformer自动的让运行于目标主机的DaemonSet的地址取代目标地址。例如,这个Linkerd传出路由配置发送所有的请求到运行于相同主机的作为目标应用的Linkerd的输入端口。
 
routers: - protocol: http  label: outgoing  interpreter:    kind: default    transformers:    - kind: io.l5d.k8s.daemonset      namespace: default      port: incoming      service: l5d  ...

Linkerd如何将输入请求路由到目标应用
当一个请求最终到达目标pod的Linkerd实例,它一定得正确的路由到该pod。为此,我们使用localnode transformer将路由限制在运行于本地主机的pod。Linkerd配置示例如下:
routers: - protocol: http  label: incoming  interpreter:    kind: default    transformers:    - kind: io.l5d.k8s.localnode  ...


将Linkerd作为Kubernetes DaemonSet部署使得两全其美——它让我们完成service mesh的全部目标(如透明的TLS、协议升级、延迟感知负载均衡等等),同时按每个host扩缩Linkerd实例而非每个pod。
 
  查看全部
作者:ALEX LEONG


翻译:平凡

转自:容器时代(CaaSOne)
 
Service Mesh,一个为云平台而设计的应用,云平台的本地应用该如何使用它?本文中,我们将讲述在Kubernetes中如何应用Linkerd作为Service Mesh,如何捕获和报告顶层服务指标如成功率、请求量和延迟,而不需要更改应用的代码。


注意:这是关于Linkerd、Kubernetes和Service Mesh的系列文章其中一篇,其余部分包括:
  1. Top-line service metrics (本文)
  2. Pods are great, until they’re not
  3. Encrypting all the things
  4. Continuous deployment via traffic shifting
  5. Dogfood environments, ingress, and edge routing
  6. Staging microservices without the tears
  7. Distributed tracing made easy
  8. Linkerd as an ingress controller
  9. gRPC for fun and profit
  10. The Service Mesh API
  11. Egress
  12. Retry budgets, deadline propagation, and failing gracefully
  13. Autoscaling by top-line metrics




使用service mesh的必要性

关于Linkerd最常见的一个疑问就是,到底什么是Service Mesh?当Kubernetes已经提供了如Service资源对象、负载均衡这样的基本功能后,为什么Service Mesh要作为云本地应用程序的关键组件。


简单来说,Service Mesh这一层管理着应用之间的通信(或者部分应用之间的通信如微服务)。传统应用中,这个逻辑直接构建到应用程序本身中:重试和超时,监控/可见性,追踪,服务发现等等。这些都被硬编码到每个应用程序中。

然而,随着应用程序架构被越来越多的分割成服务,将通信逻辑从应用中移出到底层基础设施中变得越来越重要。就像是应用程序不应该写它自己的TCP栈,他们也不应该管理自己的负载均衡逻辑,或他们自己的服务发现管理程序,以及他们自己的重试和超时逻辑。

像Linkerd这样的Service Mesh为大规模多服务应用程序提供关键的部件:

基本的适应性功能:重试预算,deadline,熔断器模式

顶层的服务指标:成功率,请求量,延迟

延迟和失败容忍度:感应失败和延迟的负载均衡,它可以绕过缓慢的或者损坏的服务实例

分发追踪:如Zipkin和OpenTracing

服务发现:找到目标实例

协议升级:在TLS中包装跨网络通信,或将HTTP/1.1转换为HTTP/2.0

路由:不同版本的服务之间的路由请求,集群之间的故障转移等



在这部分中,我们仅重点关注可见性:Service Mesh是如何自动捕获并报告如成功率等顶层服务指标的,我们将展示一个Kubernetes的小例子以此来引导你。
 
在Kubernetes中使用Linkerd作为Service的检测器
 
在请求层进行操作的一个优势是Service Mesh可以访问成功和失败的协议级语义。举个例子,如果你正在运行一个HTTP服务,Linkerd可以理解200 、400、500响应的含义,从而可以自动计算如成功率这样的指标。

让我们通过一个小例子讲解如何在Kubernetes中安装Linkerd,从而自动的捕获顶层服务成功率而不需要更改应用程序。
 

安装Linkerd
使用Kubernetes配置文件安装Linkerd。它会将Linkerd作为DaemonSet安装,且运行在Kubernetes的default命名空间:
kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/linkerd.yml 
 
你可以通过查看Linkerd的管理页面确认是否安装成功:
INGRESS_LB=$(kubectl get svc l5d -o jsonpath="{.status.loadBalancer.ingress[0].*}") open http://$INGRESS_LB:9990 # on OS X
 
如果集群不支持外部负载均衡,使用hostIP:
HOST_IP=$(kubectl get po -l app=l5d -o jsonpath="{.items[0].status.hostIP}") open http://$HOST_IP:$(kubectl get svc l5d -o 'jsonpath={.spec.ports[2].nodePort}') # on OS X


1.png



安装样例应用程序
在default命名空间下安装两个Service,“hello”和“world”。这些应用程序依赖于Kubernetes downward API提供的nodeName来发现Linkerd。为了检测你的集群是否支持nodeName,你可以运行:
kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/node-name-test.yml 
 
然后看它的日志:kubectl logs node-name-test
 
如果你看到了一个IP就说明支持。接下来继续部署hello world应用程序如下:
kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world.yml 
 
如果你看到报错“server can’t find…”,就部署旧版本hello-world,它依赖于hostIP而非nodeName:kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world-legacy.yml 
 
这两个Service——“hello”和“world”——功能在一起使得高度可扩展,“hello world”微服务(“hello”Service调用“world”Service完成这个请求)。

你可以通过给Linkerd的外部IP发送请求来查看此操作:
http_proxy=$INGRESS_LB:4140 curl -s http://hello或者直接使用hostIP:http_proxy=$HOST_IP:$(kubectl get svc l5d -o 'jsonpath={.spec.ports[0].nodePort}') curl -s http://hello 
 
你应该可以看到字符串“Hello world”。
 

安装Linkerd-viz
最后,通过安装Linkerd-viz,让我们可以看看Service正在做什么。Linkerd-viz是一个附加包,它包括一个简单的Prometheus和Grafana设置,并可以自动发现Linkerd。
下面的命令会将Linkerd-viz安装到default命名空间下:
kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-viz/master/k8s/linkerd-viz.yml 
 
访问Linkerd-viz的外部IP查看dashboard:
VIZ_INGRESS_LB=$(kubectl get svc linkerd-viz -o jsonpath="{.status.loadBalancer.ingress[0].*}") open http://$VIZ_INGRESS_LB # on OS X
 
如果集群不支持外部负载均衡,使用hostIP:
VIZ_HOST_IP=$(kubectl get po -l name=linkerd-viz -o jsonpath="{.items[0].status.hostIP}") open http://$VIZ_HOST_IP:$(kubectl get svc linkerd-viz -o 'jsonpath={.spec.ports[0].nodePort}') # on OS X
 
你应该在dashboard上看到包括Service与实例的选择器,所有图表都反映了这些Service和实例的选择器。
 

2.png


Linkerd-viz的dashboard包括三部分:

顶层:集群范围的成功率与请求量

Service指标:每个已部署应用的指标,包括成功率、请求量和延迟

单个实例指标:集群上每一个node的成功率、请求量和延迟

用三个简单的命令我们就可以将Linkerd安装在集群上,安装应用,并且使用Linkerd了解应用程序Service的健康状况。当然,Linkerd提供的不仅仅是可见性,还提供了延迟感应负载均衡,自动重试和断路,分发追踪等功能。
 
 
 
第二部分:导言
 
在第一部分里我们提到了Linkerd是使用DaemonSet而非Sidecar来安装的。在第二部分中,我们将解释我们为什么(怎么样)这么做。

注意:这是关于Linkerd、Kubernetes和Service ,esh的系列文章其中一篇,其余部分包括:

Top-line service metrics

Pods are great, until they’re not(本文)

Encrypting all the things

Continuous deployment via traffic shifting

Dogfood environments, ingress, and edge routing

Staging microservices without the tears

Distributed tracing made easy

Linkerd as an ingress controller

gRPC for fun and profit

The Service Mesh API

Egress

Retry budgets, deadline propagation, and failing gracefully

Autoscaling by top-line metrics
 

Linkerd以DaemonSet方式运行


作为Service Mesh,Linkerd设计为与应用程序代码一起运行。它管理和监控service的内部通信,包括服务发现、重试、负载均衡与协议升级。

初次听闻,都会觉得这非常适合在Kubernetes中以Sidecar的方式部署。毕竟,Kubernetes的定义特征之一就是它的pod模型。作为Sidecar部署理论上简单,有清晰的失败语义,我们花了大量时间用于针对该用例的Linkerd优化。

然而,Sidecar模型有其缺陷:部署一个pod就要用掉部署一个pod的资源。如果你的Service较轻量并且跑了许多的应用实例,这样使用Sidecar来部署就会代价极高。

我们可以通过每一个host而非每一个pod部署一个Linkerd来减少资源的开销。它对每个主机进行扩展而消耗资源,这通常是比pod数量要显著更慢的增长的指标。并且很幸运,Kubernetes为此目的提供了DaemonSets。

但美中不足的是,对于Linkerd来说,按每个host部署比仅仅使用DaemonSets要复杂一些。我们如何解决Service Mesh这个问题?请继续阅读下文。
 

Kubernetes的Service 
MeshService Mesh的定义特征之一是它将应用通信与传输通信分离开的能力。例如,如果Service A与B使用HTTP协议通信,Service Mesh也许会通过电缆将之转换为HTTPS,而且应用程序并不知晓。Service Mesh也可以做连接池、权限控制,或其它的传输层特性,并且是以对应用程序透明的方式。

为了完美的做到这些,Linkerd必须作为本地实例的代理处于请求的发送端与接收端。例如HTTP升级为HTTPS,Linkerd一定要在传输层协议的开始与结束。在DaemonSet的世界,一个通过Linkerd的请求路线看起来如下图所示:

31.png

 
正如你所见,一个从Host 1中Pod A发起的目标为Host 2中Pod B的请求必须通过Pod A的本地Linkerd实例,然后到达Host 2的Linkerd实例,最后到达Pod J。这个路径引入了Linkerd必须解决的三个问题:


应用如何定位它的本地Linkerd

Linkerd如何将传出请求路由到目标Linkerd

Linkerd如何将传入请求路由到目标应用

接下来就讲述我们如何解决这三个问题的技术细节。
 
 

应用程序如何定位它的本地Linkerd
因为DaemonSet使用Kubernetes的host端口,我们就知道Linkerd运行于host IP的一个固定端口。因此,为了发送一个请求给运行于同一宿主机的Linkerd进程,我们需要确定这个主机的IP地址。

在Kubernetes 1.4及其以后的版本,此信息可通过底层API直接获取到。以下是来自hello-world.yaml的摘要,显示了如何将节点名称传递到应用程序中:
env: - name: NODE_NAME  valueFrom:    fieldRef:      fieldPath: spec.nodeName - name: http_proxy  value: $(NODE_NAME):4140 args: - "-addr=:7777" - "-text=Hello" - "-target=world"
 
(请注意,此例设置http_proxy环境变量以引导通过本地Linkerd实例的所有HTTP调用。然而此方法仅适用于大多数的HTTP应用,非HTTP应用需要做一些不同的工作)

Kubernetes 1.4之前的版本这些信息仍旧可用,但是方式要间接一些。

以下是hello-world-legacy.yml的一部分,显示如何将主机IP传递到应用程序中。
env: - name: POD_NAME  valueFrom:    fieldRef:      fieldPath: metadata.name - name: NS  valueFrom:    fieldRef:      fieldPath: metadata.namespace command: - "/bin/sh" - "-c" - "http_proxy=`hostIP.sh`:4140 helloworld -addr=:7777 -text=Hello -target=world"
 
请注意,hostIP.sh脚本需要将pod名和命名空间以环境变量的方式注入pod中。



Linkerd如何将传出请求路由到目标Linkerd
在我们的Service Mesh部署中,传出请求不应当直接发送给目标应用,而应当发送给运行于应用程序所在主机的Linkerd。为了做到这点,我们可以利用Linkerd 0.8.0引入的被称为transformer的新特性,它可以对Linker路由到的目标地址进行任意的后期处理。在这种情况下,我们可以使用DaemonSet transformer自动的让运行于目标主机的DaemonSet的地址取代目标地址。例如,这个Linkerd传出路由配置发送所有的请求到运行于相同主机的作为目标应用的Linkerd的输入端口。
 
routers: - protocol: http  label: outgoing  interpreter:    kind: default    transformers:    - kind: io.l5d.k8s.daemonset      namespace: default      port: incoming      service: l5d  ...

Linkerd如何将输入请求路由到目标应用
当一个请求最终到达目标pod的Linkerd实例,它一定得正确的路由到该pod。为此,我们使用localnode transformer将路由限制在运行于本地主机的pod。Linkerd配置示例如下:
routers: - protocol: http  label: incoming  interpreter:    kind: default    transformers:    - kind: io.l5d.k8s.localnode  ...


将Linkerd作为Kubernetes DaemonSet部署使得两全其美——它让我们完成service mesh的全部目标(如透明的TLS、协议升级、延迟感知负载均衡等等),同时按每个host扩缩Linkerd实例而非每个pod。
 
 

A-Service-Mesh-for-Kubernetes_Final-linkerd(附pdf下载)

小数 发表了文章 • 1 个评论 • 263 次浏览 • 2017-12-04 17:17 • 来自相关话题

分享两篇有关月linkerd的pdf文档,转自宋净超(Jimmy Song)https://github.com/rootsongjc/cloud-native-slides-share/tree/master/linkerd
分享两篇有关月linkerd的pdf文档,转自宋净超(Jimmy Song)https://github.com/rootsongjc/cloud-native-slides-share/tree/master/linkerd