流量控制(流量切分)
请求路由
- 特定网格中服务的规范表示有 Pilot 维护。服务的 istio 模型和在底层平台(Kubernetes、Mesos以及 Cloud
Foundry 等)中的表达无关。 - 特定平台的适配器负责从各自平台中获取元数据的各种字段,然后对服务模型进行填充。
- istio 引入了服务版本的概念,可以通过版本(v1、v2)或环境(staging、prod)对服务进一步的细分。这些版本不一定是不同的API版本,他们可能是部署在不同环境(staging、prod或者dev 等)中的同一服务的不同迭代(使用这种方式的常见场景包括A/B 测试或者金丝雀部署)。
- istio 的流量路由规则可以根据服务版本来对服务之间流量进行附加控制。
服务之间的通讯
- 服务的客户端不知道服务不同版本之间的差异。
- 它们可以使用服务的主机名或者 IP 地址继续访问服务。
- Envoy sidecar/ 代理拦截并转发客户端和服务器之间的所有请求和相应。
- istio 还为同一服务版本的多个实例提供流量负载均衡。可以在服务发现和负载均衡中找到更多信息。
- istio 不提供 DNS。应用程序可以尝试使用底层平台(kube-dns、mesos-dns 等)中存在的 DNS服务来解析 FQDN。
Ingress 和 Egress
- istio 假定进入和离开服务网络的所有流量都会通过 Envoy 代理进行传输。
- 通过将 Envoy 代理部署在服务之前,运维人员可以针对面向用户的服务进行 A/B 测试、部署金丝雀服务等。
- 通过使用 Envoy 将流量路由到外部 Web 服务(例如,访问 Maps API 或视频服务 API)的方式,运维人员可以为这些服务添加超时控制、重试、断路器等功能,同时还能从服务连接中获取各种细节指标。
服务发现和负载均衡
istio 负载均衡服务网格中实例之间的通信
- istio 假定存在服务注册表,以跟踪应用程序中服务的 pod/VM。它还假设服务的新实例自动注册到服务注册表,并且不健康的实例将被自动删除。
- Pilot 使用来自服务注册的信息,并提供与平台无关的服务发现接口。网格中的 Envoy 实例执行服务发现,并相应的动态更新其负载均衡池。
- 网格中的服务使用其 DNS 名称访问彼此,服务的所有 HTTP 流量都会通过 Envoy 自动重新路由。
Envoy 在负载均衡池中的实例之间分发流量
- istio 目前仅允许三种负载均衡模式:轮询、随机、和带权重的最少请求。
- 除了负载均衡外,Envoy 还会定期检查池中每个实例的运行状况。Envoy遵循熔断器风格模式, 根据健康检查 API调用的失败率将实例分类为不健康和健康两种。当给定实例的健康检查失败次数超过预定阈值时,将会被从负载均衡池中弹出。类似地,当通过的健康检查数超过预定國值时, 该实例将被添加回负载均衡池。您可以在处理故障中了解更多有关 Envoy 的故障处理功能。
- 服务可以通过使用 HTTP 503 响应健康检查来主动减轻负担。在这种情况下,服务实例将立即从调用者的负载均衡池中删除。
故障处理
解读istio 提供的两个对象,Gateway 和 VirtualService
对象 Gateway :
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "bookinfo.bianmc.com"
解读:定义了 Gateway 规则对象,指定标签 istio=ingressgateway ,处理的域名为 bookinfo.bianmc.com ,定义了一个 80 端口,协议为HTTP。对应了 Envoy 内的 监听器 listener
对象 VirtualService :
spec:
hosts:
- "bookinfo.bianmc.com"
gateways:
- bookinfo-gateway // 指定gateways 转发规则,要与这个对象关联
http:
- match:
- port: 80 // 默认,可以不写
uri:
exact: /productpage
route:
- destination:
host: productpage
port:
number: 9080
解读:访问域名 bookinfo.bianmc.com 如果 match 端口80,路径 /productpage ,就 destination 转发到目的地名为 productpage 的svc,svc的端口为9080,所以 VirtualService 对应的是路由 route 转发规则。
合起来解读:
Gateway 对象 在标签为 istio=ingressgateway 的 POD(Envoy )中插入一个规则,这个规则定义一个 listener ,这个 listener 监听 http 协议的80 端口用户处理域名 bookinfo.bianmc.com 的请求。
VirtualService 对象在listener 中加一个转发规则,如果match 端口80,路径 /productpage ,就 destination 转发到目的地名为 productpage 的svc,svc的端口为9080。
实践1:基于域名的方式访问Istio服务网格
用户请求bookinfo的项目,在浏览器中输入域名,由DNS解析到LB负载均衡器,LB负载均衡器会将请求转发到IngressGateway中,IngressGateway根据请求头中的域名,将请求转发到对应的Gateway中,然后在将请求转发到应用程序的 Service资源,最后由应用程序的Pod资源提供应用程序的服务。
1. 注入 sidecar
2. 创建deploy
[root@vms120 httpbin]# kubectl create ns simple
namespace/simple created
[root@vms120 kube]# kubectl apply -f bookinfo.yaml
service/details created
serviceaccount/bookinfo-details created
deployment.apps/details-v1 created
service/ratings created
serviceaccount/bookinfo-ratings created
deployment.apps/ratings-v1 created
service/reviews created
serviceaccount/bookinfo-reviews created
deployment.apps/reviews-v1 created
deployment.apps/reviews-v2 created
deployment.apps/reviews-v3 created
service/productpage created
serviceaccount/bookinfo-productpage created
deployment.apps/productpage-v1 created
[root@vms120 kube]# kubectl get pod
NAME READY STATUS RESTARTS AGE
details-v1-7f4669bdd9-qc8z8 2/2 Running 0 91m
productpage-v1-5586c4d4ff-npzkn 2/2 Running 0 91m
ratings-v1-6cf6bc7c85-95fnq 2/2 Running 0 91m
reviews-v1-7598cc9867-bhk25 2/2 Running 0 91m
reviews-v2-6bdd859457-gkspm 2/2 Running 0 91m
reviews-v3-6c98f9d7d7-6fpjt 2/2 Running 0 91m
3. 创建 Gateway 和 VirtualService
[root@vms120 networking]# cat bookinfo-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "bookinfo.bianmc.com"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "bookinfo.bianmc.com"
gateways:
- 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
[root@vms120 kube]# kubectl get svc -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.101.89.49 <pending> 15021:31342/TCP,80:31857/TCP,443:31702/TCP 2d21h
istiod ClusterIP 10.100.70.217 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 2d21h
访问测试
curl -H 指定域名, CLUSTER-IP/地址
[root@vms120 ~]# curl -H "host:bookinfo.bianmc.com" 10.101.89.49/productpage -v
* About to connect() to 10.101.89.49 port 80 (#0)
* Trying 10.101.89.49...
* Connected to 10.101.89.49 (10.101.89.49) port 80 (#0)
> GET /productpage HTTP/1.1
> User-Agent: curl/7.29.0
> Accept: */*
> host:bookinfo.bianmc.com
>
< HTTP/1.1 200 OK
< content-type: text/html; charset=utf-8
< content-length: 4294
< server: istio-envoy
< date: Mon, 05 Sep 2022 08:46:27 GMT
< x-envoy-upstream-service-time: 23
<
<!DOCTYPE html>
<html>
<head>
<title>Simple Bookstore App</title>
LB负载均衡我们采用Nginx来实现,由Nginx去反向代理IngressGateway的NodePort端口来实现基于域名去访问lstio中的程序.
1.安装Nginx
[root@lb~]# yum -y install nginx
2.配置Nginx反向代理Istio的IngressGateway
[root@lb~]# vim /etc/nginx/conf.d/istio-ingressgateway.conf
server {
listen 80;
server_name _;
location / {
proxy_http_version 1.1; #开启http的1.1版本协议,istio是1.1版本,nginx默认1.0版本
proxy_set_header Host $host; #代理转发时携带请求的主机头
proxy_pass http://192.168.26.120:31857; #代理到istio的IngressGateway
}
}
3.启动Nginx
[root@lb~]# systemctl restart nginx
实践2:基于Istio服务网格进行重定向
[root@vms120 networking]# cat bookinfo-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "bookinfo.bianmc.com"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "bookinfo.bianmc.com"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage/hello
rewrite:
uri: /productpage
route:
- destination:
host: productpage
port:
number: 9080
只要修改 VirtualService 对象在listener 中的转发规则,让访问 /productpage/hello 的流量 rewrite 重定向到 /productpage
[root@vms120 ~]# curl -H "host:bookinfo.bianmc.com" 10.101.89.49/productpage -v
* About to connect() to 10.101.89.49 port 80 (#0)
* Trying 10.101.89.49...
* Connected to 10.101.89.49 (10.101.89.49) port 80 (#0)
> GET /productpage HTTP/1.1
> User-Agent: curl/7.29.0
> Accept: */*
> host:bookinfo.bianmc.com
>
< HTTP/1.1 404 Not Found
还是访问 /productpage 显示 404
[root@vms120 ~]# curl -H "host:bookinfo.bianmc.com" 10.101.89.49/productpage/hello -v
* About to connect() to 10.101.89.49 port 80 (#0)
* Trying 10.101.89.49...
* Connected to 10.101.89.49 (10.101.89.49) port 80 (#0)
> GET /productpage/hello HTTP/1.1
> User-Agent: curl/7.29.0
> Accept: */*
> host:bookinfo.bianmc.com
>
< HTTP/1.1 200 OK
访问 /productpage/hello 被转发到正确的地址
实践3:基于Istio服务网格部署 HTTPS 证书
1. 生成 https 证书
[root@vms120 ~]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=bianmc Inc./CN=*.bianmc.io' -keyout bianmc.io.key -out bianmc.io.crt
Generating a 2048 bit RSA private key
..................................+++
...........................................................................+++
writing new private key to 'bianmc.io.key'
-----
2. 创建存放证书的 secret ,也可以在 VirtualService 中直接调用证书文件
[root@vms120 ~]# kubectl create secret tls bianmc-credential --key=bianmc.io.key --cert=bianmc.io.crt -n istio-system
secret/bianmc-credential created
3. 创建 Gateway 和 VirtualService
[root@vms120 networking]# cat bookinfo-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 443 // https 端口
name: https
protocol: HTTPS // 协议HTTPS
tls: // 指定 存放证书的 secret
mode: SIMPLE
credentialName: bianmc-credential
// 也可以在 VirtualService 中直接调用证书文件
// serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
// privateKey: /etc/istio/ingressgateway-certs/tls.key
hosts:
- "bookinfo.bianmc.com"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "bookinfo.bianmc.com"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
port: 443 // 监听端口修改
route:
- destination:
host: productpage
port:
number: 9080
[root@vms120 ~]# curl --resolve bookinfo.bianmc.com:443:10.101.89.49 https://bookinfo.bianmc.com/productpage -v -k
* Added bookinfo.bianmc.com:443:10.101.89.49 to DNS cache
* About to connect() to bookinfo.bianmc.com port 443 (#0)
* Trying 10.101.89.49...
* Connected to bookinfo.bianmc.com (10.101.89.49) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: CN=*.bianmc.io,O=bianmc Inc.
* start date: 9月 05 09:09:50 2022 GMT
* expire date: 9月 05 09:09:50 2023 GMT
* common name: *.bianmc.io
* issuer: CN=*.bianmc.io,O=bianmc Inc.
> GET /productpage HTTP/1.1
> User-Agent: curl/7.29.0
> Host: bookinfo.bianmc.com
> Accept: */*
>
< HTTP/1.1 200 OK