【云原生 | 从零开始学istio】五、istio灰度发布以及核心资源

【云原生 | 从零开始学istio】五、istio灰度发布以及核心资源_第1张图片

istio灰度发布

  • 接着上一章部署bookinfo
  • 通过 Istio 实现灰度发布
    • 什么是灰度发布?
    • 使用 istio 进行灰度发布
  • istio 核心资源解读
    • Gateway
    • VirtualService
    • DestinationRule
  • 写在最后

接着上一章部署bookinfo

1.进入 istio 安装目录。 

2.istio 默认自动注入 sidecar,需要为 default 命名空间打上标签 istio-injection=enabled,然后 default 也会自动注入了
[root@k8smaster istio-1.10.1]# kubectl label namespace default istio-injection=enabled 
namespace/default labeled

3.使用 kubectl 部署应用 
[root@k8smaster istio-1.10.1]# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
上面的命令会启动全部的四个服务,其中也包括了 reviews 服务的三个版本(v1、v2 以及 v3)可以去自己查看一下这个yaml写的啥。 

4.确认所有的服务和 Pod 都已经正确的定义和启动: 
[root@k8smaster istio-1.10.1]# kubectl get services
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
details       ClusterIP   10.97.7.165     <none>        9080/TCP   2m22s
productpage   ClusterIP   10.105.145.13   <none>        9080/TCP   2m22s
ratings       ClusterIP   10.105.6.245    <none>        9080/TCP   2m22s
reviews       ClusterIP   10.106.50.234   <none>        9080/TCP   2m22s

[root@k8smaster istio-1.10.1]# kubectl get pods 
NAME                              READY   STATUS    RESTARTS   AGE
details-v1-65bbfd4f58-7w985       2/2     Running   0          2m45s
productpage-v1-6b746f74dc-hxn89   2/2     Running   0          2m44s
ratings-v1-b45758b-kz668          2/2     Running   0          2m45s
reviews-v1-74894b48c8-g8nv8       2/2     Running   0          2m44s
reviews-v2-f649764d-2lc54         2/2     Running   0          2m45s
reviews-v3-6c675c6774-smbvr       2/2     Running   0          2m45s
 
5.确认 Bookinfo 应用是否正在运行,在某个 Pod 中用 curl 命令对应用发送请求,例如 ratings: 
[root@k8smaster istio-1.10.1]# kubectl exec -it $(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}') -c ratings -- curl productpage:9080/productpage | grep -o ".*" 
#显示下面这个就是没问题
<title>Simple Bookstore App</title>

6.确定 Ingress 的 IP 和端口 
现在 Bookinfo 服务已经启动并运行,你需要使应用程序可以从 Kubernetes 集群外部访问,例如从浏览器访问,那可以用 Istio Gateway 来实现这个目标。 
1)为应用程序定义 gateway 网关: 
[root@k8smaster istio-1.10.1]# kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml 
#这个yaml里的控制器是ingressgateway,对应了istio-system下的ingresspod,hosts:*是所有主机,下一个定义的是虚拟服务。
[root@k8smaster istio-1.10.1]# kubectl describe pods istio-ingressgateway-569f64cdf8-kc8cj -n istio-system
#也可以查看它的详细信息,里面有个标签istio=ingressgateway,网管会找到这个pod去进行操作。
[root@k8smaster istio-1.10.1]# kubectl api-versions | grep istio
install.istio.io/v1alpha1
networking.istio.io/v1alpha3
networking.istio.io/v1beta1
security.istio.io/v1beta1
telemetry.istio.io/v1alpha1
#查看istio的apiversion

2)确认网关创建完成: 
[root@k8smaster istio-1.10.1]# kubectl get gateway 
NAME               AGE
bookinfo-gateway   19s
[root@k8smaster istio-1.10.1]# kubectl get virtualservice
NAME       GATEWAYS               HOSTS   AGE
bookinfo   ["bookinfo-gateway"]   ["*"]   19m

3)确定 ingress ip 和端口 
执行如下指令,明确自身 Kubernetes 集群环境支持外部负载均衡: 
[root@k8smaster istio-1.10.1]# kubectl get svc istio-ingressgateway -n istio-system
如果 EXTERNAL-IP 值已设置,说明环境正在使用外部负载均衡,可以用其为 ingress gateway 提供服务。如果 EXTERNAL-IP 值为<none>(或持续显示<pending>),说明环境没有提供外部负载均衡,无法使用 ingress gateway。无法使用域名访问,但是可以用ip和端口,在这种情况下,使用服务的 NodePort 访问网关。 
 
若自身环境未使用外部负载均衡器,需要通过 node port 访问。可以通过以下命令获取 Istio Gateway 的地址: 
 
[root@k8smaster istio-1.10.1]# export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}') 
#定义一个变量 指定名称空间,获取到ingress映射到物理机的端口,端口协议是httpd2,赋值给这个变量。
[root@k8smaster istio-1.10.1]# echo $INGRESS_PORT
31411

[root@k8smaster istio-1.10.1]# export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}') 
[root@k8smaster istio-1.10.1]# echo $SECURE_INGRESS_PORT
31608
 
4)设置 GATEWAY_URL 
[root@k8smaster istio-1.10.1]# INGRESS_HOST=192.168.11.129
[root@k8smaster istio-1.10.1]# export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT 
#把host和port的值赋给网关url
[root@k8smaster istio-1.10.1]# echo $GATEWAY_URL
192.168.11.129:31411
 
确认可以从集群外部访问应用,可以用 curl 命令来确认是否能够从集群外部访问 Bookinfo 应用程序: 
[root@k8smaster istio-1.10.1]# curl -s http://${GATEWAY_URL}/productpage | grep -o ".*" 
<title>Simple Bookstore App</title>

还可以用浏览器打开网址 192.168.11.129:31411/productpage 来浏览应用的 Web 页面。如果刷新几次应用的页面,就会看到 productpage 页面中会随机展示 reviews 服务的不同版本的效果(红色、黑色的星形或者没有显示)。 

通过 istio 的 ingressgateway 访问可以在官网学习: 
https://istio.io/docs/examples/bookinfo/#determine-the-ingress-ip-and-port 
 
扩展:添加外部 IP-extertal-IP 
[root@xianchaomaster1 ~]# kubectl edit svc istio-ingressgateway -n istio-system
在clusterIPs:下添加
externalIPs:
  - 192.168.11.129
在 windows 机器上的 C:\Windows\System32\drivers\etc\hosts 里面最后一行加上如下域名解析: 
192.168.11.129 productpage.xianchao.cn 
在浏览器访问 http://productpage.paopao.cn/productpage 就可以看到网站了!在自己电脑做了ip和域名,访问域名(默认的80,因为没制定)然后会访问到根据网关设置的80映射的端口31411,这个更符合七层代理。

卸载 bookinfo 服务 
可以使用下面的命令来完成应用的删除和清理了: 
1.删除路由规则,并销毁应用的 Pod 
sh samples/bookinfo/platform/kube/cleanup.sh 
2.确认应用已经关停 
kubectl get virtualservices #-- there should be no virtual services 
kubectl get destinationrules #-- there should be no destination rules 
kubectl get gateway #-- there should be no gateway 
kubectl get pods #-- the Bookinfo pods should be deleted 

VirtualService中文名称虚拟服务,是istio中一个重要的资源,它定义了一系列针对指定服务的流量路由规则。每个路由规则都针对特定协议的匹配规则。如果流量符合这些特征,就会根据规则发送到服务注册表中的目标服务(或者目标服务的子集或版本)。

通过 Istio 实现灰度发布

什么是灰度发布?

灰度发布也叫金丝雀发布 ,是指通过控制流量的比例,实现新老版本的逐步更替。

比如对于服务 A 有 version1、 version2 两个版本 , 当前两个版本同时部署,但是 version1 比例 90% ,version2 比例 10% ,看运行效果,如果效果好逐步调整流量占比 80~20 ,70~30 ·····10~90 ,0,100 ,最终 version1 版本下线。

灰度发布的特点:

1)新老板共存
2)可以实时根据反馈动态调整占比
3)理论上不存在服务完全宕机的情况。
4)适合于服务的平滑升级与动态更新。

使用 istio 进行灰度发布

[root@k8snode1 ~]# docker load -i canary-v2.tar.gz 
[root@k8snode1 ~]# docker load -i canary-v1.tar.gz 
[root@k8smaster ~]# mkdir istio-canary
[root@k8smaster ~]# cd istio-canary/
[root@k8smaster istio-canary]# vim deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: appv1
  labels:
    app: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: v1
      apply: canary
  template:
    metadata:
      labels:
        app: v1
        apply: canary
    spec:
      containers:
      - name: nginx
        image: xianchao/canary:v1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: appv2
  labels:
    app: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: v2
      apply: canary
  template:
    metadata:
      labels:
        app: v2
        apply: canary
    spec:
      containers:
      - name: nginx
        image: xianchao/canary:v2
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
[root@k8smaster istio-canary]# kubectl apply -f deployment.yaml
[root@k8smaster istio-canary]# kubectl get deployment
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
appv1            1/1     1            1           2m4s
appv2            1/1     1            1           2m4s

创建 service
[root@k8smaster istio-canary]# vim service.yaml
apiVersion: v1
kind: Service 
metadata: 
  name: canary 
  labels: 
    apply: canary
spec: 
  selector:
    apply: canary
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
[root@k8smaster istio-canary]# kubectl apply -f service.yaml 
[root@k8smaster istio-canary]# kubectl get svc
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
canary        ClusterIP   10.104.100.198   <none>        80/TCP     16s

创建 gateway 
[root@k8smaster istio-canary]# vim gateway.yaml
apiVersion: networking.istio.io/v1beta1
kind: Gateway 
metadata: 
  name: canary-gateway
spec: 
  selector:
    istio: ingressgateway
  servers:
  - port: 
      number: 80
      name: http
      protocol: HTTP 
    hosts:
    - "*"
[root@k8smaster istio-canary]# kubectl apply -f gateway.yaml
[root@k8smaster istio-canary]# kubectl get gateway
NAME               AGE
canary-gateway     15s

创建 virtualservice(虚拟服务)
[root@k8smaster istio-canary]# vim virtual.yaml 
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: canary
spec:
  hosts:
  - "*"
  gateways:
  - canary-gateway
  http:
  - route:
    - destination:
        host: canary.default.svc.cluster.local
        subset: v1		#v1的全局量域名权重90
      weight: 90
    - destination:
        host: canary.default.svc.cluster.local
        subset: v2		#v2的全局量域名权重10
      weight: 10
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule						#目标规则
metadata:
  name: canary			
spec:
  host: canary.default.svc.cluster.local	#全局量域名
  subsets:
  - name: v1
    labels:
      app: v1
  - name: v2
    labels:
      app: v2
[root@k8smaster istio-canary]# kubectl apply -f virtual.yaml
[root@k8smaster istio-canary]# kubectl get virtualservice
NAME       GATEWAYS               HOSTS   AGE
canary     ["canary-gateway"]     ["*"]   2m22s
[root@k8smaster istio-canary]# kubectl get DestinationRule
NAME     HOST                               AGE
canary   canary.default.svc.cluster.local   2m54s
[root@k8smaster istio-canary]# vim /etc/hosts
192.168.11.129 productpage.paopao.cn
#添加一个域名解析,下面验证的时候域名也可以

验证金丝雀发布效果: 
[root@k8smaster istio-canary]# for i in `seq 1 100`; do curl productpage.paopao.cn;done > 1.txt
或者
[root@k8smaster istio-canary]# for i in `seq 1 100`; do curl 192.168.40.180:30871;done > 1.txt #请求100次
打开 1.txt 可以看到结果有 90 次出现 v1,10 次出现 canary-v2,符合我们预先设计的流量走向。 

istio 核心资源解读

Gateway

在 Kubernetes 环境中,Ingress controller(七层代理) 用于管理进入集群的流量。在 Istio 服务网格中 Istio Ingress Gateway 承担相应的角色,它使用新的配置模型(Gateway 和 VirtualServices)完成流量管理的功能。通过下图做一个总的描述。
【云原生 | 从零开始学istio】五、istio灰度发布以及核心资源_第2张图片
1、用户向某端口发出请求

2、负载均衡器监听端口,并将请求转发到集群中的某个节点上。Istio Ingress Gateway Service 会监听集群节点端口的请求

3、Istio Ingress Gateway Service 将请求交给 Istio Ingress Gateway Pod 处理。IngressGateway Pod 通过 Gateway 和 VirtualService 配置规则处理请求。其中,Gateway 用来配置端口、协议和证书;VirtualService 用来配置一些路由信息(找到请求对应处理的服务 App Service)

4、Istio Ingress Gateway Pod 将请求转给 App Service

5、最终的请求会交给 App Service 关联的 App Deployment 处理

[root@k8smaster istio-canary]# cat gateway.yaml 
apiVersion: networking.istio.io/v1beta1 
kind: Gateway 
metadata: 
  name: canary-gateway 
spec: 
  selector: 
    istio: ingressgateway 
  servers: 
  - port: 
      number: 80 
      name: http 
      protocol: HTTP 
    hosts: 
    - "*" 

网关是一个运行在网格边缘的负载均衡器,用于接收传入或传出的 HTTP/TCP 连接。主要工作是接受外部请求,把请求转发到内部服务。网格边缘的 Ingress 流量,会通过对应的 Istio IngressGateway Controller 进入到集群内部。
在上面这个 yaml 里我们配置了一个监听 80 端口的入口网关,它会将 80 端口的 http 流量导入到集群内对应的 Virtual Service上。
注意:hosts:

  • “*”
    *表示通配符,通过任何域名都可以访问

VirtualService

VirtualService 是 Istio 流量治理的一个核心配置,可以说是 Istio 流量治理中最重要、最复杂的。VirtualService 在形式上表示一个虚拟服务,将满足条件的流量都转发到对应的服务后端,这个服务后端可以是一个服务,也可以是在 DestinationRule 中定义的服务的子集。

[root@k8smaster istio-canary]# cat virtual.yaml 
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: canary
spec:
  hosts:
  - "*"
  gateways:
  - canary-gateway
  http:
  - route:
    - destination:
        host: canary.default.svc.cluster.local
        subset: v1
      weight: 90
    - destination:
        host: canary.default.svc.cluster.local
        subset: v2
      weight: 10
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: canary
spec:
  host: canary.default.svc.cluster.local
  subsets:
  - name: v1
    labels:
      app: v1
  - name: v2
    labels:
      app: v2

这个虚拟服务会收到上一个 gateway 中所有 80 端口来的 http 流量。

VirtualService 主要由以下部分组成
1、hosts:虚拟主机名称,如果在 Kubernetes 集群中,则这个主机名可以是 service 服务名。
hosts 字段列出了 virtual service 的虚拟主机。它是客户端向服务发送请求时使用的一个或多个地址,通过该字段提供的地址访问 virtual service,进而访问后端服务。在集群内部(网格内)使用时通常与 kubernetes 的 Service 同名;当需要在集群外部(网格外)访问时,该字段为 gateway 请求的地址,即与 gateway 的 hosts 字段相同。
hosts:

  • reviews
    virtual service 的主机名可以是 IP 地址、DNS 名称,也可以是短名称(例如 Kubernetes 服务短名称),该名称会被隐式或显式解析为全限定域名(FQDN),具体取决于 istio 依赖的平台。可以使用前缀通配符(“*”)为所有匹配的服务创建一组路由规则。virtual service 的 hosts 不一定是 Istio 服务注册表的一部分,它们只是虚拟目的地,允许用户为网格无法路由到的虚拟主机建立流量模型。

virtual service 的 hosts 短域名在解析为完整的域名时,补齐的 namespace 是 VirtualService 所在的命名空间,而非 Service 所在的命名空间。如上例的 hosts 会被解析为:reviews.default.svc.cluster.local。写的时候最好是全局量域名
hosts:

  • “*”
    *表示通配符,任何域名都可以,如在虚拟机配置 hosts 文件
    192.168.11.129 k8smaster hello.com.cn
    这样就可以在虚拟机通过域名 hello.com.cn 访问 istio 内部的服务了

扩展:virtualservice 配置路由规则
路由规则的功能是:满足 http.match 条件的流量都被路由到 http.route.destination,执行重定向(HTTPRedirect)、重写(HTTPRewrite)、重试(HTTPRetry)、故障注入(HTTPFaultInjection)、跨站(CorsPolicy)策略等。HTTPRoute 不仅可以做路由匹配,还可以做一些写操作来修改请求本身。
如下:

apiVersion: networking.istio.io/v1alpha3 
kind: VirtualService 
metadata: 
 name: reviews 
spec: 
 hosts: 
 - reviews 
 http: 
 - match: 
 - headers: 
 end-user: 
 exact: jason 
 route: 
 - destination: 
 host: reviews 
 subset: v2 
 - route: 
 - destination: 
 host: reviews 
 subset: v3 
在 http 字段包含了虚拟服务的路由规则,用来描述匹配条件和路由行为,它们把 HTTP/1.1、HTTP2 和 gRPC 等流量发送到 hosts 字段指定的目标。示例中的第一个路由规则有一个条件,以 match 字段开始。此路由接收来自 ”jason“ 用户的所有请求,把请求发送到 destination 指定的 v2 子集。 
 
路由规则优先级 
在上面例子中,不满足第一个路由规则的流量均流向一个默认的目标,该目标在第二条规则中指定。因此,第二条规则没有 match 条件,直接将流量导向 v3 子集。多路由规则详细配置可参考: https://istio.io/latest/zh/docs/reference/config/networking/virtualservice/#HTTPMatchRequest 

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 
 
路由规则是将特定流量子集路由到指定目标地址的工具。可以在流量端口,header字段,URI等内容上设置匹配条件。例如上面这个虚拟服务让用户发送请求到两个独立的服务ratings和reviews,相当于访问http://bookinfo.com/ratings和http://bookinfo.com/reviews,虚拟服务规则根据请求的 URI 把请求路由到特定的目标地址。 

2、Gateway:流量来源网关。 

3、路由
路由的 destination 字段指定了匹配条件的流量的实际地址。与 virtual service 的主机不同,该 host 必须是存在于 istio 的服务注册表(如 kubernetes services,consul services 等)中的真实目的地或由 ServiceEntries 声明的 hosts,否则 Envoy 不知道应该将流量发送到哪里。它可以是一个带代理的网格服务或使用 service entry 添加的非网格服务。在 kubernetes 作为平台的情况下,host 表示名为 kubernetes 的 service 名称: 
- destination: 
host: canary.default.svc.cluster.local 
subset: v1 
weight: 90	#权重,多少流量到这

DestinationRule

destination rule 是 istio 流量路由功能的重要组成部分。一个 virtual service 可以看作是如何将流量分发给特定的目的地,然后调用 destination rule 来配置分发到该目的地的流量。destination rule 在 virtual service 的路由规则之后起作用(即在 virtual service 的 math->route-destination 之后起作用,如果没匹配上rule才起作用,此时流量已经分发到真实的 service 上)应用于真实的目的地。可以使用 destination rule 来指定命名的服务子集,例如根据版本对服务的实例进行分组,然后通过 virtual service 的路由规则中的服务子集将控制流量分发到不同服务的实例中。

apiVersion: networking.istio.io/v1beta1 
kind: DestinationRule 
metadata: 
 name: canary 
spec: 
 host: canary.default.svc.cluster.local 
 subsets: 
 - name: v1 
 labels: 
 app: v1 
 - name: v2 
 labels: 
 app: v2 
在虚拟服务中使用 Hosts 配置默认绑定的路由地址,用 http.route 字段,设置 http 进入的路由地址,可以看到,上面导入到了目标规则为 v1 和 v2 的子集。 
 
v1 子集对应的是具有如下标签的 pod: 
selector: 
matchLabels: 
app: v1 
 
流量控制流程: 
Gateway->VirtaulService->TCP/HTTP Router->DestinationWeight->Subset:Port

写在最后

创作不易,如果觉得内容对你有帮助,麻烦给个三连关注支持一下我!如果有错误,请在评论区指出,我会及时更改!

目前正在更新的系列:从零开始学istio

感谢各位的观看,文章掺杂个人理解,如有错误请联系我指出~

你可能感兴趣的:(从零开始学istio,云原生,istio,kubernetes)