专栏首页DevOps时代的专栏使用 Istio 实现灰度发布(金丝雀发布)

使用 Istio 实现灰度发布(金丝雀发布)

灰度发布(又名金丝雀发布)介绍

当应用上线以后,运维面临的一大挑战是如何能够在不影响已上线业务的情况下进行升级。做过产品的同学都清楚,不管在发布前做过多么完备的自动化和人工测试,在发布后都会出现或多或少的故障。根据墨菲定律,可能会出错的版本发布一定会出错。

“ANYTHING THAN CAN GO WRONG WILL GO WRONG” –MURPHY’S LAW

因此我们不能寄希望于在线下测试时发现所有潜在故障。在无法百分百避免版本升级故障的情况下,需要通过一种方式进行可控的版本发布,把故障影响控制在可以接受的范围内,并可以快速回退。

可以通过灰度发布(又名金丝雀发布)来实现业务从老版本到新版本的平滑过渡,并避免升级过程中出现的问题对用户造成的影响。

“金丝雀发布”的来源于矿工们用金丝雀对矿井进行空气测试的做法。以前矿工挖煤的时候,矿工下矿井前会先把金丝雀放进去,或者挖煤的时候一直带着金丝雀。金丝雀对甲烷和一氧化碳浓度比较敏感,会先报警。所以大家都用“金丝雀”来搞最先的测试。

下图中,左下方的少部分用户就被当作“金丝雀”来用于测试新上线的1.1版本。如果新版本出现问题,“金丝雀”们会报警,但不会影响其他用户业务的正常运行。

灰度发布(金丝雀发布)的流程如下:

  • 准备和生产环境隔离的“金丝雀”服务器。
  • 将新版本的服务部署到“金丝雀”服务器上。
  • 对“金丝雀”服务器上的服务进行自动化和人工测试。
  • 测试通过后,将“金丝雀”服务器连接到生产环境,将少量生产流量导入到“金丝雀”服务器中。
  • 如果在线测试出现问题,则通过把生产流量从“金丝雀”服务器中重新路由到老版本的服务的方式进行回退,修复问题后重新进行发布。
  • 如果在线测试顺利,则逐渐把生产流量按一定策略逐渐导入到新版本服务器中。
  • 待新版本服务稳定运行后,删除老版本服务。

Istio实现灰度发布(金丝雀发布)的原理

从上面的流程可以看到,如果要实现一套灰度发布的流程,需要应用程序和运维流程对该发布过程进行支持,工作量和难度的挑战是非常大的。虽然面对的问题类似,但每个企业或组织一般采用不同的私有化实现方案来进行灰度发布,为解决该问题导致研发和运维花费了大量的成本。

Istio通过高度的抽象和良好的设计采用一致的方式解决了该问题,采用sidecar对应用流量进行了转发,通过Pilot下发路由规则,可以在不修改应用程序的前提下实现应用的灰度发布。

备注:采用kubernetes的滚动升级(rolling update)功能也可以实现不中断业务的应用升级,但滚动升级是通过逐渐使用新版本的服务来替换老版本服务的方式对应用进行升级,在滚动升级不能对应用的流量分发进行控制,因此无法采用受控地把生产流量逐渐导流到新版本服务中,也就无法控制服务升级对用户造成的影响。

采用Istio后,可以通过定制路由规则将特定的流量(如指定特征的用户)导入新版本服务中,在生产环境下进行测试,同时通过渐进受控地导入生产流量,可以最小化升级中出现的故障对用户的影响。并且在同时存在新老版本服务时,还可根据应用压力对不同版本的服务进行独立的缩扩容,非常灵活。采用Istio进行灰度发布的流程如下图所示:

操作步骤

下面采用Istion自带的BookinfoInfo示例程序来试验灰度发布的流程。

测试环境安装

首先参考手把手教你从零搭建Istio及Bookinfo示例程序安装Kubernetes及Istio控制面。

因为本试验并不需要安装全部3个版本的reviews服务,因此如果已经安装了该应用,先采用下面的命令卸载。

istio-0.2.10/samples/bookinfo/kube/cleanup.sh

部署V1版本的服务

首先只部署V1版本的Bookinfo应用程序。由于示例中的yaml文件中包含了3个版本的reviews服务,我们先将V2和V3版本的Deployment从yaml文件istio-0.2.10/samples/bookinfo/kube/bookinfo.yaml中删除。

从Bookinfo.yaml中删除这部分内容:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: reviews-v2
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: reviews
        version: v2
    spec:
      containers:
      - name: reviews
        image: istio/examples-bookinfo-reviews-v2:0.2.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: reviews-v3
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: reviews
        version: v3
    spec:
      containers:
      - name: reviews
        image: istio/examples-bookinfo-reviews-v3:0.2.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---

部署V1版本的Bookinfo程序。

kubectl apply -f <(istioctl kube-inject -f istio-0.2.10/samples/bookinfo/kube/bookinfo.yaml)

通过kubectl命令行确认pod部署,可以看到只有V1版本的服务。

kubectl get pods

NAME                              READY     STATUS    RESTARTS   AGE
details-v1-3688945616-nhkqk       2/2       Running   0          2m
productpage-v1-2055622944-m3fql   2/2       Running   0          2m
ratings-v1-233971408-0f3s9        2/2       Running   0          2m
reviews-v1-1360980140-0zs9z       2/2       Running   0          2m

在浏览器中打开应用程序页面,地址为istio-ingress的External IP。由于V1版本的reviews服务并不会调用rating服务,因此可以看到Product 页面显示的是不带星级的评价信息。

http://10.12.25.116/productpage

此时系统中微服务的部署情况如下图所示(下面的示意图均忽略和本例关系不大的details和ratings服务):

部署V2版本的reviews服务

在部署V2版本的reviews服务前,需要先创建一条缺省路由规则route-rule-default-reviews.yaml,将所有生产流量都导向V1版本,避免对线上用户的影响。

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: reviews-default
spec:
  destination:
    name: reviews
  precedence: 1
  route:
  - labels:
      version: v1

启用该路由规则。

istioctl create -f route-rule-default-reviews.yaml -n default 创建一个V2版本的部署文件bookinfo-reviews-v2.yaml,内容如下

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: reviews-v2
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: reviews
        version: v2
    spec:
      containers:
      - name: reviews
        image: istio/examples-bookinfo-reviews-v2:0.2.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080

部署V2版本的reviews服务。

kubectl apply -f <(istioctl kube-inject -f  bookinfo-reviews-v2.yaml)

此时系统中部署了V1和V2两个版本的reviews服务,但所有的业务流量都被规则reviews-default导向了V1,如下图所示:

将测试流量导入到V2版本的reviews服务

在进行模拟测试时,由于测试环境和生产环境的网络,服务器,操作系统等环境存在差异,很难完全模拟生产环境进行测试。为了减少环境因素的对测试结果的影响,我们希望能在生产环境中进行上线前的测试,但如果没有很好的隔离措施,可能会导致测试影响已上线的业务,对企业造成损失。

通过采用Istio的路由规则,可以在类生产环境中进行测试,又完全隔离了线上用户的生产流量和测试流量,最小化模拟测试对已上线业务的影响。如下图所示:

创建一条规则,将用户名为 test-user 的流量导入到V2

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: reviews-test-user
spec:
  destination:
    name: reviews
  precedence: 2
  match:
    request:
      headers:
        cookie:
          regex: "^(.*?;)?(user=test-user)(;.*)?$"
  route:
  - labels:
      version: v2

注意:precedence属性用于设置规则的优先级,在同时存在多条规则的情况下,优先级高的规则将先执行。这条规则的precedence设置为2,以确保其在缺省规则之前运行,将test-user用户的请求导流到V2版本reviews服务中。

启用该规则。

istioctl create -f route-rule-test-reviews-v2.yaml -n default

以test-user用户登录,可以看到V2版本带星级的评价页面。

注销test-user,只能看到V1版本不带星级的评价页面。如下图所示:

将部分生产流量导入到V2版本的reviews服务

在线上模拟测试完成后,如果系统测试情况良好,可以通过规则将一部分用户流量导入到V2版本的服务中,进行小规模的“金丝雀”测试。

修改规则route-rule-default-reviews.yaml,将50%的流量导入V2版本。

备注:本例只是描述原理,因此为简单起见,将50%流量导入V2版本,在实际操作中,更可能是先导入较少流量,然后根据监控的新版本运行情况将流量逐渐导入,如采用5%,10%,20%,50% …的比例逐渐导入。

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: reviews-default
spec:
  destination:
    name: reviews
  precedence: 1
  route:
  - labels:
      version: v1
    weight: 50
  - labels:
      version: v2
    weight: 50
istioctl replace -f route-rule-default-reviews.yaml -n default

此时系统部署如下图所示:

将所有生产流量导入到到V2版本的reviews服务

如果新版本的服务运行正常,则可以将所有流量导入到V2版本。

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: reviews-default
spec:
  destination:
    name: reviews
  precedence: 1
  route:
  - labels:
      version: v2
    weight: 100
istioctl replace -f route-rule-default-reviews.yaml -n default

系统部署如下图所示:

此时不管以任何用户登录,都只能看到V2版本带星级的评价页面,如下图所示:

备注:如果灰度发布的过程中新版本的服务出现问题,则可以通过修改路由规则,将流量重新导入到V1版本的服务中,将V2版本故障修复后再进行测试。

删除V1版本的reviews服务

待V2版本上线稳定运行后,删除V1版本的reviews服务和测试规则。

kubectl delete pod reviews-v1-1360980140-0zs9z

istioctl delete -f route-rule-test-reviews-v2.yaml -n default

参考

https://istio.io/docs/

本文分享自微信公众号 - DevOps时代(DevOpsTimes),作者:赵化冰

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-04-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 大型分布式团队的集中化持续交付

    持续集成是一种软件开发实践,即团队开发成员集成他们的工作,通常每个成员每天至少集成一次,随着对自动化要求的不断提高,需要自动化构建来完成的应用也越来越多,此问题...

    DevOps时代
  • 你可能会忽略的 Git 提交规范

    一直是 ESLint 的忠实用户,深知规范的重要性。然而,在新项目交接中,我被 Git Commit 规范逼疯了。才意识到自己的疏忽,于是便有了一探究竟的想法。

    DevOps时代
  • 评审的艺术——谈谈现实中的代码评审

    曾经写过一点关于代码评审(code review)的文章,比如这篇和这篇,现在觉得关于它的认识又有了不少更新。软件工程的技术和实践分成两部分,一部分是和书本知识...

    DevOps时代
  • kubernetes 版本多久该升级一次

    kubernetes 社区每三个月发布一个新版本,可以说发布新版本的速度非常快,当然,在生产环境中版本升级的速度可能跟不上新版本发布的速度,那么确保目前使用的...

    田飞雨
  • 第一模块:Python基础(二)

    变量用于存储要在计算机程序中引用和操作的信息。它们的唯一目的是在内存中标记和存储数据。然后可以在整个程序中使用这些数据。变量存储在内存中的值。这就意味着在创建变...

    py3study
  • 数据说云:Oracle Cloud花落腾讯企鹅家

    在今日(11月12日)北京举行的Oracle云技术大会上,甲骨文宣布在中国区和腾讯公司合作,落地Oracle的云数据中心。尽管大家猜测已久,早在年初Oracle...

    数据和云
  • Matlab中libsvm工具箱用PSO优化SVM做回归,训练集结果很好,但测试集结果是一条直线?

    部分代码如下: load data.mat %% % 1. 随机产生训练集和测试集 n = randperm(size(c,2));

    w4979的博客
  • BERT_Paper_Chinese_Translation: BERT论文中文翻译版

    Google发布的论文《Pre-training of Deep Bidirectional Transformers for Language Underst...

    AINLP
  • 生信人的R语言视频教程-语法篇-第十二章:面向对象编程(S3类与S4类)

    面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。早期的计算机编程是基于面向过程的方法,例如实现算术运算2+3+4=9,通过设计...

    DoubleHelix
  • Oracle基础之保留字和关键字

    在Oracle之中,有分为保留字和关键字,所谓关键字就是Oracle中有实际意义的,而保留字(比如DESC、ORDER等等)是Oracle中不能随便使用的,比如...

    用户1208223

扫码关注云+社区

领取腾讯云代金券