Istio详细使用-流量管理(二)
上篇介绍了istio的基础和网关的安装,以及bookInfo的应用用例安装,接下来介绍流量管理,比如熔断器、超时和重试,并且能轻松的设置重要的任务, 如 A/B 测试、金丝雀发布、基于流量百分比切分的分阶段发布等。
1. 介绍
为了在网格中导流,Istio 需要知道所有的 endpoint 在哪和属于哪个服务。 为了定位到 service registry(服务注册中心), Istio 会连接到一个服务发现系统。例如,如果您在 Kubernetes 集群上安装了 Istio, 那么它将自动检测该集群中的服务和 endpoint。使用此服务注册中心,Envoy 代理可以将流量定向到相关服务。
Istio 维护了一个内部服务注册表 (service registry),它包含在服务网格中运行的一组服务及其相应的服务 endpoints。Istio 使用服务注册表生成 Envoy 配置。
本章节的其余部分将分别介绍每个流量管理 API 以及如何使用它们。这些资源包括:
- 虚拟服务(Virtual Service) 在istio服务网格中定义路由规则,控制路由如何路由到服务上
- 目标规则(Destination Rule)是VirtualService路由生效后,配置应用与请求的策略集
- 网关(Gateway) 为HTTP/TCP流量配置负载均衡器,最常见的是在网格的边缘的操作,以启用应用程序的入口流量
- 服务入口(ServiceEntry) 是通常用于在Istio服务网格之外启用对服务的请求 参考类似k8s的service
- 外部工作负载(WorkloadEntry) 参考类似k8s中svc+ep
- 外部工作负载组(WorkloadGroup) 官方参考主要用于虚机加入网格情况(不进行介绍)
- Sidecar(Sidecar)用于配置进出网格的流量信息,可针对流量进行更精细的配置
2. 虚拟服务(Virtual Service)
虚拟服务让您配置如何在服务网格内将请求路由到服务, 这基于 Istio 和平台提供的基本的连通性和服务发现能力。每个虚拟服务包含一组路由规则, Istio 按顺序评估它们,Istio 将每个给定的请求匹配到虚拟服务指定的实际目标地址。
2.1 示例
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: bookinfo-gateway
namespace: istio-system
spec:
# The selector matches the ingress gateway pod labels.
# If you installed Istio using Helm following the standard documentation, this would be "istio=ingress"
selector:
istio: ingress # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: bookinfo
namespace: istio-xjy
spec:
hosts:
- "*"
gateways:
- istio-system/bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: helloworld
spec:
hosts:
- helloworld # 配置svc名称 或则ip之类
http:
- match:
- headers:
cookie:
regex: "^(.*?;)?(email=[^;]*@some-company-name.com)(;.*)?$"
route:
- destination:
host: helloworld
subset: v1
weight: 50
- destination:
host: helloworld
subset: v2
weight: 50
- route:
- destination:
host: helloworld
subset: v1
2.2 hosts字段
使用 hosts
字段列举虚拟服务的主机——即用户指定的目标或是路由规则设定的目标。 这是客户端向服务发送请求时使用的一个或多个地址。
虚拟服务主机名可以是 IP 地址、DNS 名称,或者依赖于平台的一个简称(例如 Kubernetes 服务的短名称,ServiceEntries声明主机),隐式或显式地指向一个完全限定域名(FQDN)。您也可以使用通配符(“*”)前缀, 让您创建一组匹配所有服务的路由规则(比如:reviews.default.svc.cluster.local 为了避免潜在的错误配置,建议始终使用完全限定的域名而不是短域名。)
hosts:
- reviews
- bookinfo.com
2.3 匹配规则
在 http
字段包含了虚拟服务的路由规则,用来描述匹配条件和路由行为, 它们把 HTTP/1.1、HTTP2 和 gRPC 等流量发送到 hosts 字段指定的目标。
2.3.1 根据header匹配
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: helloworld
spec:
hosts:
- helloworld # 配置svc名称 或则ip之类
http:
- match:
- headers: # 根据请求头部访问
cookie:
regex: "^(.*?;)?(email=[^;]*@some-company-name.com)(;.*)?$"
.......=
参考其他路由规则:
HTTP:https://istio.io/latest/docs/reference/config/networking/virtual-service/#HTTPMatchRequest
TCP:https://istio.io/latest/docs/reference/config/networking/virtual-service/#TCPRoute
TLS:https://istio.io/latest/docs/reference/config/networking/virtual-service/#TLSRoute
2.3.2 根据uri匹配
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: helloworld
spec:
hosts:
- helloworld # 配置svc名称 或则ip之类
http:
- match:
- uri: # 根据url 前缀匹配
prefix: /api/v1
.....
2.3.3 根据sourceLabels/ sourceNamespace 匹配
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: helloworld
spec:
hosts:
- helloworld # 配置svc名称 或则ip之类
http:
- match:
sourceLabels: # 根据请求服务的标签匹配
app: test
sourceNamespace: default # 根据请求的命名空间匹配
具体详细使用规则可以参考文档: https://istio.io/latest/zh/docs/reference/config/networking/virtual-service/#HTTPMatchRequest
2.4 路由规则
可以将匹配的流量按照一定的规则进行分发到对应的服务中心。
路由规则按从上到下的顺序选择,虚拟服务中定义的第一条规则有最高优先级。 不满足第一个路由规则的流量均流向下一一个默认的目标,该目标在第二条规则中指定。
subset 需要设置subset,否则不会以pod作为基础去检测,而是以service来检测异常
2.4.1 服务间的流量拆分
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews-route
spec:
hosts:
- reviews.prod.svc.cluster.local
http:
- route:
- destination:
host: reviews.prod.svc.cluster.local
subset: v2 # # 需要设置subset,否则不会以pod作为基础去检测,而是以service来检测异常
weight: 25
- destination:
host: reviews.prod.svc.cluster.local
subset: v1
weight: 75
2.5 超时与重试
2.5.1 超时
# 超时
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: my-productpage-rule
namespace: istio-system
spec:
hosts:
- productpage.prod.svc.cluster.local # ignores rule namespace
http:
- timeout: 5s # 设置超时
route:
- destination:
host: productpage.prod.svc.cluster.local
2.5.2 重试
# 重试 https://istio.io/latest/zh/docs/reference/config/networking/virtual-service/#HTTPRetry
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: ratings-route
spec:
hosts:
- ratings.prod.svc.cluster.local
http:
- route:
- destination:
host: ratings.prod.svc.cluster.local
subset: v1
retries:
attempts: 3 # 给定重试的次数,重试之间的间隔将自动确定(25ms以上)
perTryTimeout: 2s # 重试超时时间
retryOn: gateway-error,connect-failure,refused-stream # 重试策略,具体可以参考envoy https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/router_filter#x-envoy-retry-on
2.6 延迟、故障注入
2.6.1 延迟注入
# 延迟注入 https://istio.io/latest/zh/docs/reference/config/networking/virtual-service/#HTTPFaultInjection-Delay
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews-route
spec:
hosts:
- reviews.prod.svc.cluster.local
http:
- match:
- sourceLabels:
env: prod
route:
- destination:
host: reviews.prod.svc.cluster.local
subset: v1
fault:
delay:
percentage:
value: 10 # 10%的流量会进行延迟5秒返回
fixedDelay: 5s
2.6.2 故障注入
# 故障注入 https://istio.io/latest/zh/docs/reference/config/networking/virtual-service/#HTTPFaultInjection-Abort
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: ratings-route
spec:
hosts:
- ratings.prod.svc.cluster.local
http:
- route:
- destination:
host: ratings.prod.svc.cluster.local
subset: v1
fault:
abort:
percentage:
value: 10 # 10%的流量返回400 错误状态码
httpStatus: 400
2.7 流量镜像
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews-route
spec:
hosts:
- reviews.prod.svc.cluster.local
http:
- route:
- destination:
host: reviews.prod.svc.cluster.local
subset: v1
weight: 100
mirror: # 流量镜像,访问了v1之后 还会在额外同步相同请求访问到v2中
host: reviews.prod.svc.cluster.local
subset: v2
2.8 规则委托
描述委托VirtualService。以下路由规则通过名为productpage
的委派VirtualService将流量转发到/productpage
,通过名为reviews
的委派VirtualService将流量转发到/reviews
。 https://istio.io/latest/zh/docs/reference/config/networking/virtual-service/#Delegate
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "bookinfo.com"
gateways:
- mygateway
http:
- match:
- uri:
prefix: "/productpage"
delegate: # 只有“路由”和“重定向”为空时才能设置,并且VirtualService委托的路由规则将与当前委托的路由规则合并。
name: productpage
namespace: nsA
- match:
- uri:
prefix: "/reviews"
delegate:
name: reviews
namespace: nsB
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: productpage
namespace: nsA
spec:
http:
- match:
- uri:
prefix: "/productpage/v1/"
route:
- destination:
host: productpage-v1.nsA.svc.cluster.local
- route:
- destination:
host: productpage.nsA.svc.cluster.local
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
namespace: nsB
spec:
http:
- route:
- destination:
host: reviews.nsB.svc.cluster.local
2.9 重定向与重写
2.9.1 重定向
# 重定向 https://istio.io/latest/zh/docs/reference/config/networking/virtual-service/#HTTPRedirect
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: ratings-route
spec:
hosts:
- ratings.prod.svc.cluster.local
http:
- match:
- uri:
exact: /v1/getProductRatings
redirect:
uri: /v1/bookRatings # 将ratings的/v1/getProductRatings请求 重定向到newratings的 /v1/bookRatings地址上
authority: newratings.default.svc.cluster.local # 覆盖主机部分
...
2.9.2 重写
# 重写 https://istio.io/latest/zh/docs/reference/config/networking/virtual-service/#HTTPRewrite
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: ratings-route
spec:
hosts:
- ratings.prod.svc.cluster.local
http:
- match:
- uri:
prefix: /ratings
rewrite:
uri: /v1/bookRatings # 重写uri请求
authority: newratings.default.svc.cluster.local # 覆盖主机部分
route:
- destination:
host: ratings.prod.svc.cluster.local
subset: v1
3. 目标规则(Destination Rule)
DestinationRule定义了在路由发生后应用于服务的流量的策略。这些规则指定负载平衡的配置、侧车的连接池大小,以及用于从负载平衡池中检测和排除不健康主机的离群值检测设置。这些策略包含了断路器、负载均衡和TLS配置相关内容。
3.1 示例
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: my-destination-rule
spec:
host: my-svc
trafficPolicy:
loadBalancer: # 负载配置 https://istio.io/latest/zh/docs/reference/config/networking/destination-rule/#LoadBalancerSettings
simple: RANDOM
subsets: # 需要设置subset,否则不会以pod作为基础去检测,而是以service来检测异常
- name: v1
labels: # 每个子集都是基于一个或多个 labels 定义的,在 Kubernetes 中它是附加到像 Pod 这种对象上的键/值对。
version: v1
- name: v2
labels:
version: v2
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
- name: v3
labels:
version: v3
3.2 负载连接配置
# https://istio.io/latest/zh/docs/reference/config/networking/destination-rule/#ConnectionPoolSettings
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: bookinfo-redis
spec:
host: myredissrv.prod.svc.cluster.local
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
connectTimeout: 30ms
tcpKeepalive:
time: 7200s
interval: 75s
3.3 断路器
一种断路器实现,用于跟踪上游服务中每个单独主机的状态。HTTP服务和TCP服务均可使用。对于HTTP服务,对于API调用连续返回5xx错误的主机将在预定义的时间段内从池中弹出。对于TCP服务,在测量连续错误度量时,连接超时或到给定主机的连接失败算作错误。
# https://istio.io/latest/zh/docs/reference/config/networking/destination-rule/#OutlierDetection
# 下面的规则将连接池大小设置为100个HTTP1连接,并且不超过10个请求/连接到“reviews”服务。此外,它还设置了1000个并发HTTP2请求的限制,并将上游主机配置为每5分钟扫描一次,以便任何连续7次失败并出现502、503或504错误码的主机将被驱逐15分钟。
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: reviews-cb-policy
spec:
host: reviews.prod.svc.cluster.local
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
http2MaxRequests: 1000
maxRequestsPerConnection: 10
outlierDetection:
consecutive5xxErrors: 7 # 5xx的错误失败7次,即认为该endpoint有问题
interval: 5m # 5分钟检测一次(实际验证的话,如果连续3个请求是失败的话,也可以触发异常)
baseEjectionTime: 15m #(异常之后,将该endpoint”隔离“的时间)
maxEjectionPercent: 100 #(最多允许多少个endpoint异常被隔离,百分比)
4. 网关(Gateway)
GateWay
为HTTP/TCP配置了一个负载均衡器。多数情况下载网格边缘进行操作,用于启用一个服务入口ingress
流量。
与Kubernetes Ingress 不同,lstio Gateway只配置四层到六层的功能(例如开放端口或者TLS 配置)。绑定一个VitualService
到Gateway
上,用户就可以使用标准的Istio 规则来控制进入的HTTP和TCP流量。
4.1 示例
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.example.com"
tls:
mode: SIMPLE
credentialName: ext-host-cert
# 这个网关配置让 HTTPS 流量从 httpbin.example.com 通过 443 端口流入网格, 但没有为请求指定任何路由规则。要指定路由并让网关按预期工作,您必须把网关绑定到虚拟服务上。 正如下面的示例所示,使用虚拟服务的 gateways 字段进行设置:
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
4.2 网关加固
# 创建secret kubectl create -n istio-system secret tls httpbin-credential \
# --key=example_certs1/httpbin.example.com.key \
# --cert=example_certs1/httpbin.example.com.crt
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: mygateway
spec:
selector:
istio: ingressgateway # use istio default ingress gateway controller
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: httpbin-credential # secret 名称
hosts:
- httpbin.example.com
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: mygateway
spec:
selector:
istio: ingressgateway # use istio default ingress gateway controller
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE # enables HTTPS on this port
serverCertificate: /etc/certs/servercert.pem
privateKey: /etc/certs/privatekey.pem
hosts:
- httpbin.example.com
5. 服务入口(ServiceEntry)
Istio
内部会维护一个服务注册表,可以用ServiceEntry
向其中加入额外的条目。通常这个对象用来启用对Isto服务网格之外的服务发出请求ServiceEntry中使用hosts字段来指定目标,字段值可以是一个完全限定名,也可以是个通配符域名。
其中包含的白名单,包含一或多个允许网格中服务访问的服务。
只要ServiceEntry涉及到了匹配host的服务,就可以和VirtualService以及DestinationRule配合工作。
5.1 示例
# 访问foo.bar.com可以访问到其他endpoints
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: external-svc-dns
spec:
hosts:
- foo.bar.com
location: MESH_EXTERNAL # 外部服务
ports:
- number: 80
name: http
protocol: HTTP
resolution: DNS
endpoints:
- address: us.foo.bar.com
ports:
http: 8080
- address: uk.foo.bar.com
ports:
http: 9080
- address: in.foo.bar.com
ports:
http: 7080
# https://istio.io/latest/zh/docs/reference/config/networking/service-entry/#ServicePort
# https://istio.io/latest/zh/docs/tasks/traffic-management/egress/egress-control/
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: external-svc-mongocluster
spec:
# DNS名称
hosts:
- mymongodb.somedomain # not used
addresses:
- 192.192.192.192/24 # VIPs
# 关联的端口
ports:
- number: 27018
name: mongodb
# 端口协议:HTTP, HTTPS, HTTP2, GRPC, MONGO, TCP或TLS
protocol: MONGO
# 网格的角度,内部 or 外部服务,MESH_INTERNAL / MESH_EXTERNAL
location: MESH_INTERNAL
# 主机的服务发现模式: NONE / STATIC / DNS
resolution: STATIC
# 外部服务在网格内的域名和网格外的域名不同,在 endpoints 中配置原始域名:
endpoints:
- address: us.foo.bar.com
ports:
https: 8080
- address: uk.foo.bar.com
ports:
https: 9080
- 使用默认的Allow-all的访问外部服务控制使用简单,但缺点,即丢失了对外部服务流量的 Istio 监控和控制;比如,允许调用所有未知的外部服务,外部服务的调用没有记录到 Mixer 的日志中。
- 在服务调用过程中会使用到外部的服务,外部服务和本身集群内的服务无任何关系,通过ServiceEntry将该服务注册到 Istio 网格,在集群内部就好像访问自身的服务一样,我们还可以结合VirtualService、DestinationRule进而对网格内调用外部服务使用一些高级的治理能力,例如限流、重试等等对服务治理能力支持。– 总体可以认为是k8s的svc+endpoint类似功能
- 现实的世界中,并不能做到所有的业务都容器化,Istio也意识到了这个问题,所以正在支持非容器部署的业务。除了ServiceEntry,又增加了WorkloadEntry,从而支持将vm部署的业务纳入mesh中。
- 管理外部流量https://istio.io/latest/zh/docs/tasks/traffic-management/egress/egress-control/#manage-traffic-to-external-services
6. 外部工作负载(WorkloadEntry)
WorkloadEntry
使操作员能够描述单个非kubernetes工作负载的属性,例如虚拟机或裸机服务器,把它加载到网格中。WorkloadEntry必须伴随着Istio ServiceEntry,它通过适当的标签选择工作负载,并为MESH_INTERNAL服务(主机名、端口属性等)提供服务定义。ServiceEntry对象可以根据服务条目中指定的标签选择器选择多个工作负载条目以及Kubernetes pod。
6.1 示例
通过details-svc访问到对应的虚拟机或物理机上
# https://istio.io/latest/zh/docs/reference/config/networking/workload-entry/
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
name: details-svc
spec:
# use of the service account indicates that the workload has a
# sidecar proxy bootstrapped with this service account. Pods with
# sidecars will automatically communicate with the workload using
# istio mutual TLS.
serviceAccount: details-legacy
address: 172.31.12.217
ports:
http: 4000
labels:
app: zstone-nginx
instance-id: vm1
---
# 关联到serviceEntry
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: details-svc
spec:
hosts:
- details.bookinfo.com
location: MESH_INTERNAL
ports:
- number: 80
name: http
protocol: HTTP
targetPort: 4000
resolution: STATIC
workloadSelector:
labels:
app: zstone-nginx
echo "172.31.12.216 details.bookinfo.com" >> /etc/hosts
kubectl -n istio-xjy run client --image=ikubernetes/admin-box -it --rm --restart=Never --command -- /bin/sh
curl details.bookinfo.com # 会变成请求到 172.31.12.217:4000服务上
7. 外部工作负载组(WorkloadGroup)
其他
IstioCtl使用查看代理情况
- 网格概览
istioctl proxy-status / istioctl ps
- 检索特定 Pod 中 Envoy 实例的集群配置的信息(service服务)
istioctl proxy-config cluster -n istio-xjy details-v1-795f98b94c-gm7rb
- 检索特定 Pod 中 Envoy 实例的 bootstrap 配置的信息:
istioctl proxy-config bootstrap -n istio-xjy details-v1-795f98b94c-gm7rb
- 检索特定 Pod 中 Envoy 实例的监听器配置的信息:
istioctl proxy-config listener -n istio-xjy details-v1-795f98b94c-gm7rb
- 检索特定 Pod 中 Envoy 实例的路由配置的信息:
istioctl proxy-config route -n istio-xjy details-v1-795f98b94c-gm7rb
- 检索特定 Pod 中 Envoy 实例的 endpoint 配置的信息:
istioctl proxy-config endpoints -n istio-xjy details-v1-795f98b94c-gm7rb
外部引用
[Istio官网]: https://istio.io/latest/zh/docs/concepts/ “Istio官网”
[流量管理]: https://istio.io/latest/zh/docs/concepts/traffic-management/#sidecars “流量管理”
[ServiceEntry]: https://zhuanlan.zhihu.com/p/360760454 “Istio学习之CRD:ServiceEntry”