灰度发布(又名金丝雀发布)介绍api
当应用上线之后,运维面临的一大挑战是如何可以在不影响已上线业务的状况下进行升级。作过产品的同窗都清楚,无论在发布前作过多么完备的自动化和人工测试,在发布后都会出现或多或少的故障。根据墨菲定律,可能会出错的版本发布必定会出错。浏览器
“ANYTHING THAN CAN GO WRONG WILL GO WRONG” –MURPHY’S LAW服务器
所以咱们不能寄但愿于在线下测试时发现全部潜在故障。在没法百分百避免版本升级故障的状况下,须要经过一种方式进行可控的版本发布,把故障影响控制在能够接受的范围内,并能够快速回退。cookie
能够经过灰度发布(又名金丝雀发布)来实现业务从老版本到新版本的平滑过渡,并避免升级过程当中出现的问题对用户形成的影响。网络
“金丝雀发布”的来源于矿工们用金丝雀对矿井进行空气测试的作法。之前矿工挖煤的时候,矿工下矿井前会先把金丝雀放进去,或者挖煤的时候一直带着金丝雀。金丝雀对甲烷和一氧化碳浓度比较敏感,会先报警。因此你们都用“金丝雀”来搞最早的测试。app
下图中,左下方的少部分用户就被看成“金丝雀”来用于测试新上线的1.1版本。若是新版本出现问题,“金丝雀”们会报警,但不会影响其余用户业务的正常运行。运维
灰度发布(金丝雀发布)的流程以下:ide
准备和生产环境隔离的“金丝雀”服务器。微服务
将新版本的服务部署到“金丝雀”服务器上。测试
对“金丝雀”服务器上的服务进行自动化和人工测试。
测试经过后,将“金丝雀”服务器链接到生产环境,将少许生产流量导入到“金丝雀”服务器中。
若是在线测试出现问题,则经过把生产流量从“金丝雀”服务器中从新路由到老版本的服务的方式进行回退,修复问题后从新进行发布。
若是在线测试顺利,则逐渐把生产流量按必定策略逐渐导入到新版本服务器中。
待新版本服务稳定运行后,删除老版本服务。
从上面的流程能够看到,若是要实现一套灰度发布的流程,须要应用程序和运维流程对该发布过程进行支持,工做量和难度的挑战是很是大的。虽然面对的问题相似,但每一个企业或组织通常采用不一样的私有化实现方案来进行灰度发布,为解决该问题致使研发和运维花费了大量的成本。
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版本的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服务前,须要先建立一条缺省路由规则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,以下图所示:
在进行模拟测试时,因为测试环境和生产环境的网络,服务器,操做系统等环境存在差别,很难彻底模拟生产环境进行测试。为了减小环境因素的对测试结果的影响,咱们但愿能在生产环境中进行上线前的测试,但若是没有很好的隔离措施,可能会致使测试影响已上线的业务,对企业形成损失。
经过采用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版本的服务中,进行小规模的“金丝雀”测试。
修改规则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版本。
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版本故障修复后再进行测试。
待V2版本上线稳定运行后,删除V1版本的reviews服务和测试规则。
kubectl delete pod reviews-v1-1360980140-0zs9z istioctl delete -f route-rule-test-reviews-v2.yaml -n default