简介 Istio v1alpha3 路由 API

Istio v1alpha3 路由 API 的介绍、动机和设计原则。

2018 年 4 月 25 日 | 作者:Frank Budinsky - IBM 和 Shriram Rajagopalan - VMware

到目前为止,Istio 提供了一个简单的 API 用于使用四个配置资源进行流量管理:RouteRuleDestinationPolicyEgressRule 和(Kubernetes)Ingress。使用此 API,用户可以轻松管理 Istio 服务网格中的流量流。API 允许用户将请求路由到服务的特定版本,注入延迟和故障以进行弹性测试,添加超时和断路器,等等,所有这些都无需更改应用程序代码本身。

虽然此功能已被证明是 Istio 的一个非常引人注目的部分,但用户反馈也表明此 API 确实存在一些缺点,特别是在使用它来管理包含数千个服务的非常大的应用程序时,以及在处理 HTTP 以外的协议时。此外,使用 Kubernetes Ingress 资源配置外部流量已被证明远远不能满足我们的需求。

为了解决这些问题以及其他问题,引入了新的流量管理 API,也称为 v1alpha3,它将完全取代之前的 API。虽然 v1alpha3 模型在根本上是相同的,但它与以前的版本不兼容,需要手动从旧 API 转换。

为了证明这种中断的合理性,v1alpha3 API 经过了漫长而艰苦的社区评审过程,希望最终能得到一个大大改进的 API,能够经受时间的考验。在本文中,我们将介绍新的配置模型,并尝试解释影响它的某些动机和设计原则。

设计原则

一些关键设计原则在路由模型重新设计中发挥了作用

v1alpha3 中的配置资源

典型的网格将有一个或多个负载均衡器(我们称它们为网关),这些负载均衡器从外部网络终止 TLS 并允许流量进入网格。然后,流量通过旁路网关流经内部服务。应用程序通常也会使用外部服务(例如,Google 地图 API)。这些服务可以直接调用,或者在某些部署中,所有从网格传出的流量都可能被强制通过专用的出口网关。下图描述了这种思维模型。

Role of gateways in the mesh
Istio 服务网格中的网关

考虑到上述设置,v1alpha3 引入了以下新的配置资源来控制流量路由进出网格以及网格内流量路由。

  1. 网关
  2. 虚拟服务
  3. 目标规则
  4. 服务条目

VirtualServiceDestinationRuleServiceEntry 分别替换 RouteRuleDestinationPolicyEgressRuleGateway 是一个平台无关的抽象概念,用于对流入专用中间件的流量进行建模。

下图描述了跨配置资源的控制流。

Relationship between different v1alpha3 elements
不同 v1alpha3 元素之间的关系

网关

一个 Gateway 为 HTTP/TCP 流量配置负载均衡器,无论它将在哪里运行。网格内可以存在任意数量的网关,并且多个不同的网关实现可以共存。事实上,可以通过在配置中指定一组工作负载(Pod)标签将网关配置绑定到特定工作负载,从而允许用户通过编写简单的网关控制器来重用现成的网络设备。

对于入口流量管理,您可能会问:为什么不重用 Kubernetes Ingress API 呢?Ingress API 被证明无法表达 Istio 的路由需求。通过尝试在不同的 HTTP 代理之间找到一个共同点,Ingress 只能支持最基本的 HTTP 路由,最终将现代代理的每一个其他功能都推送到不可移植的注释中。

Istio Gateway 通过将 L4-L6 规范与 L7 分开,克服了 Ingress 的缺点。它只配置所有好的 L7 代理都统一实现的 L4-L6 功能(例如,要公开的端口、TLS 配置)。然后,用户可以使用标准 Istio 规则来控制 HTTP 请求以及通过将 VirtualService 绑定到它来进入 Gateway 的 TCP 流量。

例如,以下简单的 Gateway 配置了一个负载均衡器,允许外部 https 流量为主机 bookinfo.com 流入网格

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  servers:
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
    - bookinfo.com
    tls:
      mode: SIMPLE
      serverCertificate: /tmp/tls.crt
      privateKey: /tmp/tls.key

要配置相应的路由,必须为相同主机定义 VirtualService(在 下一节 中描述),并使用配置中的 gateways 字段将其绑定到 Gateway

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
    - bookinfo.com
  gateways:
  - bookinfo-gateway # <---- bind to gateway
  http:
  - match:
    - uri:
        prefix: /reviews
    route:
    ...

Gateway 可用于对边缘代理或纯内部代理进行建模,如第一张图所示。无论位置如何,所有网关都可以以相同的方式配置和控制。

虚拟服务

用称为“虚拟服务”的东西替换路由规则乍一看可能很奇怪,但实际上,它对于正在配置的内容来说是一个更好的名字,尤其是在重新设计 API 以解决之前模型的可扩展性问题之后。

实际上,变化在于,我们不再使用一组针对特定目标服务的独立配置资源(规则)来配置路由,每个规则都包含一个优先级字段来控制评估顺序,而是现在配置(虚拟)目标本身,它包含所有与之关联的规则,这些规则以一个有序列表的形式排列在一个相应的 VirtualService 资源中。例如,之前我们对 Bookinfo 应用程序的 reviews 服务有两种 RouteRule 资源,如下所示

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

v1alpha3 中,我们在单个 VirtualService 资源中提供相同的配置

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - match:
    - headers:
        cookie:
          regex: "^(.*?;)?(user=jason)(;.*)?$"
    route:
    - destination:
        host: reviews
        subset: v2
  - route:
    - destination:
        host: reviews
        subset: v1

如您所见,reviews 服务的所有规则都集中在一个地方,这乍一看可能看起来更好或更糟。但是,如果您仔细观察这个新模型,您会发现它存在一些根本区别,使 v1alpha3 功能更强大。

首先,请注意,VirtualService 的目标服务使用 hosts 字段(实际上是重复字段)指定,然后在每个路由规范的 destination 字段中再次指定。这是与之前模型的一个非常重要的区别。

VirtualService 描述了从一个或多个用户可寻址的目标到网格内部实际目标工作负载之间的映射。在我们的示例中,它们是相同的,但是,用户可寻址的主机可以是任何 DNS 名称,带有可选的通配符前缀或 CIDR 前缀,这些名称将用于寻址服务。这在促进将单体应用转变为由不同微服务组成的复合服务方面尤其有用,而无需要求服务的使用者适应这种转变。

例如,以下规则允许用户像寻址 Bookinfo 应用程序的 reviewsratings 服务一样寻址它们,就好像它们是 http://bookinfo.com/ 中更大(虚拟)服务的一部分一样

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
    - bookinfo.com
  http:
  - match:
    - uri:
        prefix: /reviews
    route:
    - destination:
        host: reviews
  - match:
    - uri:
        prefix: /ratings
    route:
    - destination:
        host: ratings
  ...

VirtualService 的主机实际上不必是服务注册表的一部分,它们只是虚拟目标。这允许用户为没有可路由条目在网格内的虚拟主机建模流量。这些主机可以通过将 VirtualService 绑定到相同主机的 Gateway 配置来在网格外部公开(如 上一节 中所述)。

除了这种根本性重组之外,VirtualService 还包含其他一些重要的更改

  1. 可以在 VirtualService 配置内部表达多个匹配条件,从而减少对冗余规则的需求。

  2. 每个服务版本都有一个名称(称为服务子集)。属于子集的 Pod/VM 集在 DestinationRule 中定义,这将在下一节中介绍。

  3. VirtualService 主机可以使用通配符 DNS 前缀来为所有匹配的服务创建单个规则。例如,在 Kubernetes 中,要对 foo 命名空间中的所有服务应用相同的重写规则,VirtualService 将使用 *.foo.svc.cluster.local 作为主机。

目标规则

一个 DestinationRule 配置了在将流量转发到服务时要应用的一组策略。它们旨在由服务所有者创作,描述断路器、负载均衡器设置、TLS 设置等等。DestinationRule 与其前身 DestinationPolicy 几乎相同,但有以下例外

  1. DestinationRulehost 可以包含通配符前缀,允许为许多实际服务指定单个规则。
  2. DestinationRule 定义了相应目标主机的可寻址 subsets(即命名版本)。这些子集在 VirtualService 路由规范中使用,用于将流量发送到服务的特定版本。以这种方式命名版本允许我们跨不同的虚拟服务干净地引用它们,简化 Istio 代理发出的统计信息,以及将子集编码到 SNI 标头中。

配置了 reviews 服务的策略和子集的 DestinationRule 可能看起来像这样

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  trafficPolicy:
    loadBalancer:
      simple: RANDOM
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
    trafficPolicy:
      loadBalancer:
        simple: ROUND_ROBIN
  - name: v3
    labels:
      version: v3

请注意,与 DestinationPolicy 不同,多个策略(例如,默认策略和特定于 v2 的策略)是在单个 DestinationRule 配置中指定的。

服务条目

ServiceEntry 用于将其他条目添加到 Istio 在内部维护的服务注册表中。它最常用于允许对网格的外部依赖项进行建模,例如从网络使用或流量到旧式基础设施中的服务的 API。

之前使用 EgressRule 可以配置的所有内容都可以轻松地使用 ServiceEntry 完成。例如,可以使用类似于以下配置的配置来启用从网格内部访问简单外部服务

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: foo-ext
spec:
  hosts:
  - foo.com
  ports:
  - number: 80
    name: http
    protocol: HTTP

也就是说,ServiceEntry 的功能远超其前身。首先,ServiceEntry 不限于外部服务配置,它可以有两种类型:网格内部或网格外部。网格内部条目与所有其他内部服务类似,但用于显式地将服务添加到网格。它们可以用于将服务添加为将服务网格扩展到包括非管理基础设施(例如,添加到基于 Kubernetes 的服务网格的 VM)的一部分。网格外部条目表示网格外部的服务。对于它们来说,双向 TLS 身份验证被禁用,并且策略执行是在客户端进行的,而不是在内部服务请求的通常服务器端进行的。

由于 ServiceEntry 配置仅仅是在内部服务注册表中添加了一个目标,因此它可以与 VirtualService 和/或 DestinationRule 结合使用,就像注册表中的任何其他服务一样。例如,以下 DestinationRule 可用于为外部服务启动双向 TLS 连接

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: foo-ext
spec:
  host: foo.com
  trafficPolicy:
    tls:
      mode: MUTUAL
      clientCertificate: /etc/certs/myclientcert.pem
      privateKey: /etc/certs/client_private_key.pem
      caCertificates: /etc/certs/rootcacerts.pem

除了扩展的一般性之外,ServiceEntry 还提供了几个其他改进,优于 EgressRule,包括以下内容

  1. 单个 ServiceEntry 可以配置多个服务端点,而以前这需要多个 EgressRules
  2. 端点的解析模式现在可配置(NONESTATICDNS)。
  3. 此外,我们正在努力解决另一个痛点:需要通过纯文本端口访问安全的外部服务(例如,http://google.com:443)。这将在未来几周内得到解决,允许您从应用程序直接访问 https://google.com。敬请关注解决此限制的 Istio 修补程序版本 (0.8.x)。

创建和删除 v1alpha3 路由规则

由于给定目标的所有路由规则现在作为一个有序列表存储在一个 VirtualService 资源中,因此为特定目标添加第二个及后续规则不再是通过创建新的 (RouteRule) 资源来完成,而是通过更新该目标的唯一 VirtualService 资源来完成。

旧路由规则

$ kubectl apply -f my-second-rule-for-destination-abc.yaml

v1alpha3 路由规则

$ kubectl apply -f my-updated-rules-for-destination-abc.yaml

删除特定目标的最后一个以外的路由规则也是通过使用 kubectl apply 更新现有资源来完成的。

在添加或删除引用服务版本的路由时,将需要在服务的对应 DestinationRule 中更新 subsets。您可能已经猜到了,这也可以使用 kubectl apply 完成。

摘要

Istio v1alpha3 路由 API 的功能远超其前身,但不幸的是不向后兼容,需要一次手动转换。以前配置资源 RouteRuleDesintationPolicyEgressRule 将在 Istio 0.9 之后不再受支持。Kubernetes 用户可以继续使用 Ingress 为基本路由配置其边缘负载均衡器。但是,高级路由功能(例如,跨两个版本拆分流量)将需要使用 Gateway,这是一个功能更强大且强烈推荐的 Ingress 替代方案。

致谢

路由模型重新设计和实现工作的功劳归于以下人员(按字母顺序)

分享这篇文章