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作为入口控制器。
这是关于linkerd,Kubernetes和service mesh的一系列文章中的一篇文章 。本系列的其他部分包括:
- Service重要指标
- 以DaemonSet方式运行linkerd
- 加密所有的东西
- 通过流量切换进行连续部署
- Dogfood环境,入口和边缘路由(本文)
- 轻松发布微服务
- 如何使分布式跟踪变得容易
- 使用Linkerd作为入口控制器
- gRPC乐趣和收益
- 服务网格API
- 出口
- 重试预算,截止日期传播,和如何让失败变得优雅(原文:Retry budgets, deadline propagation, and failing gracefully)
- 通过顶层指标(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的ingress
VIP 发送流量来测试设置 。在没有使用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.world
和 api.hello.world
的proxy_pass
指令发送请求到linkerd实例,为了最大程度地发挥作用,我们将使用Headers Moremore_clear_input_headers
提供的指令 (使用通配符匹配)。
(还有另外的方法,我们可以通过使用nginx的proxy_set_header
指令来避免使用第三方的Nginx模块来清除报文头。我们会需要为每个单独的条目剥离 l5d-ctx-
报文头还有 l5d-dtab
和 l5d-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 来查找相关信息,发送邮件到我们的 邮件列表或 直接与我们联系!