Istio中的路由包含以下几种常见的对象:
- VirtualService:Istio服务网格中定义的路由规则,控制流量路由到service的规则
- DestinationRule:配置将流量转发到实际工作负载时应用的策略集
- ServiceEntry:用于在 Istio 服务网格之外启用的服务请求
- Gateway:为 HTTP/TCP 流量配置负载均衡器,最常见的是作用于网格边缘,以处理应用程序的入口/出口流量
- EnvoyFilter:用于定制Envoy配置
- Sidecar:用于定义入网和出网流量的可达性
VirtualService
首先是一个例子:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews-route
spec:
hosts:
- reviews.prod.svc.cluster.local
http:
- name: "reviews-v2-routes"
match:
- uri:
prefix: "/wpcatalog"
- uri:
prefix: "/consumercatalog"
rewrite:
uri: "/newcatalog"
route:
- destination:
host: reviews.prod.svc.cluster.local
subset: v2
- name: "reviews-v1-route"
route:
- destination:
host: reviews.prod.svc.cluster.local
subset: v1
上面的例子表示对于一个service:reviews.prod.svc.cluster.local收到的http流量,将被转发到两个目标service:如果这个http请求的路径包含/wpcatalog或/consumercatalog,那么流量将被发送给reviews服务的v2子集(v2子集是什么将在稍后解释,可以看成拥有特定label的reviews服务);否则,流量被发送给reviews服务的v1子集。
下面是一些关键配置项:
- hosts:接收请求的主机。它可以是一个DNS或IP地址。这儿的reviews.prod.svc.cluster.local是reviews service在K8s中的域名。因此,所有通向reviews服务的流量都将被这个virtualService重新路由。注意,如果这儿直接使用"reviews"而非"reviews.prod.svc.cluster.local",那么Istio会根据这个virtualService所在的命名空间来解析这个reviews服务的全限定名。例如这个virtualService定义在default namespace中,那么"reviews"会被视为 reviews.default.svc.cluster.local,而不会是这个 reviews 服务所在真实的命名空间。为了避免可能的错误配置,建议使用服务的全限定名(FQDN)来进行服务引用。
- hosts 配置的服务的名字只是表示该配置是针对于reviews服务的路由规则,但是具体将对该服务的访问的流量路由到哪些服务的哪些实例上,就是要通过 destination 进行配置。
- destination.host 应该明确指向服务注册表中的一个服务。Istio 的服务注册表除包含平台服务注册表中的所有服务(例如 Kubernetes 服务、Consul 服务)之外,还包含了 ServiceEntry 资源所定义的服务。subset 用于配置流量目的地的子集,这个子集具体包含了哪些服务,是通过DestinationRule来定义的。
- 另外,还可以为每个destination添加weight,来实现路由的权重切分。
DestinationRule
subset 是服务端点的集合,可以用于 A/B 测试或者分版本路由等场景。对于 Kubernetes 中的服务,一个 subset 相当于使用 label 的匹配条件选出来的 service。下面是一个DestinationRule的定义:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews-destination
spec:
host: reviews.prod.svc.cluster.local
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
这个例子中为reviews服务定义了两个子集:v1和v2,因此在VirtualService中可以通过subset:v1和subset:v2来引用这两个服务。子集v1表示所有拥有 version=v1 的label的reviews服务,而子集v2表示所有拥有 version=v2的label的reviews服务。
因此,DestinationRule 定义了目标 host 的子集 subsets (或者称之为命名版本)。 这些 subset 用于 VirtualService 的路由规则设置中,可以将流量导向服务的某些特定版本。
ServiceEntry
Istio 服务网格内部会维护一个与平台无关的使用通用模型表示的服务注册表,当你的服务网格需要访问外部服务的时候,就需要使用 ServiceEntry 来添加服务注册。类似于K8s中ExternalName类型的Service。
Gateway
Gateway描述了在网络边缘运行的负载均衡器,用于接收传入或传出的HTTP / TCP连接。下面是一个例子:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
app: my-gateway-controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- uk.bookinfo.com
这个例子表示Istio会监听spec.selector选中的pod的80端口,并且允许包含了uk.bookinfo.com域名的http请求进入。
Gateway 为 HTTP/TCP 流量配置了一个负载均衡,多数情况下在网格边缘进行操作,用于启用一个服务的入口(ingress)流量,相当于前端代理。与 Kubernetes 的 Ingress 不同,Istio Gateway 只配置四层到六层的功能(例如开放端口或者 TLS 配置),而 Kubernetes 的 Ingress 是七层的。将VirtualService 绑定到 Gateway 上,用户就可以使用标准的 Istio 规则来控制进入的 HTTP 和 TCP 流量。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo-rule
namespace: bookinfo-namespace
spec:
hosts:
- reviews.prod.svc.cluster.local
- uk.bookinfo.com
- eu.bookinfo.com
gateways:
- some-config-namespace/my-gateway
http:
- match:
- headers:
cookie:
exact: "user=dev-123"
route:
- destination:
port:
number: 7777
host: reviews.qa.svc.cluster.local
- match:
- uri:
prefix: /reviews/
route:
- destination:
port:
number: 9080 # can be omitted if it's the only port for reviews
host: reviews.prod.svc.cluster.local
weight: 80
- destination:
host: reviews.qa.svc.cluster.local
weight: 20
如这个例子所示,通过VirtualService绑定一个gateway能够将gateway进入的流量路由到目标service中。
EnvoyFilter
EnvoyFilter用于定制由Istio Pilot自动生成的Envoy配置。通过EnvoyFilter能够修改Envoy中的特配置,添加新的filter,listener,cluster等等。这个功能必须小心使用,因为不正确的配置可能会导致整个mesh奔溃。下面是一个例子:
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: custom-protocol
namespace: istio-config # as defined in meshConfig resource.
spec:
configPatches:
- applyTo: NETWORK_FILTER
match:
context: SIDECAR_OUTBOUND # will match outbound listeners in all sidecars
listener:
portNumber: 9307
filterChain:
filter:
name: "envoy.tcp_proxy"
patch:
operation: INSERT_BEFORE
value:
name: "envoy.config.filter.network.custom_protocol"
config:
...
- applyTo: NETWORK_FILTER # http connection manager is a filter in Envoy
match:
# context omitted so that this applies to both sidecars and gateways
listener:
filterChain:
filter:
name: "envoy.http_connection_manager"
patch:
operation: MERGE
value:
typed_config:
"@type": "type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager"
idle_timeout: 30s
上面的例子在istio-config命名空间下定义了一个EnvoyFilter对象,这样这些配置会作用于整个系统中的sidecar。它在原有的envoy.tcp_proxy filter前增加了一些配置,配置内容省略。另外,又在envoy.http_connection_manager fileter中融合了一个新功能,即通过 envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager 增加一个30s的延迟。这就是一个EnvoyFilter的简单的使用例子。
Sidecar
Sidecar用于控制pod能够接收什么流量和能够向何处发送流量。
Sidecar是具有命名空间的资源。每个Sidecar应用到命名空间的一个和多个工作负载,工作负载的选择通过workloadSelector进行,如果不指定workloadSelector(每个命名空间只能有一个这样的Sidecar)则Sidecar应用到命名空间的所有(没有被其它带有workloadSelector的Sidecar匹配的)工作负载。
如果命名空间包含多个没有workloadSelector的Sidecar,或者多个Sidecar的workloadSelector匹配同一工作负载,则网格的行为是未定义的。
apiVersion: networking.istio.io/v1alpha3
kind: Sidecar
metadata:
name: default
namespace: prod-us1
spec:
# 入站流量规则
ingress:
# 对于从9080端口入站的HTTP流量,将其转发给Sidecar关联的工作负载监听的UDS
- port:
number: 9080
protocol: HTTP
name: somename
defaultEndpoint: unix:///var/run/someuds.sock
# 出站流量规则
egress:
# 允许针对istio-system命名空间的出站流量
- hosts:
- "istio-system/*"
# 允许针对prod-us1命名空间的9080端口的HTTP流量
- port:
number: 9080
protocol: HTTP
name: egresshttp
hosts:
- "prod-us1/*"
参考文章
- https://istio.io/docs/reference/config/networking/
- https://www.servicemesher.com/blog/istio-service-visibility/
- https://blog.gmem.cc/istio-study-note
- https://cloud.tencent.com/developer/article/1525435
- https://www.servicemesher.com/blog/istio-routing-basics/
- https://jimmysong.io/istio-handbook/concepts/traffic-management-basic.html
- https://www.kubernetes.org.cn/6296.html