简介 Istio v1alpha3 路由 API
Istio v1alpha3 路由 API 的介绍、动机和设计原则。
到目前为止,Istio 提供了一个简单的 API 用于使用四个配置资源进行流量管理:RouteRule
、DestinationPolicy
、EgressRule
和(Kubernetes)Ingress
。使用此 API,用户可以轻松管理 Istio 服务网格中的流量流。API 允许用户将请求路由到服务的特定版本,注入延迟和故障以进行弹性测试,添加超时和断路器,等等,所有这些都无需更改应用程序代码本身。
虽然此功能已被证明是 Istio 的一个非常引人注目的部分,但用户反馈也表明此 API 确实存在一些缺点,特别是在使用它来管理包含数千个服务的非常大的应用程序时,以及在处理 HTTP 以外的协议时。此外,使用 Kubernetes Ingress
资源配置外部流量已被证明远远不能满足我们的需求。
为了解决这些问题以及其他问题,引入了新的流量管理 API,也称为 v1alpha3
,它将完全取代之前的 API。虽然 v1alpha3
模型在根本上是相同的,但它与以前的版本不兼容,需要手动从旧 API 转换。
为了证明这种中断的合理性,v1alpha3
API 经过了漫长而艰苦的社区评审过程,希望最终能得到一个大大改进的 API,能够经受时间的考验。在本文中,我们将介绍新的配置模型,并尝试解释影响它的某些动机和设计原则。
设计原则
一些关键设计原则在路由模型重新设计中发挥了作用
- 明确地建模基础设施以及意图。例如,除了配置入口网关之外,还可以指定实现它的组件(控制器)。
- 创作模型应为“生产者导向”和“主机中心”,而不是组合的。例如,与特定主机关联的所有规则都是一起配置的,而不是单独配置的。
- 将路由与路由后行为明确分离。
v1alpha3 中的配置资源
典型的网格将有一个或多个负载均衡器(我们称它们为网关),这些负载均衡器从外部网络终止 TLS 并允许流量进入网格。然后,流量通过旁路网关流经内部服务。应用程序通常也会使用外部服务(例如,Google 地图 API)。这些服务可以直接调用,或者在某些部署中,所有从网格传出的流量都可能被强制通过专用的出口网关。下图描述了这种思维模型。
考虑到上述设置,v1alpha3
引入了以下新的配置资源来控制流量路由进出网格以及网格内流量路由。
网关
虚拟服务
目标规则
服务条目
VirtualService
、DestinationRule
和 ServiceEntry
分别替换 RouteRule
、DestinationPolicy
和 EgressRule
。Gateway
是一个平台无关的抽象概念,用于对流入专用中间件的流量进行建模。
下图描述了跨配置资源的控制流。
网关
一个 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 应用程序的 reviews
和 ratings
服务一样寻址它们,就好像它们是 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
还包含其他一些重要的更改
可以在
VirtualService
配置内部表达多个匹配条件,从而减少对冗余规则的需求。每个服务版本都有一个名称(称为服务子集)。属于子集的 Pod/VM 集在
DestinationRule
中定义,这将在下一节中介绍。VirtualService
主机可以使用通配符 DNS 前缀来为所有匹配的服务创建单个规则。例如,在 Kubernetes 中,要对foo
命名空间中的所有服务应用相同的重写规则,VirtualService
将使用*.foo.svc.cluster.local
作为主机。
目标规则
一个 DestinationRule
配置了在将流量转发到服务时要应用的一组策略。它们旨在由服务所有者创作,描述断路器、负载均衡器设置、TLS 设置等等。DestinationRule
与其前身 DestinationPolicy
几乎相同,但有以下例外
DestinationRule
的host
可以包含通配符前缀,允许为许多实际服务指定单个规则。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
,包括以下内容
- 单个
ServiceEntry
可以配置多个服务端点,而以前这需要多个EgressRules
。 - 端点的解析模式现在可配置(
NONE
、STATIC
或DNS
)。 - 此外,我们正在努力解决另一个痛点:需要通过纯文本端口访问安全的外部服务(例如,
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 的功能远超其前身,但不幸的是不向后兼容,需要一次手动转换。以前配置资源 RouteRule
、DesintationPolicy
和 EgressRule
将在 Istio 0.9 之后不再受支持。Kubernetes 用户可以继续使用 Ingress
为基本路由配置其边缘负载均衡器。但是,高级路由功能(例如,跨两个版本拆分流量)将需要使用 Gateway
,这是一个功能更强大且强烈推荐的 Ingress
替代方案。
致谢
路由模型重新设计和实现工作的功劳归于以下人员(按字母顺序)
- Frank Budinsky (IBM)
- Zack Butcher (Google)
- Greg Hanson (IBM)
- Costin Manolache (Google)
- Martin Ostrowski (Google)
- Shriram Rajagopalan (VMware)
- Louis Ryan (Google)
- Isaiah Snell-Feikema (IBM)
- Kuat Yessenov (Google)