Kubernetes的服务网格(第4部分):通过流量切换持续部署

除了服务发现,重要指标和TLS之外,linkerd还具有强大的路由语言,称为dtabs,可以用来改变请求的方式 - 甚至是单个请求 - 流经应用程序拓扑。在本文中,我们将向您展示如何使用linkerd作为服务网格来作为CI / CD管道的最后一步来执行新代码的蓝绿部署。

注意:这篇文章是和 Kevin Lingerfelt 共同撰写的。它是关于linkerd,Kubernetes和服务网格的系列文章之一。本系列的其他部分包括:

  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这样的服务网格来获取重要的服务指标,并在应用程序代码中透明地添加TLS。

在本文中,我们将向您展示如何使用linkerd的路由策略(称为 dtabs)在CI / CD管道末端通过应用程序自动更改流量流以在新旧之间执行蓝绿部署服务的版本。

持续部署(CD)是持续集成(CI)的延伸,将代码持续推向生产,与开发过程紧密结合。虽然它需要很强的自动化,但可以最大限度地缩短开发和部署之间的周期,使公司能够快速迭代产品。

对于多服务或微服务体系结构,CD流程的最后一步(部署本身)可能是有风险的,因为运行时的环境(包括处理生产流量的其他服务)限定了太多的行为。在这种情况下,像蓝绿部署这样的服务的推广变得越来越重要。

协调跨多个链接器的流量转移需要一个集中的流量控制工具。为此,我们推荐使用 namerd服务,该服务使用API​​来提供由一致存储支持的路由规则。您可以在我们之前的博客文章中了解更多关于namerd如何与生产系统集成的内容,其中涵盖了linkerd中的路由。

我们将使用来自linkerd-examples GitHub 仓库的示例应用程序演示蓝绿部署 。示例应用程序是一个人工的“hello world”微服务应用程序,由一个“hello”服务组成,它处理传入请求并在返回响应之前调用“全局”服务。通过Jenkins作为我们的自动化服务器,我们将使用Jenkins管道插件部署新版本的world服务 。

Kubernetes的服务网格

在我们开始持续部署之前,我们需要首先将hello world app部署到Kubernetes,使用linkerd和namerd路由请求。我们可以通过使用 linkerd-examples回购库中的Kubernetes配置轻松完成此操作 。

第1步:安装Namerd

我们从安装namerd开始,namerd管理着dtabs,而dtabs是我们用来编排蓝绿部署的。此处请注意所用的namerd configuration使用ThirdPartyResource APIs,并依赖于Kubernetes 1.2+的集群且启用了ThirdPartyResource。

要将namerd安装在默认的Kubernetes名称空间中,请运行:

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

您可以通过查看namerd的管理页面来确认安装是否成功(请注意,入口IP可能需要几分钟时间):

NAMERD_INGRESS_LB = $(kubectl get svc namerd -o jsonpath =“{。status.loadBalancer.ingress [0]。*}”)
open http://$NAMERD_INGRESS_LB:9990 #在OS X上

管理页面显示所有已配置的namerd命名空间,并配置了两个命名空间 - “external”和“internal”。为了持续部署,我们主要去关注“内部”命名空间。

除了管理界面之外,我们还可以使用 namerctl 工具直接与namerd对话。部署脚本将使用此实用程序来开始将流量发送到新部署的服务。要在本地安装,请运行:

go get -u github.com/linkerd/namerctl
go intall github.com/linkerd/namerctl

该实用程序使用 NAMERCTL_BASE_URL 环境变量连接到namerd。为了连接到我们刚刚部署到Kubernetes的namerd版本,请按如下所示设置变量:

export NAMERCTL_BASE_URL = http:// $ NAMERD_INGRESS_LB:4180

现在尝试使用 namerctl 来显示内部dtab:

$ namerctl dtab get internal
#版本为 MjgzNjk5NzI =
/ srv          = > / #/ io.l5d.k8s / default / http;
/ host         = > / srv;
/ tmp          = > / srv;
/ svc          = > / host;
/ host / world   = > / srv / world-v1;

dtab的最后一行将world 服务的逻辑名称映射到当前部署的world服务的版本 world-v1。在一个生产系统中,版本可以是shas、日期或其他保证名称唯一性的东西。我们将使用这个dtab条目安全地将新版本的world服务引入生产环境。

第2步:安装Linkerd

接下来,我们将安装linkerd并将其配置为使用namerd解析路由。要将链接器作为DaemonSet(即每个主机一个实例)安装在默认的Kubernetes命名空间中,请运行:

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

您可以通过查看linkerd的管理用户界面来确认安装是否成功(请注意,入口IP可能需要几分钟时间):

L5D_INGRESS_LB = $(kubectl get svc l5d -o jsonpath =“{。status.loadBalancer.ingress [0]。*}”)
open http:// $ L5D_INGRESS_LB:9990 #在OS X上

我们将使用管理界面来验证蓝绿部署的步骤。

第3步:安装示例应用程序

现在,我们将通过运行以下命令来将hello和world应用程序安装在默认命名空间中:

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

在这一点上,我们实际上有一个正常运行的服务网格和一个使用它的应用程序。您可以通过linkerd的外部IP发送流量来查看整个设置:

$ curl  $ L5D_INGRESS_LB
hello(10.196.2.5)world(10.196.2.6)!!

如果一切正常,您将看到类似于上面的“Hello world”消息,以及为请求提供服务的pod的IP。

持续部署

我们现在将使用Jenkins来执行我们在前一步中部署的“world”服务的蓝绿部署。

设置詹金斯

我们首先将buoyantio / jenkins-plus Docker镜像部署 到我们的Kubernetes集群。该图像提供了基本jenkins的图像,与我们需要的kubectlnamerctl 二进制文件,以及额外的插件,并且我们可以用它来运行部署的预配置的流水线作业。管道作业使用 Jenkins管道插件 和 自定义的Groovy脚本 来处理蓝绿部署中的每个步骤。

要将Jenkins图像部署到默认的Kubernetes命名空间,请运行:

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

您可以通过打开Jenkins Web UI来确认安装是否成功(请注意,入口IP可能需要几分钟时间):

JENKINS_LB = $(kubectl get svc jenkins -o jsonpath =“{。status.loadBalancer.ingress [0]。*}”)
open http:// $ JENKINS_LB  #在OS X上

你应该在UI中看到一个“hello_world”作业。

提交代码

现在是对世界服务进行一些代码更改的时候了,Jenkins的工作将它们部署到我们的生产环境中。要做到这一点,首先在Github UI中 linkerd-examples 进行分叉。一旦你创建了一个分支,便要在本地克隆你的分支:

git clone https://github.com/esbie/linkerd-examples.git
cd linkerd-examples

为了这个例子,我们要改变一个控制world服务输出的文本文件。默认情况下,world服务输出字符串“ world”:

$ cat k8s-daemonset / helloworld / world.txt
world

让我们来补充一点:

echo "hal, open the pod bay doors" > k8s-daemonset/helloworld/world.txt

提交:

git commit -am "Improve the output of the world service"
git push origin master

现在是时候把这个关键的修改投入生产了。

运行工作

随着我们所做的改变,并推送到我们的linkerd-examples 分叉 ,我们可以启动jenkins“hello_world”管道工作,以安全地将这些变化部署到生产变化。管道作业中的6个步骤中的每一个步骤均由自定义的Groovy脚本控制,并在下面进行更详细的介绍。部署是完全自动化的,除了管道中的三个地方之外,它们在进行之前暂停用于对关键指标进行人为在线验证。

用参数建立

要开始部署,请单击Jenkins UI中的“hello_world”作业,然后单击边栏中的“使用参数生成”。你会被带到一个页面,让你自定义部署,它会看起来像这样:

pipeline-build-parameters.png

gitRepo 表单字段的值更改为指向您的linkerd-examples分支 ,然后单击“生成”按钮。请注意,如果您将更改推送到分叉中的单独分支,则还应该更改gitBranch 表单字段的值以匹配分支名称。

克隆

管道中的第一步是使用上面指定的构建参数来克隆git 仓库。

部署

部署管道中的第二步是实际将新版本的世界服务部署到我们的集群,而不发送任何流量。该脚本确定当前部署的世界服务版本是 world-v1,因此它创建一个新的服务调用,world-v2 并将其部署到我们的Kubernetes群集。在这一点上,你会看到两个不同版本的世界服务同时运行:

$ kubectl  get po | grep world
world-v1-9eaxk                1/1       Running  0           3H
world-v1-kj6gi                1/1       Running   0          3h
world-v1-vchal                1/1       Running   0          3h
world-v2-65y9g                1/1       Running   0          30m
world-v2-d260q                1/1       Running   0          30m
world-v2-z7ngo                1/1       Running   0          30m

即使 world-v2 版本完全部署,我们仍然没有对生产流量进行任何更改!linkerd和namerd仍被配置为将所有世界服务流量路由到现有 world-v1 版本。在发送任何流量之前完全部署新版本的服务是执行蓝绿部署的关键。

集成测试

一旦我们的服务的新版本被部署,脚本执行一个测试请求,以确保可以达到新版本。如果测试请求成功,则暂停部署并等待我们确认新部署的版本在继续之前看起来是正确的。

pipeline-integration-testing.png

在这一点上,我们要确保新的pods正在按预期运行 - 不仅仅是自己运行,而且还要与生产环境的其他部分一起运行。通常情况下,这将涉及部署到单独的分段集群,再加上一些向该集群发送或重播生产流量的机制。

由于我们使用的是linkerd,所以我们可以通过利用linkerd的每个请求路由 来在没有专门的登台环境的情况下完成同样的事情,从而大大简化了这个操作 。在入口处,我们可以用一个特殊的头部来标记我们的请求 l5d-dtab,这将指示链接器通过生产集群路由这个请求,但是用所有的服务 world-v1 调用来 world-v2 代替 这个请求

Jenkins UI提供了我们需要将请求路由到新版本服务的dtab覆盖,并使用该信息我们可以创建自己的测试请求:

$ curl -H 'l5d-dtab: /host/world => /tmp/world-v2' $L5D_INGRESS_LB
Hello (10.196.2.5) hal, open the pod bay doors (10.196.1.17)!!

成功!我们的请求正在被传送到 world-v2 服务中,该服务正在返回我们在分支上添加的新world文本。虽然我们能够达到新的服务,值得注意的是 ,除了我们刚刚提出的请求之外,我们没有改变任何生产流量的行为。我们可以进行验证,通过省略 l5d-dtab,并确保我们仍然得到 world-v1 回应:

$ curl  $ L5D_INGRESS_LB
Hello (10.196.2.5) world (10.196.2.6)!!

如果一切正常,我们可以通过单击“Ok, I’m done with manual testing”按钮进行下一步。

切换流量(10%)

经过一些手动测试,我们准备开始蓝绿部署,将生产流量10%发送到新部署的服务版本。脚本在路由策略中进行了更改,并再次暂停,要求我们确认一切正常,然后再继续执行这10%的流量。

pipeline-shift-traffic-10.png

请注意,如果用户在任何管道步骤中放弃,则脚本会假定新服务出现问题,并自动恢复路由更改,并将所有通信发送回原始服务。由于我们并没有在切换流量的同时拆除旧版本服务的实例,因此恢复流量回收可能会很快发生,从而最大限度地减少不良部署的影响。

我们可以通过发送10个请求来验证我们的服务占用了10%的请求,希望我们的服务对我们有利:

$ for i in {1..10}; do curl $L5D_INGRESS_LB; echo ""; done
Hello (10.196.2.5) world (10.196.1.16)!!
Hello (10.196.2.5) world (10.196.1.16)!!
Hello (10.196.2.5) hal, open the pod bay doors (10.196.2.13)!!
Hello (10.196.2.5) world (10.196.1.16)!!
Hello (10.196.2.13) world (10.196.2.6)!!
Hello (10.196.2.13) world (10.196.2.6)!!
Hello (10.196.2.5) world (10.196.1.16)!!
Hello (10.196.2.5) world (10.196.2.6)!!
Hello (10.196.1.14) world (10.196.2.6)!!
Hello (10.196.1.14) world (10.196.2.16)!!

看起来不错!现在也是检查linkerd的管理仪表板的好时机,以验证新服务是否正常。如果您的应用程序收到少量稳定的流量,那么仪表板将如下所示:

pipeline-admin.png

我们可以马上看到,该 world-v2 服务约占流量的10%,成功率为100%。如果一切正常,我们可以通过单击Jenkins UI中的“Ok, success rates look stable”按钮继续下一步。

切换流量(100%)

在这一步中,脚本将额外的流量转移到我们服务的新版本。举一个简明的例子,我们立刻转向100%的流量,但在典型的部署中,您可以在流水线中包含额外的中间百分比作为单独的步骤。

pipeline-shift-traffic-100.png

我们可以通过发送一个没有dtab覆盖头的请求来验证新服务是否提供流量。

$ curl  $ L5D_INGRESS_LB

Hello (10.196.2.5) hal, open the pod bay doors (10.196.2.13)!!

一旦我们 world-v2 成功处理了100%的生产流量,我们可以通过单击Jenkins UI中的“确定,一切看起来不错”按钮进行最后一步。

清理

在最后一步,脚本通过使路由规则将流量路由到新版本的服务永久性来完成部署。它还会将先前版本的仍在群集中运行但尚未收到任何流量的服务截断。

pipeline-cleanup.png

namerd的dtab的最终版本现在是:

$ namerctl dtab get internal
#版本为 MTIzMzU0OTE =
/ srv          = > / #/ io.l5d.k8s / default / http;
/ host         = > / srv;
/ tmp          = > / srv;
/ http / * / *     = > / host;
/ host / world   = > / srv / world-v2;

我们可以通过查看当前部署到集群的world服务来验证旧服务已经被拆除。

$ kubectl  get po | grep world
world-v2-65y9g                1/1       Running   0          1h
world-v2-d260q                1/1       Running   0          1h
world-v2-z7ngo                1/1       Running   0          1h

一切看起来不错。启动后续管道作业将部署一个 world-v3服务版本,逐渐将流量转移,然后在部署成功完成时将其提升为当前版本。

结论

在这篇文章中,我们展示了一个包含linkerd,namerd和Jenkins的基本工作流程,以逐步将流量从旧版本转移到新版本的服务作为持续部署管道的最后一步。我们已经展示了linkerd如何执行每个请求路由,实际上让我们可以在不需要单独的临时集群的情况下执行新版本的服务,通过使用 l5d-dtab 头将新服务缝合到生产拓扑中,仅用于该请求。最后,我们展示了基于百分比的流量转移如何与Jenkins的输入步骤相结合,以便在流量从0%移动到100%时允许对指标进行人为的在线验证。

这是一个相当简单的例子,但我们希望它演示了使用服务网格路由进行持续部署的基本模式,并为您自己的组织提供了用于自定义此工作流的模板。如需关于dtabs或其他关于linkerd的帮助,请随时通过我们的linkerd社区Slack联系 ,发送邮件到我们的邮箱,或直接与我们联系!

本文的版权归 Ksher 所有,如需转载请联系作者。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏杂烩

elasticsearch2.3.1 集群安装

    ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elastic...

763
来自专栏nimomeng的自我进阶

简单免费的文档中心——dokuWiki搭建指南

首先去官网下载页面下载最新版本的Dokuwiki,根据自己需要动态打包,不需要安装:

4.3K3
来自专栏linux运维学习

linux学习第五十九篇:LVS DR模式搭建,keepalived lvs

LVS DR模式搭建 准备工作 三台机器 分发器,也叫调度器(简写为dir) 需要把之前rs机器的网关改回来 85.132 rs1 85.1...

29710
来自专栏前端杂货铺

提升node.js中使用redis的性能

某基于node.js开发的业务系统向外提供了一个dubbo服务,提供向第三方缓存查询、设置多项业务数据并聚合操作结果。在QPS达到800时(两台虚拟机,每台机器...

1962
来自专栏王清培的专栏

ElasticSearch大数据分布式弹性搜索引擎使用

阅读目录: 背景 安装 查找、下载rpm包 、执行rpm包安装 配置elasticsearch专属账户和组 设置elasticsearch文件所有者 切换到el...

74310
来自专栏码神联盟

nginx+tomcat负载均衡配置

前几天,我们讲过了【互联网常见架构模式 之 nginx负载均衡】(忘记的童鞋,点击上面链接或者输入关键词:nginx\负载均衡,即可重新阅读),...

4178
来自专栏微服务生态

缓存穿透、缓存并发、缓存失效之思路变迁

我们在用缓存的时候,不管是Redis或者Memcached,基本上会通用遇到以下三个问题:

1394
来自专栏芋道源码1024

缓存穿透、缓存并发、缓存失效之思路变迁

来源:https://www.jianshu.com/p/d96906140199

962
来自专栏java思维导图

Cookie、Session、Token那点事儿

前言:新公司项目中使用到了Cookie,在各大Android技术讨论群向前辈们取经讨论这cookie、session、token这仨哥们的时候,很多开发者说法不...

2483
来自专栏Java技术栈

分布式Session共享解决方案

Session是服务器用来保存用户操作的一系列会话信息,由Web容器进行管理。单机情况下,不存在Session共享的情况,分布式情况下,如果不进行Session...

3646

扫码关注云+社区