第3章 流控............................................................................................................... 1

3.1 更加智能的金丝雀........................................................................................ 1

3.2流量路由...................................................................................................... 2

3.2.1路由到特定版本的部署........................................................................ 3

3.2.2 Recommendation服务v2版本的金丝雀部署........................................... 4

3.2.3 继续加码recommendation服务的v2版本.............................................. 5

3.2.4 基于HTTP头的路由.......................................................................... 6

3.3 暗部署......................................................................................................... 8

3.4对外请求(Egress)..................................................................................... 10

第3章 流控

前面讲过Istio包括一个控制平面和一个数据平面。数据平面由代理组成,代理以边车容器形式和业务容器共存。前面还介绍了“边车”这种代理部署方式,其中每个应用实例都有自己专属的代理,网络流量在到达应用实例之前都会经过该代理。这些边车代理可以独立地配置路由、过滤和扩张网络流量。本章中,我们会介绍利用Istio的各种流控模式。你将发现这些模式其实跟一些大的互联网公司比如Netfilix、Amzaon和Fracebook用的东西差不多。

3.1 更加智能的金丝雀

过去几年中金丝雀部署(canary deployment)概念变得越来越流行。这个名字来自于“煤矿中的金丝雀”概念。过去矿工们常把一只鸟笼中的金丝雀放进矿井中去检测是否有危险气体存在,因为金丝雀比人类对这类气体更加敏感。金丝雀不仅能为矿工们放声歌唱,而且一旦发现有危险气体泄露,矿工们就能迅速逃离矿井。

金丝雀部署也有类似作用。在这种部署模式下,你部署一个新版本代码到生产环境中,但只允许一部分流量访问到它。也许只是测试客户,也许只是组织内部员工,也许只是iOS用户等等。然后你可以监控这个版本的故障、出错、SLA的变化等等。如果这个版本没有问题,那就可以逐步引导更多的流量给到它;如果有问题,那就很容易将它从生产环境中移除。金丝雀部署让你部署更快,而且将可能的有问题代码带来的影响控制到最小。

默认地,Kubernetes提供Service提供轮询负债功能能力。如果你只想为最新代码pod导入10%的网络流量,那么你不得不将新代码pod的数目设置为老代码pod的十分之一。利用Istio,你可以做到更精细的控制。你可以设置只将20%的网络流量导给三个最新代码的pod。Istio还能让你逐渐增加导入给新代码pod的流量,直到所有流量都被导入给它,然后老代码版本就能从生产环境中移除了。

3.2流量路由

使用Istio,你可以设置路由规则(routing rule)来控制流量导入指定pod中。特别地,Istio使用DestionationRule和VirtualServer资源来描述这些规则。下面是一个DestionationRule示例:

apiVersion: networking.istio.io/v1alpha3

    kind: DestinationRule

    metadata:

      name: recommendation

      namespace: tutorial

    spec:

      host: recommendation

      subsets:

      - labels:

          version: v1

        name: version-v1

      - labels:

          version: v2

          name: version-v2

下面是一个VirtualServer示例,它通过一个集合(subset)和权重(weighting factor)来指定流量导入:

apiVersion: networking.istio.io/v1alpha3

    kind: VirtualService

    metadata:

      name: recommendation

      namespace: tutorial

    spec:

      hosts:

      - recommendation

      http:

      - route:

        - destination:

            host: recommendation

            subset: version-v1

            weight: 100

使用此VirtualService定义,你可以配置特定百分比的流量定向到recommendation服务的特定版本上。在上面的例子中,recommendation服务的100%流量将始终流向与标签version:v1匹配的pod。此处Pod的选择方式与Kubernetes基于标签的选择器模型非常相似。因此,服务网格中与recommendation服务进行通信的任何流量都将始终被路由到recommendation服务的v1版本。

上述路由行为不仅仅针对进入流量(ingress trafic)。实际上,可针对所有进入了网格的流量。这适用于网格内的所有服务间通信。如本例所示,这些路由规则适用于可能在服务调用图中的深层服务。如果你将不属于服务网格的服务部署到Kubernetes,它将不会看到这些规则,而会遵循默认的Kubernetes负载平衡规则。

3.2.1路由到特定版本的部署

为了在类似金丝雀部署的场景中展示Istio更复杂的路由能力,我们来部署recommendation服务的v2版本。首先,你要修改recommendation服务的一些源码。修改

com.redhat.developer.demos.recommendation.RecommendationVerticle中的RESPONSE_STRING_FORMAT所定义的字符串为“v2”:

private static final String RESPONSE_STRING_FORMAT = "recommendation v2 from '%s': %d\n";

然后再编译和打包新代码为v2版本:

cd recommendation/java/vertx

mvn clean package

docker build -t example/recommendation:v2 .

你可以执行jar文件以快速测试代码修改:

java -jar target/recommendation.jar

然后你在另一个中断中运行下面的curl命令:

curl localhost:8080

recommendation v2 from 'unknown': 1

最后,注入Istio边车代理并部署到Kubernetes中:

oc apply -f <(istioctl kube-inject -f  ../../kubernetes/Deployment-v2.yml) -n tutorial

现在,你可以运行oc get pods命令去查看pod。如果所有pod都成功运行的话,会是下面这样子:

NAME                    READY STATUS  RESTARTS     AGE

customer-3600192384-fpljb      2/2     Running   0          17m

preference-243057078-8c5hz     2/2     Running   0          15m

recommendation-v1-60483540     2/2    Running   0          12m

recommendation-v2-99634814     2/2    Running   0          15s

现在,运行curl访问customer服务端点,就会看到流量在两个recommendation版本中做负载均衡。你会看到下面这样子:

#!/bin/bash

    while true

    do curl customer-tutorial.$(minishift ip).nip.io

    sleep .1

    done

    customer => preference => recommendation v1 from '60483540': 29

    customer => preference => recommendation v2 from '99634814': 1

    customer => preference => recommendation v1 from '60483540': 30

    customer => preference => recommendation v2 from '99634814': 2

    customer => preference => recommendation v1 from '60483540': 31

    customer => preference => recommendation v2 from '99634814': 3

现在,创建DestionalRule和VirtualService实例来将所有流量导入recommendation服务的v1版本。你要转到源代码的根目录,进入istio-tutorial目录,运行下面的命令:

oc -n tutorial create -f istiofiles/destination-rule-recommendation-v1-v2.yml

oc -n tutorial create -f istiofiles/virtual-service-recommendation-v1.yml

现在,运行curl命令去访问customer服务的话,你会看到流量全部被导到了v1版本:

customer => preference => recommendation v1 from '60483540': 32

customer => preference => recommendation v1 from '60483540': 33

customer => preference => recommendation v1 from '60483540': 34

VirtualService已经创建了到由DesetionationRule指定的目标子集的路由,子集中只有recommendation服务的v1版本。

3.2.2 Recommendation服务v2版本的金丝雀部署

现在,所有访问流量都被导向recommendation服务的v1版本。你可以使用创建一个VirtualService实例来进行金丝雀部署:

apiVersion: networking.istio.io/v1alpha3

    kind: VirtualService

    metadata:

      name: recommendation

      namespace: tutorial

    spec:

      hosts:

      - recommendation

      http:

      - route:

        - destination:

            host: recommendation

            subset: version-v1

          weight: 90

        - destination:

            host: recommendation

            subset: version-v2

          weight: 10

这个VirtualService实例指定90%的流量被导向v1版本,10%的流量被导向v2版本。现在,使用这个VirtualService实例来覆盖之前的实例,使用下面的命令:

oc -n tutorial replace -f istiofiles/virtual-service-recommendation-v1_and_v2.yml

现在,使用curl命令访问customer服务的话,只有10%的流量被导向recommendation服务的v2版本。V2就是一个金丝雀版本。监控其日志、指标和跟踪系统来查看这个版本有没有引入任何错误或非期望的行为到你的环境中。

3.2.3 继续加码recommendation服务的v2版本

现在,如果没有任何不期望的事情发生,你对recommendation服务的v2版本的信心会大一些了。你可能会想往v2版本导入更多的流量。此时,你只需要将如下VirtualService定义替换已有的:

apiVersion: networking.istio.io/v1alpha3

    kind: VirtualService

    metadata:

      name: recommendation

      namespace: tutorial

    spec:

      hosts:

      - recommendation

      http:

      - route:

        - destination:

            host: recommendation

            subset: version-v1

          weight: 50

        - destination:

            host: recommendation

            subset: version-v2

          weight: 50

使用这个VirtualService实例后,各有50%的流量会被导向v1和v2版本。要应用该配置,只需要运行下面的命令:

oc -n tutorial replace –f istiofiles/virtual-service-recommendation-v1_and_v2_50_50.yml

运行成功后,你会看到流量行为的变化,一半流量被导向了v2版本,另一半到v2版本。输出类似下面这样子:

customer => ... => recommendation v1 from '60483540': 192

customer => ... => recommendation v2 from '99634814': 37

customer => ... => recommendation v2 from '99634814': 38

customer => ... => recommendation v1 from '60483540': 193

customer => ... => recommendation v2 from '99634814': 39

customer => ... => recommendation v2 from '99634814': 40

最后,如果一切正常的话,你可将所有流量导向v2版本,只需应用下面的VirtualService实例:

apiVersion: networking.istio.io/v1alpha3

    kind: VirtualService

    metadata:

      name: recommendation

      namespace: tutorial

    spec:

      hosts:

      - recommendation

      http:

      - route:

        - destination:

            host: recommendation

            subset: version-v2

            weight: 100

现在,你会看到所有流量被导向v2版本:

customer => preference => recommendation v2 from '99634814': 43

customer => preference => recommendation v2 from '99634814': 44

customer => preference => recommendation v2 from '99634814': 45

customer => preference => recommendation v2 from '99634814': 46

customer => preference => recommendation v2 from '99634814': 47

customer => preference => recommendation v2 from '99634814': 48

在继续下面的步骤前,要恢复到默认流量路由行为,运行下面的命令删除recommendation服务的VirtualService实例即可,然后你会看到Kubernetes自己的轮询负载均衡效果:

oc delete virtualservice/recommendation -n tutorial

  

3.2.4 基于HTTP头的路由

前面介绍了Istio基于服务的元数据所做的细粒度路由控制。你还可以用Istio基于请求的元数据进行控制。比如,你可以使用匹配原语去创建基于请求的特定路由规则。比如,你想基于请求的地域、移动设备或者浏览器去将部分流量导向特定服务。我们来看下如何利用Istio做到这些。使用Istio,你可以在VirtualService中设置匹配规则。例如下面的VirtualService定义:

apiVersion: networking.istio.io/v1alpha3

    kind: VirtualService

    metadata:

      creationTimestamp: null

      name: recommendation

      namespace: tutorial

spec: hosts:

      - recommendation

      http:

      - match:

        - headers:

            baggage-user-agent:

              regex: .*Safari.*

        route:

        - destination:

            host: recommendation

            subset: version-v2

      - route:

        - destination:

            host: recommendation

            subset: version-v1

这条规则匹配HTTP请求头,只将由“Safari”浏览器发起的请求导入recommendation服务的v2版本。运行下面的命令以安装这条规则:

oc -n tutorial create -f istiofiles/virtual-service-safari-recommendation-v2.yml

然后试一下:

curl customer-tutorial.$(minishift ip).nip.io

customer => preference => recommendation v1 from '60483540': 465

如果在curl命令中添加“user-agent:Safari”头,那么访问会被导向v2版本:

curl -H 'User-Agent: Safari' customer-tutorial.$(minishift ip).nip.io

customer => preference => recommendation v2 from '99634814': 318

如果用Firefox浏览器,那该访问会被导向v1版本:

curl -A Firefox customer-tutorial.$(minishift ip).nip.io

customer => preference => recommendation v1 from '60483540': 465

  

注意:如果你使用真实的浏览器进行测试,请注意在macOS系统上Chome浏览器会被识别为Safari。

Istio的DestiontionRule和VirtualService对象是使用CRD定义的,你可以象使用Kubernetes原生对象类型(比如Deployment、Pod、Service等)一样去使用它们。运行下面的命令去获取跟recommendation有关的Istio对象:

oc get crd | grep virtualservice

kubectl describe destinationrule recommendation -n tutorial

oc get virtualservice recommendation -o yaml -n tutorial

注意:基本上oc和kubectl两个命令可以交替使用,因为oc是kubectl的一个超级,它多了一些跟login、project和new-app相关的命令,这些命令弥补了原生Kubernetes的一些不足。

继续下面的步骤前,请使用下面的命令去清理所安装的Istio对象:

oc delete virtualservice recommendation -n tutorial

oc delete destinationrule recommendation -n tutorial

  

3.3 暗部署

暗部署(Dark Launch)对不同的人有不同的含义。本质上,暗部署是对客户不可见的一种生产系统的部署。此时,Istio允许你复制或镜像流量到应用的新版本中,然后将其行为与在线应用的行为进行对比。这种方式允许你将生产品质的请求导向新服务,同时不影响生产环境。

例如,recommendation的v1版本是生产环境,而v2版本是新部署环境。可使用Istio将到v1的浏览镜像到v2。但Istio做浏览镜像时,它采用“触发并忘记”(fire-and-forget)模式。其含义是,Istio会做生产浏览的异步镜像,将被镜像的请求发往测试pod,因此不用担心它会返回什么。我们来尝试下。

首先,请确保环境中没有DeistionationRule和VirtualService实例存在:

oc get destinationrules -n tutorial

No resources found.

oc get virtualservices -n tutorial

No resources found.

我们来看下配置浏览镜像的VirtualService定义:

apiVersion: networking.istio.io/v1alpha3

    kind: VirtualService

    metadata:

      name: recommendation

      namespace: tutorial

    spec:

      hosts:

      - recommendation

      http:

      - route:

        - destination:

            host: recommendation

            subset: version-v1

        mirror:

          host: recommendation

          subset: version-v2

该定义中,所有流量被导向recommendation服务的v1版本,在mirror部分,指定了接受镜像流量的host和subset。

然后,转到从Istio Tutorial克隆下来的代码的根目录,运行下面的命令:

oc -n tutorial create -f istiofiles/destination-rule-recommendation-v1-v2.yml

oc -n tutorial create -f istiofiles/virtual-service-recommendation-v1-mirror-v2.yml

在终端中,输出recommendation服务v2版本pod的日志:

oc -n tutorial logs -f `oc get pods|grep recommendation-v2|awk  '{ print $1 }'` -c recommendation

你也可以使用stern去查看recommendation服务的v1和v2版本pod的日志:

stern recommendation

在另一个窗口中,用curl访问customer服务:

curl customer-tutorial.$(minishift ip).nip.io

customer => preference => recommendation v1 from '60483540': 466

从输出中,你能看到recommendation服务的v1版本被访问到了。再查看v2版本pod的日志,你会看到该服务处理进行流量所产生的日志条目。

流量镜像对于发布前的测试会有很大帮助,但是还是有一些挑战。比如,一个服务的新版本可能会访问数据库或其它关联服务。要进行微服务中的数据处理,建议你阅读Edson Yanaga所写的Migrating to Microservice Databases(O’Reilly)一书。要了解流量镜像更多的细节,可阅读Christian的博文“Advanced Traffic-Shadowing Patterns for Microservices with Istio Service Mesh” (https://blog.christianposta.com/microservices/advanced-traffic-shadowing-patterns-for-microservices-with-istio-service-mesh/)。

请记得在继续后面的步骤前删除DestionationRule和VirtualService实例:

oc delete virtualservice recommendation -n tutorial

oc delete destinationrule recommendation -n tutorial

  

3.4对外请求(Egress)

默认地,服务的所有流量都会通过Istio代理,代理和应用服务部署在一起。这个代理负责校验路由规则,决定如何转发请求。Istio很好的一点是它默认阻止所有发到集群外的请求流量,除非显式创建规则去允许这种访问。因此,你可以在不信任网络和传统私有云环境中使用Istio。这些场景中,Istio会帮助阻止恶意代理访问应用服务进而获得网络的完全访问权限。通过默认阻止对外访问请求,并允许利用路由规则去控制内外部流量,你可以更从容地应对外面攻击,不管它们是从哪里发起的。

要进行测试验证,可以进入一个pod,然后用curl发起请求:

oc get pods -n tutorial

    NAME                   READY  STATUS    RESTARTS  AGE

    customer-6564ff969f-jqkkr       2/2    Running   0         19m

    preference-v1-5485dc6f49-hrlxm  2/2    Running   0         19m

    recommendation-v1-60483540      2/2    Running   0         20m

    recommendation-v2-99634814      2/2    Running   0         7m

    oc exec -it recommendation-v2-99634814 /bin/bash

    [jboss@recommendation-v2-99634814 ~]$ curl -v now.httpbin.org

    * About to connect() to now.httpbin.org port 80 (#0)

    *   Trying 54.174.228.92...

    * Connected to now.httpbin.org (54.174.228.92) port 80 (#0)

    > GET / HTTP/1.1

    > User-Agent: curl/7.29.0

    > Host: now.httpbin.org

    > Accept: */*

    >

    < HTTP/1.1 404 Not Found

    < date: Sun, 02 Dec 2018 20:01:43 GMT

    < server: envoy

    < content-length: 0

    <

    * Connection #0 to host now.httpbin.org left intact

    [jboss@recommendation-v2-99634814 ~]$ exit

结果你会从now.httpbin.org收到404 NOT Found错误信息。要能正常访问,你需要定义一个ServiceEntry实例,下面这个正是我们将要应用的:

apiVersion: networking.istio.io/v1alpha3

    kind: ServiceEntry

    metadata:

      name: httpbin-egress-rule

      namespace: tutorial

    spec:

      hosts:

      - now.httpbin.org

      ports:

      - name: http-80

        number: 80

        protocol: http

首先你要创建DesionationRule实例,然后应用ServiceEntry实例:

oc -n tutorial create -f istiofiles/destination-rule-recommendation-v1-v2.yml

oc -n tutorial create -f istiofiles/service-entry-egress-httpbin.yml -n tutorial

现在,你再进入pod,运行curl后你会得到200返回:

oc exec -it recommendation-v2-99634814 /bin/bash

[jboss@recommendation-v2-99634814 ~]$ curl now.httpbin.org

{"now": {"epoch": 1543782418.7876487...

你可以列表所有出口规则:

oc get serviceentry -n tutorial

SERVICE-ENTRY NAME    HOSTS      PORTS     NAMESPACE  AGE

httpbin-egress-rule   now.httpbin.org  http/80   tutorial   5m

最后,清理所有Istio实例,回到默认的Kubernetes行为:

oc delete serviceentry httpbin-egress-rule -n tutorial

oc delete virtualservice recommendation -n tutorial

oc delete destinationrule recommendation -n tutorial

本章中的这些示例都很简单,但都是你探索Istio流控功能的一个良好的起点。

书籍英文版下载链接为 https://developers.redhat.com/books/introducing-istio-service-mesh-microservices/,作者 Burr Sutter 和 Christian Posta

本中文译稿版权由本人所有。水平有限,错误肯定是有的,还请海涵。

感谢您的阅读,欢迎关注我的微信公众号:

【译文连载】 理解Istio服务网格(第三章 流控)的更多相关文章

  1. 【译文连载】 理解Istio服务网格(第一章 概述)

    书籍英文版下载链接为 https://developers.redhat.com/books/introducing-istio-service-mesh-microservices/,作者 Burr ...

  2. 【译文连载】 理解Istio服务网格(第二章 安装)

    全书目录 第一章 概述 本文目录 1.命令行工具安装 2. Kubernetes/OpenShift安装 3. Istio安装 4.示例Java微服务安装 4.1 源码概览 4.2 编译和部署cust ...

  3. 【译文连载】 理解Istio服务网格(第六章 可观测性)

    全书目录 第一章 概述 第二章 安装 第三章 流控 第四章 服务弹性 第五章 混沌测试 ​本文目录 第6章 可观测性 6.1 分布式调用链跟踪(tracing) 6.1.1 基本概念 6.1.2 Ja ...

  4. 【译文连载】 理解Istio服务网格(第七章 安全)

    全书目录 第一章 概述 第二章 安装 第三章 流控 第四章 服务弹性 第五章 混沌测试 第六章 可观测性 本文目录 第7章 安全 7.1 身份认证 7.1.1 Kubernetes上的Istio的身份 ...

  5. 【连载】微服务网格Istio(一)

    Istio基础 服务网格是用于描述构成应用程序的微服务网络以及应用之间的交互,服务网格的功能包括服务发现.负载均衡.故障恢复.指标和监控以及更加复杂的运维工作,例如A/B测试.金丝雀发布.限流.访问控 ...

  6. Istio最佳实践:在K8s上通过Istio服务网格进行灰度发布

    Istio是什么? Istio是Google继Kubernetes之后的又一开源力作,主要参与的公司包括Google,IBM,Lyft等公司.它提供了完整的非侵入式的微服务治理解决方案,包含微服务的管 ...

  7. Istio(十一):向istio服务网格中引入虚拟机

    目录 一.模块概览 二.系统环境 三.虚拟机负载 3.1 虚拟机负载 3.2 单网络架构 3.3 多网络架构 3.4 Istio 中如何表示虚拟机工作负载? 四.实战:向istio Mesh中引入虚拟 ...

  8. 初识 Istio - 服务网格管理工具

    What is a service mesh(服务网格)? 微服务在国内流行已经多年了,大多数公司选择了基于容器化技术( Docker )以及容器编排管理平台 ( Kubernetes )落地微服务 ...

  9. ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇

    原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇 第三章 为控件添加事件 后篇 前一篇文章只是简单的说了下事件,但是大家应该方法,在ASP.NET自定义控件中只是简单那么定义事件是 ...

随机推荐

  1. SpringBoot系列之集成Dubbo的方式

    SpringBoot系列之集成Dubbo的方式 本博客介绍Springboot框架集成Dubbo实现微服务的3种常用方式,对于Dubbo知识不是很熟悉的,请先学习我上一篇博客:SpringBoot系列 ...

  2. ubuntu频繁死机--独立显卡问题

    问题:笔记本安装ubuntu时以及装好后有时会出现花屏.死机的问题,系统报错 *ERROR* UVD not responding, trying to reset the VCPU!!! *ERRO ...

  3. 一些常用查询SQL语句以及显示格式

    1.查询当前年.月.周相关时间 1.1.查询当前年份 SELECT TO_CHAR(SYSDATE,'YYYY') AS YEAR FROM DUAL--查询当前年份 SELECT TO_CHAR(S ...

  4. c++快读与快输模板

    快读 inline int read() { ; ; char ch=getchar(); ; ch=getchar();} )+(X<<)+ch-'; ch=getchar();} if ...

  5. 曹工说Spring Boot源码(11)-- context:component-scan,你真的会用吗(这次来说说它的奇技淫巧)

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  6. 自定义博客cnblogs样式的必备前端小知识——js、jq

    JQ.JS相关小知识 任意元素自动点击 $(".editicon").trigger('click') 添加子元素 append() - 在被选元素的结尾插入内容 prepend( ...

  7. WingIDE注册破解方法 CalcActivationCode.py

    1) 安装WingIDE成功后启动,激活时输入license id CN123-12345-12345-12345 2) 点击Continue后弹框,拷贝框中的request code 3) 修改Py ...

  8. 如何利用Serilog的RequestLogging来精简ASP.NET Core的日志输出

    这是该系列的第一篇文章:在ASP.NET Core 3.0中使用Serilog.AspNetCore. 第1部分-使用Serilog RequestLogging来简化ASP.NET Core的日志输 ...

  9. Nginx. 用http访问https跨域

    用http 访问 https域名, 报跨越问题 解决方法: 在nginx相应服务的转发配置下添加: add_header 'Access-Control-Allow-Origin' 'http://i ...

  10. PHP——常量

    一.什么是常量 常量可以理解为值不变的量(如圆周率)或者是常量值被定义后,在脚本的其他任何地方都不可以被改变.PHP中的常量分为自定义常量和系统常量,自定义常量是根据我们开发的需要,而定义的常量,它通 ...