专题 | A Service Mesh for Kubernetes 第一期

Posted ServiceMesh中文网

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了专题 | A Service Mesh for Kubernetes 第一期相关的知识,希望对你有一定的参考价值。

翻译:平凡



第一部分:导言


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为大规模多服务应用程序提供关键的部件:

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

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

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

  4. 分发追踪:如Zipkin和OpenTracing

  5. 服务发现:找到目标实例

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

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


在这部分中,我们仅重点关注可见性:Service Mesh是如何自动捕获并报告如成功率等顶层服务指标的,我们将展示一个Kubernetes的小例子以此来引导你。


在Kubernetes中使用Linkerd作为Service的检测器


在请求层进行操作的一个优势是Service Mesh可以访问成功和失败的协议级语义。举个例子,如果你正在运行一个HTTP服务,Linkerd可以理解200 、400、500响应的含义,从而可以自动计算如成功率这样的指标。

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


1
安装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



2
安装样例应用程序

在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”。


3
安装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和实例的选择器。

专题 | A Service Mesh for Kubernetes 第一期

Linkerd-viz的dashboard包括三部分:

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

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

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

用三个简单的命令我们就可以将Linkerd安装在集群上,安装应用,并且使用Linkerd了解应用程序Service的健康状况。当然,Linkerd提供的不仅仅是可见性,还提供了延迟感应负载均衡,自动重试和断路,分发追踪等功能。


专题 | A Service Mesh for Kubernetes 第一期


第二部分:导言


在第一部分里我们提到了Linkerd是使用DaemonSet而非Sidecar来安装的。在第二部分中,我们将解释我们为什么(怎么样)这么做。

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

  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以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这个问题?请继续阅读下文。


1
Kubernetes的Service Mesh

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

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

专题 | A Service Mesh for Kubernetes 第一期

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

  • 应用如何定位它的本地Linkerd

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

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

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


2
应用程序如何定位它的本地Linkerd

在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中。


3
Linkerd如何将传出请求路由到目标Linkerd
routers: - protocol: http  label: outgoing  interpreter:    kind: default    transformers:    - kind: io.l5d.k8s.daemonset      namespace: default      port: incoming      service: l5d  ...
4
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。




推荐阅读














活动推荐:

1月27日,Building Microservice系列活动走进深圳即将开始,四位大咖齐聚深圳,带你深度学习华为微服务框架 ServiceComb,更有 Service Mesh 热潮架构Istio的实现过程面对面教学。点击阅读原文即可报名!


ServiceMesh中文社区:

ServiceMesh中文社区(servicemesh.cn)已上线,Istio、Conduit官方文档翻译版已在社区发布,欢迎大家登录浏览


ServiceMesh微信交流群:





点击“阅读原文”5


以上是关于专题 | A Service Mesh for Kubernetes 第一期的主要内容,如果未能解决你的问题,请参考以下文章

云原生技术专题-Service Mesh-技术演进之路

云原生技术专题-Service Mesh-产品的竞争

了解 Linkerd Service Mesh 架构

Building a Service Mesh with HAProxy and Consul

边缘计算场景下Service Mesh的延伸和扩展

Service Mesh 在中国工商银行的探索与实践