使用Istio服务网格进行请求路由和策略管理

编者注:今天,IBM软件工程师Frank Budinsky,Google软件工程师Andra Cismaru和Google产品经理Israel Shalom的帖子是有关Istio的三部分系列文章的第二篇。它提供了有关请求路由和策略管理的详细信息。

在一个 上一篇文章,我们看着 简单应用程序(Bookinfo) 由四个独立的微服务组成。本文展示了如何在不更改任何应用程序代码的情况下使用Kubernetes和启用Istio的集群部署应用程序。本文还概述了如何查看Istio提供的有关正在运行的服务的L7指标。

本文通过使用Bookinfo对Istio进行了更深入的研究。具体来说,我们将介绍Istio的另外两项功能:请求路由和策略管理。

运行Bookinfo应用程序

和以前一样,我们运行Bookinfo应用程序的v1版本。后 安装Istio 在我们的集群中,我们启动在 bookinfo-v1.yaml 使用以下命令:

kubectl apply -f \<(istioctl kube-inject -f bookinfo-v1.yaml)

我们为应用创建了一个Ingress资源:

cat \<\<EOF | kubectl create -f -

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

name: bookinfo

annotations:

    kubernetes.io/ingress.class: "istio"

spec:

rules:

- http:

        paths:

        - path: /productpage

            backend:

                serviceName: productpage

                servicePort: 9080

        - path: /login

            backend:

                serviceName: productpage

                servicePort: 9080

        - path: /logout

            backend:

                serviceName: productpage

                servicePort: 9080

EOF

然后,我们检索了Istio Ingress控制器的NodePort地址:

export BOOKINFO\_URL=$(kubectl get po -n istio-system -l istio=ingress -o jsonpath={.items[0].status.hostIP}):$(kubectl get svc -n istio-system istio-ingress -o jsonpath={.spec.ports[0].nodePort})

最后,我们将浏览器指向 http:// $ BOOKINFO_URL / productpage,以查看正在运行的v1应用程序:

HTTP请求路由

现有的容器编排平台(如Kubernetes,Mesos和其他微服务框架)使操作员可以控制何时一组特定的Pod / VM应接收流量(例如,通过添加/删除特定标签)。与现有技术不同,Istio使流量和基础架构扩展脱钩。这使Istio可以提供驻留在应用程序代码之外的各种流量管理功能,包括动态HTTP 请求路由 用于A / B测试,金丝雀版本,逐步推出, 故障恢复 使用超时,重试,断路器和 故障注入 测试跨服务的故障恢复策略的兼容性。

为了演示,我们将部署 评论 服务并使用Istio使其仅对特定的测试用户可见。我们可以使用以下命令创建一个Kubernetes部署reviews-v2 这个YAML档案:

apiVersion: extensions/v1beta1

kind: Deployment

metadata:

name: 评论-v2

spec:

replicas: 1

template:

    metadata:

        labels:

            app: 评论

            version: v2

    spec:

        containers:

        - name: 评论

            image: istio/examples-bookinfo-reviews-v2:0.2.3

            imagePullPolicy: IfNotPresent

            ports:

            - containerPort: 9080

从Kubernetes的角度来看,v2部署添加了其他Pod,评论服务选择器将其包含在循环负载平衡算法中。这也是Istio的默认行为。

在开始评论:v2之前,我们将启动四个Bookinfo服务评级中的最后一个,v2版本使用该服务来提供与每个评论相对应的评级星号:

kubectl apply -f \<(istioctl kube-inject -f bookinfo-ratings.yaml)

如果我们要开始 评论:v2 现在,我们将看到浏览器响应在v1(无相应评分的评论)和v2(有黑色评分星的评论)之间交替变化。但是,这不会发生,因为我们将使用Istio的流量管理功能来控制流量。

使用Istio,无需根据正在运行的Pod的数量显示新版本。版本可见性由指定确切条件的规则控制。为了进行演示,我们首先使用Istio来指定仅要将100%的评论流量发送到v1窗格。

立即设置默认规则 为每一项服务 在网格中是Istio最佳做法。这样做可以避免意外地看到更新的,可能不稳定的版本。但是,出于演示目的,我们仅将其用于评论服务:

cat \<\<EOF | istioctl create -f -

apiVersion: config.istio.io/v1alpha2

kind: RouteRule

metadata:

  name: 评论-default

spec:

  destination:

      name: 评论

  route:

  - labels:

          version: v1

      weight: 100

EOF

此命令指示服务网格将评论服务的100%流量发送到带有标签“版本:v1”的Pod。有了此规则,我们就可以安全地部署v2版本而不暴露它。

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

刷新Bookinfo网页确认没有任何更改。

在这一点上,我们有各种选择,我们可以如何公开 评论:v2。例如,如果我们要进行简单的Canary测试,则可以使用如下规则将10%的流量发送到v2:

apiVersion: config.istio.io/v1alpha2

kind: RouteRule

metadata:

  name: 评论-default

spec:

  destination:

      name: 评论

  route:

  - labels:

          version: v2

      weight: 10

  - labels:

          version: v1

      weight: 90

对服务版本进行早期测试的一种更好的方法是改为更具体地限制对其的访问。为了演示,我们将设置一条规则,使特定测试用户只能看到评论:v2。为此,我们设置了第二个更高优先级的规则,该规则仅在请求符合特定条件时才适用:

cat \<\<EOF | istioctl create -f -

apiVersion: config.istio.io/v1alpha2

kind: RouteRule

metadata:

name: 评论-test-v2

spec:

destination:

    name: 评论

precedence: 2

match:

    request:

        headers:

            cookie:

                regex: "^(.\*?;)?(user=jason)(;.\*)?$"

route:

- labels:

        version: v2

    weight: 100

EOF

在这里,我们指定请求标头需要包含一个以值“ tester”为条件的用户cookie。如果此规则不匹配,我们将退回到v1的默认路由规则。

如果我们使用用户名“ tester”(无需密码)登录Bookinfo UI,我们现在将看到该应用程序的v2版本(每个评论包括1-5个黑色星级)。每个其他用户都不受此更改的影响。

一旦对v2版本进行了全面测试,我们可以使用Istio使用前面显示的规则进行Canary测试,或者我们可以简单地通过使用一系列规则(可选)以逐步的方式将所有流量从v1迁移到v2重量小于100(例如:10、20、30,... 100)。此流量控制与实现每个版本的Pod数量无关。例如,如果我们具有自动缩放功能和高流量,则可能会同时发生v2的相应放大和v1窗格的相应缩小。有关具有自动缩放功能的版本路由的更多信息,请参阅 “使用Istio的金丝雀部署”.

在本例中,我们将通过一个命令将所有流量发送到v2:

cat \<\<EOF | istioctl replace -f -

apiVersion: config.istio.io/v1alpha2

kind: RouteRule

metadata:

  name: 评论-default

spec:

  destination:

      name: 评论

  route:

  - labels:

          version: v2

      weight: 100

EOF

我们还应该删除为测试人员创建的特殊规则,以使其不会覆盖我们决定做的任何后续部署:

istioctl delete routerule 评论-test-v2

在Bookinfo用户界面中,我们将看到现在向所有用户公开评论的v2版本。

政策执行

Istio提供策略执行功能,例如配额,前提条件检查和访问控制。我们可以举例说明Istio的开放性和可扩展性政策框架,例如速率限制。

我们假设Bookinfo评分服务是一项外部付费服务,例如, 烂番茄®-每秒有1个请求(req / sec)的免费配额。为确保应用程序不超过此限制,我们将指定一个Istio策略,以在达到限制后切断请求。为此,我们将使用Istio的内置策略之一。

要设置1个请求/秒的配额,我们首先配置一个 孟买 有速率限制的处理程序:

cat \<\<EOF | istioctl create -f -

apiVersion: "config.istio.io/v1alpha2"

kind: 孟买

metadata:

name: handler

namespace: default

spec:

quotas:

- name: requestcount.quota.default

    maxAmount: 5000

    validDuration: 1s

    overrides:

    - dimensions:

            destination: ratings

        maxAmount: 1

        validDuration: 1s

EOF

然后我们创建一个 配额 实例,将传入属性映射到配额维度,并创建一个 规则 与它一起使用 孟买 处理程序:

cat \<\<EOF | istioctl create -f -

apiVersion: "config.istio.io/v1alpha2"

kind: 配额

metadata:

name: requestcount

namespace: default

spec:

dimensions:

    source: source.labels["app"] | source.service | "unknown"

    sourceVersion: source.labels["version"] | "unknown"

    destination: destination.labels["app"] | destination.service | "unknown"

    destinationVersion: destination.labels["version"] | "unknown"

---

apiVersion: "config.istio.io/v1alpha2"

kind: 规则

metadata:

name: 配额

namespace: default

spec:

actions:

- 处理程序: handler.memquota

    instances:

    - requestcount.quota

EOF

要查看实际的速率限制,我们将在应用程序上产生一些负载:

wrk -t1 -c1 -d20s http://$BOOKINFO\_URL/productpage

在网络浏览器中,我们会注意到,在负载生成器运行时(即,生成速度超过1 req / sec),浏览器流量将被切断。现在,该页面将显示一条消息,指示当前不可用的评分,而不是每个评论旁边的黑色星星。

停止负载生成器意味着将不再超出限制:刷新页面时,黑色星星将返回。

概要

我们已经向您展示了如何在不重新启动任何服务的情况下将高级功能(例如HTTP请求路由和策略注入)引入由Istio配置的服务网格中。这使您可以开发和部署,而不必担心服务网格的持续管理。以后可以随时添加服务范围的策略。

在本系列的下一期和最后一期中,我们将重点介绍Istio的安全性和身份验证功能。我们将讨论如何在不更改应用程序代码或部署的情况下,确保网状网络中所有服务间通信的安全,甚至防止内部人员访问网络。