如何处理服务网格中的重大更改

问题描述

我正在使用Kubernetes构建示例微服务应用程序,以找出最佳方案和未来项目的一些模式。我正在使用Istio作为服务网格来处理东西向的流量,并且我对概念(VirtualServices,DestinationRules等)有基本的了解。服务网格使我能够轻松推出微服务的新版本并将流量重定向到新实例(例如使用加权分配)。考虑到语义版本控制,这对于PatchMinor更新确实非常有效,因为从理论上讲,它们不会更改现有合同,因此可以替代现有合同服务。现在,我想知道如何正确处理服务的重大更改,因此进行了Major版本的更新。

很难找到关于此的信息,但是由于我得到的信息有限,我现在正在考虑两种方法

  1. 服务的每个主要版本(例如user-service)都有自己的VirtualService,以便客户端可以正确地寻址(通过不同的服务名称,例如user-service-v1)。然后,使用Istio将主要版本(例如1.*)的流量正确路由到其他可用服务(例如user-service v1.3.1user-service v1.4.0)。

  2. 我为特定的微服务总共使用了VirtualService(例如user-service)。 VirtualService包含许多要使用的路由定义,例如客户端发送的标头(例如x-major-version=1),以将请求与目标匹配。

总体而言,两种方法之间没有太大差异。显然,客户端需要通过设置标头或解析其他服务名称来指定要与哪个主要版本通信。所描述的方法是否存在任何局限性?还是我完全没有其他选择?任何帮助和指示,我们将不胜感激!

解决方法

TLDR

除了我在评论中提到的内容外,在对该主题进行了更详细的检查之后,我会选择方法2 ,为特定的微服务选择一个整体虚拟服务 > canary部署镜像

方法1

documentation

中所述

在单个VirtualService或DestinationRule资源中为特定主机定义完整的路由规则或策略集的情况下,最好在多个资源中递增地指定主机的配置。如果将它们绑定到网关,飞行员将合并这些目标规则并合并这些虚拟服务。

因此,在理论中,您可以采用方法1,但是我想说的是太多的配置,并且有更好的主意。

假设您有名称为v1.3.1的旧应用程序和名称为v1.4.0的新应用程序,因此适当的虚拟服务如下所示。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-vervice1
spec:
  hosts:
  - '*'
  http:
  - name: "v1.3.1"
    route:
    - destination:
        host: service1.namespace.svc.cluster.local

---

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-service2
spec:
  hosts:
  - '*'
  http:
  - name: "v1.4.0"
    route:
    - destination:
        host: service2.namespace.svc.cluster.local

方法2

实践中,我将采用方法2,例如,您可以创建2个版本的应用,在下面的示例中,分别为oldnew,然后 为其配置虚拟服务和目标规则。

这里的问题是,为什么?因为它更易于管理(至少对我而言),并且在此处易于使用canary部署和镜像,请参见下文。

假设您部署了新的应用程序,那么您将不会在此处发送1%的传入流量,此外,您还可以使用镜像,因此发往旧服务的每个请求都将被镜像到新服务以进行测试。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-vervice
spec:
  hosts:
  - '*'
  http:
  - name: "old"
    route:
    - destination:
        host: service.namespace.svc.cluster.local
        subset: v1
      weight: 99
    mirror:
      host: service.namespace.svc.cluster.local
      subset: v2
    mirror_percent: 100
  - name: "new"
    route:
    - destination:
        host: service.namespace.svc.cluster.local
        subset: v2
      weight: 1

---


apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews-destination
spec:
  host: service.namespace.svc.cluster.local
  subsets:
  - name: v1
    labels:
      version: v1  <--- label on old pod
  - name: v2
    labels:
      version: v2  <--- label on new pod

测试新应用程序

客户显然需要通过设置标头或通过解析其他服务名称来指定他要使用的主要版本。

实际上,这取决于配置,如果您将以上选项与newold版本一起使用,则这就是金丝雀部署,例如加权分布,用于。您可以指定应发送到应用程序新版本的流量百分比。当然,您可以在虚拟服务中指定标头或前缀,以便用户可以使用旧版本或新版本的应用程序。

金丝雀部署

如上所述here

Istio项目的好处之一是,它提供了部署金丝雀服务所需的控制。金丝雀部署(或推出)背后的想法是引入一种新版本的服务,方法是首先使用一小部分用户流量对其进行测试,然后,如果一切顺利,则在逐步淘汰该百分比的同时逐步增加(可能会逐步增加)旧版本。如果在此过程中出现任何问题,我们将中止并回滚到以前的版本。以最简单的形式,发送到canary版本的流量是随机选择的请求百分比,但在更复杂的方案中,流量可以基于请求的区域,用户或其他属性。

根据您在该领域的专业水平,您可能想知道为什么还需要Istio对Canary部署的支持,因为Kubernetes等平台已经提供了进行版本发布和Canary部署的方法。问题解决了吧?好吧,不完全是。尽管以这种方式进行推广在简单的情况下是可行的,但它非常有限,尤其是在需要大量(特别是数量不同)流量且需要自动扩展的大规模云环境中。

istio

使用Istio,流量路由和副本部署是两个完全独立的功能。实施服务的Pod数量可以根据流量负载自由扩展和缩小,完全与版本流量路由的控制正交。这使得在存在自动缩放比例的情况下管理金丝雀版本变得简单得多。实际上,自动定标器可以响应因流量路由更改而导致的负载变化,但是它们仍独立运行,与负载因其他原因而变化时没有什么不同。

Istio的路由规则还具有其他重要优势;您可以轻松控制细粒度的流量百分比(例如,将流量的1%路由而不需要100个Pod),并且可以使用其他条件控制流量(例如,将特定用户的流量路由到canary版本)。为了说明这一点,让我们看一下部署helloworld服务,看看问题变得多么简单。

有一个example

镜像

经常用于测试应用程序新版本的第二件事是流量镜像。

如上所述here

使用Istio,您可以使用流量镜像将流量复制到另一个服务。您可以将流量镜像规则纳入金丝雀部署管道的一部分,从而可以在向其发送实时流量之前分析服务的行为。

如果您正在寻找最佳实践,我建议从中等水平开始使用此tutorial,因为这里对此有很好的解释。

流量镜像的工作原理

流量镜像按以下步骤工作:

  • 您部署该应用程序的新版本并打开流量 镜像。

  • 旧版本像以前一样响应请求,但还会向新版本发送异步副本。

  • 新版本处理流量,但不响应用户。

  • 操作团队将监视新版本,并向开发团队报告所有问题。

enter image description here

当应用程序处理实时流量时,它可以帮助团队发现在生产前环境中通常不会发现的问题。您可以使用Prometheus和Grafana等监视工具来记录和监视测试结果。

此外,还有一个有关nginx的示例,完美地展示了它应该如何工作。

值得一提的是,如果您使用订单或付款之类的写API,那么镜像流量将意味着多次写订单之类的写API。克里斯蒂安·波斯塔({@ 3)}对这个主题进行了详细的描述。


让我知道您还有什么要讨论的。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...