Kubernetes中的Service Mesh(第5部分):Dogfood环境和入口

A Service Mesh for Kubernetes (Part 5): Dogfood Environments and Ingress

原文作者:Alex Leong
原文地址:https://dzone.com/articles/a-service-mesh-for-kubernetes-part-v-dogfood-envir
译者微博:@从流域到海域
译者博客:blog.csdn.net/solo95
本文同样刊载于腾讯云+: https://cloud.tencent.com/developer/article/1017508

Kubernetes中的Service Mesh(第5部分):Dogfood环境和入口

在这篇文章中,我们将向您展示如何使用链接实例的服务网格来处理Kubernetes上的入口流量,将流量分布到网格中的每个实例。我们还将通过一个示例来演示linkerd的高级路由功能,方法是创建一个 dogfood 环境,将某些请求路由到较新版本的基础应用程序,例如用于内部的发布前测试。

这篇文章是关于使用linkerd作为流量到Kubernetes网络的入口点。从 0.9.1开始,linkerd直接支持Kubernetes Ingress资源,这是本文中一些用例的一个替代的,可能更简单的起点。有关如何使用linkerd作为 Kubernetes入口控制器的信息,请参阅Sarah的博客文章 Linkerd作为入口控制器

这是关于linkerdKubernetes和service mesh的一系列文章中的一篇文章 。本系列的其他部分包括:

  1. Service重要指标
  2. 以DaemonSet方式运行linkerd
  3. 加密所有的东西
  4. 通过流量切换进行连续部署
  5. Dogfood环境,入口和边缘路由(本文)
  6. 轻松发布微服务
  7. 如何使分布式跟踪变得容易
  8. 使用Linkerd作为入口控制器
  9. gRPC乐趣和收益
  10. 服务网格API
  11. 出口
  12. 重试预算,截止日期传播,和如何让失败变得优雅(原文:Retry budgets, deadline propagation, and failing gracefully)
  13. 通过顶层指标(top-line metrics)实现自动缩放

在本系列的前几期中,我们向您展示了如何使用linkerd来捕获 顶层指标(top-line metrics),透明地在服务调用中添加TLS,并 执行bluegreen部署。这些帖子展示了如何在像Kubernetes这样的环境中使用linkerd作为srevice mesh,为内部服务对服务调用增加了一层弹性和性能。在这篇文章中,我们将把这个模型扩展到入口路由。

尽管本文中的示例是针对Kubernetes的,但我们不会使用 Kubernetes提供的内置 Ingress Resource(对此请参阅 Sarah的文章)。虽然Ingress Resource是一种基本路径和基于主机路由的简便方法,但在撰写本文时,它们仍相当有限。在下面的例子中,我们做的将远远超出Ingress Resources所提供的功能。

步骤1:部署Linkerd Service Mesh

从前面的文章中我们针对Kubernetes中的基本linkerd service mesh配置开始,我们将进行两个更改以支持入口(ingress):我们将修改linkerd配置以添加一个额外的逻辑路由器,然后调整围绕着linkerd展开的Kubernetes服务对象中的VIP。(完整的配置在这里: linkerd-ingress.yml。)

以下是linkerd实例上新的ingress逻辑路由器,它将处理入口流量并将其路由到相应的服务:

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”到 world 服务。为了简单起见,我们为每个域添加了一条规则,这些映射可以很容易地被聚合以实现更复杂的设置。(如果你是一个linkerd配置爱好者,我们将通过组合linkerd默认的header token identifier 在主机header上实现路由转发, the domainToPathPfx namer 把虚主机名转换成分级路径,和并且io.l5d.k8s.daemonset transformer 将请求发送到相应的主机 本地的linkerd上。)

我们已经将此入口路由器添加到每个linkerd实例 - 以真正的service mesh方式,我们将在这些实例之间完全分配入口流量,以便没有哪一个实例成为单点故障。

我们还需要修改我们的 k8s 服务对象,以便用端口80上的outgoing VIP去替换ingress VIP。这将允许我们将入口流量直接发送到linkerd service mesh - 主要用于调试目的,因为在点击linkerd之前,流量不会被消毒。(下一步,我们将解决这个问题。)

Kubernetes变化看起来像这样:

---
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

以上所有操作都可以通过运行以下命令来完成:使用完整的带入口的linkerd service mesh配置(https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/linkerd-ingress.yml):

$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/linkerd-ingress.yml

第2步:部署服务

对于在这个例子中的服务,我们将使用相同的hello and world configs 从以前的博客文章,我们将添加两个新的服务:一个API service,这就要求既 hello服务 和 world服务,以及word服务的新版本: world-v2,这将返回“earth”而不是“world”这个词 - 正在逐渐壮大的hacker团队已经向我们证明了,他们的A/B测试显示这一变化将使参与度提高10倍。

以下命令将把三个Hello World服务部署到默认名称空间:

$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world.yml
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/api.yml
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/world-v2.yml

在这一点上,我们应该能够通过Kubernetes的ingressVIP 发送流量来测试设置 。在没有使用DNS的情况下,我们将在请求中手动设置一个主机头:

$ 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)!!"}

成功!我们已经将linkerd设置为入口控制器,并且我们已经使用它将不同域中收到的请求路由转发到不同的服务。正如你所看到的,生产流量正在实现 world-v1 服务 - 我们还没有准备好把 world-v2 展示出来。

第3步:NGINX中的一层

到了这一步,我们有正在运作的入口(ingress)。但是,我们目前还没有准备好生产。首先,我们的入口路由器不会从请求中去掉头文件,这意味着外部请求可能包含我们不想接受的头文件。例如,linkerd允许每个请求应用路由规则设置将其header设置为l5d-dtab 。这对于新服务的临时分级是一个非常有用的功能,但这可能不是来自外部世界的合适调用!

例如,我们可以使用 l5d-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 来解决这个问题和其他问题(例如如何服务静态文件) 。如果我们配置NGINX在其代理的请求到链接入口路由之前剥离传入的报头,我们将得到两全其美的好处:一个能够安全处理外部流量的入口层,还有linkerd进行的动态的,基于服务的路由。

让我们把nginx添加到集群。我们将使用这个nginx.conf来配置它 。我们将使用我们的虚拟服务器下的 www.hello.worldapi.hello.worldproxy_pass指令发送请求到linkerd实例,为了最大程度地发挥作用,我们将使用Headers Moremore_clear_input_headers提供的指令 (使用通配符匹配)。

(还有另外的方法,我们可以通过使用nginx的proxy_set_header 指令来避免使用第三方的Nginx模块来清除报文头。我们会需要为每个单独的条目剥离 l5d-ctx- 报文头还有 l5d-dtabl5d-sample 报文头。)

请注意,从 linkerd 0.9.0开始,我们可以通过设置clearContext: true清除在入口路由器服务器 传入的 l5d-*报文头。然而,nginx还有很多我们可以使用的功能(就像你现在看到的那样),所以把nginx和linkerd结合使用仍然是有价值的。

对于你们这些家工作的人,我们已经发布了一个nginx的Docker镜像,其中把安装了 Headers More模块的(Dockerfile)称为buoyantio / nginx:1.11.5。我们可以使用这个Kubernetes配置文件把上面提到的配置用这个镜像部署:

$ 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

我们现在应该能够通过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)!!

第四步:Dogfood的优势时间

好吧,我们已经做好了准备:让我们建立一个使用world-v2 服务的dogfood环境 ,但仅限于使用某些流量!

为了简单起见,我们为目标流量设置一个特定的cookie, 即special_employee_cookie。在实践中,你可能想要比这更复杂的东西 - 要验证它,需要来自公司内部网络范围的IP等等。

在NGINX和linkerd安装之后,完成这些将会变得很简单。我们将使用NGINX来检查特定cookie(指special_employee_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模式可以包含出现在服务堆栈中的任何地方的新版本的服务 ,甚至是多层深度的服务代码,甚至服务代码forwards linkerd context headers,linkerd service mesh将负责其余的工作。

结论

在这篇文章中,我们看到了如何使用linkerd为Kubernetes集群提供强大灵活的入口(ingress)。我们已经演示了如何部署正如其名的已经准备完毕的生产环境配置,该生产环境配置使用linkerd进行服务路由转发。我们已经演示了如何使用linkerd的一些高级路由功能来将 traffic-serving 拓扑与 deployment拓扑分离,从而允许创建dogfood环境而不需要单独的集群或耗费很多的部署时间。

有关在Kubernetes中运行linkerd的更多信息,或者如果您在配置入口时遇到任何问题,请随时通过我们的Linkerd社区Slack 来查找相关信息,发送邮件到我们的 邮件列表直接与我们联系

posted @ 2018-01-09 19:53  从流域到海域  阅读(82)  评论(0编辑  收藏  举报