流量管理
Istio 提供了强大的流量管理功能,如智能路由、服务发现与负载均衡、故障恢复、故障注入等。
istio-traffic-management
流量管理的功能由 Pilot 配合 Envoy 负责,并接管进入和离开容器的所有流量:
    流量管理的核心组件是 Pilot,负责管理和配置服务网格中的所有 Envoy 实例
    而 Envoy 实例则负责维护负载均衡以及健康检查信息,从而允许其在目标实例之间智能分配流量,同时遵循其指定的路由规则
pilot
request-flow

API 版本

Istio 0.7.X 及以前版本仅支持 config.istio.io/v1alpha2,0.8.0 将其升级为 networking.istio.io/v1alpha3,并且重命名了流量管理的几个资源对象:
    RouteRule -> VirtualService:定义服务网格内对服务的请求如何进行路由控制 ,支持根据 host、sourceLabels 、http headers 等不同的路由方式,也支持百分比、超时、重试、错误注入等功能。
    DestinationPolicy -> DestinationRule:定义 VirtualService 之后的路由策略,包括断路器、负载均衡以及 TLS 等。
    EgressRule -> ServiceEntry:定义了服务网格之外的服务,支持两种类型:网格内部和网格外部。网格内的条目和其他的内部服务类似,用于显式的将服务加入网格。可以用来把服务作为服务网格扩展的一部分加入不受管理的基础设置(例如加入到基于 Kubernetes 的服务网格中的虚拟机)中。网格外的条目用于表达网格外的服务。对这种条目来说,双向 TLS 认证是禁止的,策略实现需要在客户端执行,而不像内部服务请求中的服务端执行。
    Ingress -> Gateway:定义边缘网络流量的负载均衡。

服务发现和负载均衡

为了接管流量,Istio 假设所有容器在启动时自动将自己注册到 Istio 中(通过自动或手动给 Pod 注入 Envoy sidecar 容器)。Envoy 收到外部请求后,会对请求作负载均衡,并支持轮询、随机和加权最少请求等负载均衡算法。除此之外,Envoy 还会以熔断机制定期检查服务后端容器的健康状态,自动移除不健康的容器和加回恢复正常的容器。容器内也可以返回 HTTP 503 显示将自己从负载均衡中移除。

流量接管

Istio 假定进入和离开服务网络的所有流量都会通过 Envoy 代理进行传输。Envoy sidecar 使用 iptables 把进入 Pod 和从 Pod 发出的流量转发到 Envoy 进程监听的端口(即 15001 端口)上:
1
*nat
2
:PREROUTING ACCEPT [0:0]
3
:INPUT ACCEPT [1:60]
4
:OUTPUT ACCEPT [482:44962]
5
:POSTROUTING ACCEPT [482:44962]
6
:ISTIO_INBOUND - [0:0]
7
:ISTIO_IN_REDIRECT - [0:0]
8
:ISTIO_OUTPUT - [0:0]
9
:ISTIO_REDIRECT - [0:0]
10
-A PREROUTING -p tcp -j ISTIO_INBOUND
11
-A OUTPUT -p tcp -j ISTIO_OUTPUT
12
-A ISTIO_INBOUND -p tcp -m tcp --dport 9080 -j ISTIO_IN_REDIRECT
13
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15001
14
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -j ISTIO_REDIRECT
15
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN
16
-A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN
17
-A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN
18
-A ISTIO_OUTPUT -j ISTIO_REDIRECT
19
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
Copied!

故障恢复

Istio 提供了一系列开箱即用的故障恢复功能,如
    超时处理
    重试处理,如限制最大重试时间以及可变重试间隔
    健康检查,如自动移除不健康的容器
    请求限制,如并发请求数和并发连接数
    熔断
这些功能均可以使用 VirtualService 动态配置。比如以下为用户 jason 的请求返回 500 (而其他用户均可正常访问):
1
apiVersion: networking.istio.io/v1alpha3
2
kind: VirtualService
3
metadata:
4
name: ratings
5
spec:
6
hosts:
7
- ratings
8
http:
9
- match:
10
- headers:
11
cookie:
12
regex: "^(.*?;)?(user=jason)(;.*)?quot;
13
fault:
14
abort:
15
percent: 100
16
httpStatus: 500
17
route:
18
- destination:
19
host: ratings
20
subset: v1
21
- route:
22
- destination:
23
host: ratings
24
subset: v1
Copied!
熔断示例:
1
cat <<EOF | istioctl create -f -
2
apiVersion: networking.istio.io/v1alpha3
3
kind: DestinationRule
4
metadata:
5
name: httpbin
6
spec:
7
host: httpbin
8
trafficPolicy:
9
connectionPool:
10
tcp:
11
maxConnections: 1
12
http:
13
http1MaxPendingRequests: 1
14
maxRequestsPerConnection: 1
15
outlierDetection:
16
http:
17
consecutiveErrors: 1
18
interval: 1s
19
baseEjectionTime: 3m
20
maxEjectionPercent: 100
21
EOF
Copied!

故障注入

Istio 支持为应用注入故障,以模拟实际生产中碰到的各种问题,包括
    注入延迟(模拟网络延迟和服务过载)
    注入失败(模拟应用失效)
这些故障均可以使用 VirtualService 动态配置。如以下配置 2 秒的延迟:
1
apiVersion: networking.istio.io/v1alpha3
2
kind: VirtualService
3
metadata:
4
name: ratings
5
spec:
6
hosts:
7
- ratings
8
http:
9
- fault:
10
delay:
11
percent: 100
12
fixedDelay: 2s
13
route:
14
- destination:
15
host: ratings
16
subset: v1
Copied!

金丝雀部署

service-versions
首先部署 bookinfo,并配置默认路由为 v1 版本:
1
# 以下命令假设 bookinfo 示例程序已部署,如未部署,可以执行下面的命令
2
$ kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo.yaml)
3
# 此时,三个版本的 reviews 服务以负载均衡的方式轮询。
4
5
# 创建默认路由,全部请求转发到 v1
6
$ istioctl create -f samples/bookinfo/routing/route-rule-all-v1.yaml
7
8
$ kubectl get virtualservice reviews -o yaml
9
apiVersion: networking.istio.io/v1alpha3
10
kind: VirtualService
11
metadata:
12
name: reviews
13
spec:
14
hosts:
15
- reviews
16
http:
17
- route:
18
- destination:
19
host: reviews
20
subset: v1
Copied!

示例一:将 10% 请求发送到 v2 版本而其余 90% 发送到 v1 版本

1
cat <<EOF | istioctl create -f -
2
apiVersion: networking.istio.io/v1alpha3
3
kind: VirtualService
4
metadata:
5
name: reviews
6
spec:
7
hosts:
8
- reviews
9
http:
10
- route:
11
- destination:
12
host: reviews
13
subset: v1
14
weight: 75
15
- destination:
16
host: reviews
17
subset: v2
18
weight: 25
19
EOF
Copied!

示例二:将 jason 用户的请求全部发到 v2 版本

1
cat <<EOF | istioctl replace -f -
2
apiVersion: networking.istio.io/v1alpha3
3
kind: VirtualService
4
metadata:
5
name: ratings
6
spec:
7
hosts:
8
- ratings
9
http:
10
- match:
11
- sourceLabels:
12
app: reviews
13
version: v2
14
headers:
15
end-user:
16
exact: jason
17
EOF
Copied!

示例三:全部切换到 v2 版本

1
cat <<EOF | istioctl replace -f -
2
apiVersion: networking.istio.io/v1alpha3
3
kind: VirtualService
4
metadata:
5
name: reviews
6
spec:
7
hosts:
8
- reviews
9
http:
10
- route:
11
- destination:
12
host: reviews
13
subset: v2
14
EOF
Copied!

示例四:限制并发访问

1
cat <<EOF | istioctl create -f -
2
apiVersion: networking.istio.io/v1alpha3
3
kind: DestinationRule
4
metadata:
5
name: reviews
6
spec:
7
host: reviews
8
subsets:
9
- name: v1
10
labels:
11
version: v1
12
trafficPolicy:
13
connectionPool:
14
tcp:
15
maxConnections: 100
16
EOF
Copied!
为了查看访问次数限制的效果,可以使用 wrk 给应用加一些压力:
1
export BOOKINFO_URL=$(kubectl get po -n istio-system -l istio=ingress -o jsonpath={.items[0].status.hostIP}):$(kubectl get svc -n istio-system istio-ingress -o jsonpath={.spec.ports[0].nodePort})
2
wrk -t1 -c1 -d20s http://$BOOKINFO_URL/productpage
Copied!

Gateway

Istio 在部署时会自动创建一个 Istio Gateway,用来控制 Ingress 访问。
1
# prepare
2
kubectl apply -f <(istioctl kube-inject -f samples/httpbin/httpbin.yaml)
3
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/tls.key -out /tmp/tls.crt -subj "/CN=httpbin.example.com"
4
5
# get ingress external IP (suppose load balancer service)
6
kubectl get svc istio-ingressgateway -n istio-system
7
export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
8
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http")].port}')
9
export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].port}')
10
11
# create gateway
12
cat <<EOF | istioctl create -f -
13
apiVersion: networking.istio.io/v1alpha3
14
kind: Gateway
15
metadata:
16
name: httpbin-gateway
17
spec:
18
selector:
19
istio: ingressgateway # use Istio default gateway implementation
20
servers:
21
- port:
22
number: 80
23
name: http
24
protocol: HTTP
25
hosts:
26
- "httpbin.example.com"
27
EOF
28
29
# configure routes for the gateway
30
cat <<EOF | istioctl create -f -
31
apiVersion: networking.istio.io/v1alpha3
32
kind: VirtualService
33
metadata:
34
name: httpbin
35
spec:
36
hosts:
37
- "httpbin.example.com"
38
gateways:
39
- httpbin-gateway
40
http:
41
- match:
42
- uri:
43
prefix: /status
44
- uri:
45
prefix: /delay
46
route:
47
- destination:
48
port:
49
number: 8000
50
host: httpbin
51
EOF
52
53
# validate 200
54
curl --resolve httpbin.example.com:$INGRESS_PORT:$INGRESS_HOST -HHost:httpbin.example.com -I http://httpbin.example.com:$INGRESS_PORT/status/200
55
56
# invalidate 404
57
curl --resolve httpbin.example.com:$INGRESS_PORT:$INGRESS_HOST -HHost:httpbin.example.com -I http://httpbin.example.com:$INGRESS_PORT/headers
Copied!
使用 TLS:
1
kubectl create -n istio-system secret tls istio-ingressgateway-certs --key /tmp/tls.key --cert /tmp/tls.crt
2
3
cat <<EOF | istioctl replace -f -
4
apiVersion: networking.istio.io/v1alpha3
5
kind: Gateway
6
metadata:
7
name: httpbin-gateway
8
spec:
9
selector:
10
istio: ingressgateway # use istio default ingress gateway
11
servers:
12
- port:
13
number: 80
14
name: http
15
protocol: HTTP
16
hosts:
17
- "httpbin.example.com"
18
- port:
19
number: 443
20
name: https
21
protocol: HTTPS
22
tls:
23
mode: SIMPLE
24
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
25
privateKey: /etc/istio/ingressgateway-certs/tls.key
26
hosts:
27
- "httpbin.example.com"
28
EOF
29
30
31
# validate 200
32
curl --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST -HHost:httpbin.example.com -I -k https://httpbin.example.com:$SECURE_INGRESS_PORT/status/200
Copied!

Egress 流量

默认情况下,Istio 接管了容器的内外网流量,从容器内部无法访问 Kubernetes 集群外的服务。可以通过 ServiceEntry 为需要的容器开放 Egress 访问,如
1
$ cat <<EOF | istioctl create -f -
2
apiVersion: networking.istio.io/v1alpha3
3
kind: ServiceEntry
4
metadata:
5
name: httpbin-ext
6
spec:
7
hosts:
8
- httpbin.org
9
ports:
10
- number: 80
11
name: http
12
protocol: HTTP
13
EOF
14
15
$ cat <<EOF | istioctl create -f -
16
apiVersion: networking.istio.io/v1alpha3
17
kind: VirtualService
18
metadata:
19
name: httpbin-ext
20
spec:
21
hosts:
22
- httpbin.org
23
http:
24
- timeout: 3s
25
route:
26
- destination:
27
host: httpbin.org
28
weight: 100
29
EOF
Copied!
需要注意的是 ServiceEntry 仅支持 HTTP、TCP 和 HTTPS,对于其他协议需要通过 --includeIPRanges 的方式设置 IP 地址范围,如
1
helm template @install/kubernetes/helm/[email protected] --name istio --namespace istio-system --set global.proxy.includeIPRanges="10.0.0.1/24" -x @templates/[email protected] | kubectl apply -f -
Copied!

流量镜像

1
cat <<EOF | istioctl replace -f -
2
apiVersion: networking.istio.io/v1alpha3
3
kind: VirtualService
4
metadata:
5
name: httpbin
6
spec:
7
hosts:
8
- httpbin
9
http:
10
- route:
11
- destination:
12
host: httpbin
13
subset: v1
14
weight: 100
15
mirror:
16
host: httpbin
17
subset: v2
18
EOF
Copied!

参考文档

最近更新 2yr ago