安装istio

一.istio是什么

Istio 提供一种简单的方式来为已部署的服务建立网络,该网络具有负载均衡、服务间认证、监控等功能,而不需要对服务的代码做任何改动。

1.istio 适用于容器或虚拟机环境(特别是 k8s),兼容异构架构。
2.istio 使用 sidecard(边车模式)代理服务的网络,不需要对业务代码本身做任何的改动。
3.HTTP、gRPC、WebSocket 和 TCP 流量的自动负载均衡。
4.istio 通过丰富的路由规则、重试、故障转移和故障注入,可以对流量行为进行细粒度控制;支持访问控制、速率限制和配额。
5.istio 对出入集群入口和出口中所有流量的自动度量指标、日志记录和跟踪。

6.官网地址:https://istio.io/

二.安装istio 

1.安装命令

curl -L https://git.io/getLatestIstio | ISTIO_VERSION=1.3.1 sh -

tar xvf istio-1.3.1-linux.tar.gz
cd istio-1.3.1

for i in install/kubernetes/helm/istio-init/files/crd*yaml; do kubectl apply -f $i; done

cp bin/istioctl /usr/local/bin/

kubectl apply -f install/kubernetes/istio-demo-auth.yaml

2.确认安装成功

[root@iZbp1at8fph52evh70atb0Z istio-1.3.1]# kubectl get svc -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
grafana ClusterIP 10.254.177.25 <none> 3000/TCP 105m
istio-citadel ClusterIP 10.254.103.41 <none> 8060/TCP,15014/TCP 105m
istio-egressgateway ClusterIP 10.254.26.180 <none> 80/TCP,443/TCP,15443/TCP 105m
istio-galley ClusterIP 10.254.135.225 <none> 443/TCP,15014/TCP,9901/TCP 105m
istio-ingressgateway LoadBalancer 10.254.26.17 <pending> 15020:33767/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:33657/TCP,15030:32629/TCP,15031:33429/TCP,15032:32859/TCP,15443:32484/TCP 105m
istio-pilot ClusterIP 10.254.124.196 <none> 15010/TCP,15011/TCP,8080/TCP,15014/TCP 105m
istio-policy ClusterIP 10.254.16.75 <none> 9091/TCP,15004/TCP,15014/TCP 105m
istio-sidecar-injector ClusterIP 10.254.20.113 <none> 443/TCP,15014/TCP 105m
istio-telemetry ClusterIP 10.254.246.184 <none> 9091/TCP,15004/TCP,15014/TCP,42422/TCP 105m
jaeger-agent ClusterIP None <none> 5775/UDP,6831/UDP,6832/UDP 105m
jaeger-collector ClusterIP 10.254.181.81 <none> 14267/TCP,14268/TCP 105m
jaeger-query ClusterIP 10.254.255.120 <none> 16686/TCP 105m
kiali ClusterIP 10.254.235.251 <none> 20001/TCP 105m
prometheus ClusterIP 10.254.61.136 <none> 9090/TCP 105m
tracing ClusterIP 10.254.179.233 <none> 80/TCP 105m
zipkin ClusterIP 10.254.178.103 <none> 9411/TCP 105m

[root@iZbp1at8fph52evh70atb0Z istio-1.3.1]# kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
grafana-575c7c4784-zgmkl 1/1 Running 0 106m
istio-citadel-59bff654d-gct58 1/1 Running 0 106m
istio-egressgateway-5b65dbcffd-tswvh 1/1 Running 0 106m
istio-galley-5cbcd84896-pm6ws 1/1 Running 0 106m
istio-grafana-post-install-1.3.1-zpzj8 0/1 Completed 0 106m
istio-ingressgateway-5897dddcff-tzqvz 1/1 Running 0 106m
istio-pilot-596fd8576f-q9j28 2/2 Running 0 106m
istio-policy-5fcc47c5b8-l89ts 2/2 Running 2 106m
istio-security-post-install-1.3.1-75gr7 0/1 Completed 0 106m
istio-sidecar-injector-6cf579975c-p7krt 1/1 Running 0 106m
istio-telemetry-548c5d7cfd-wmf4s 2/2 Running 2 106m
istio-tracing-8456d6548f-dxkhc 1/1 Running 0 106m
kiali-7dd44f7696-5fqms 1/1 Running 0 106m
prometheus-5679cb4dcd-x7ddv 1/1 Running 0 106m

三.安装bookinfo

1.bookinfo应用架构图

网站包括四个微服务:

productpage :本服务会调用 details 和 reviews 两个微服务,用来生成页面。
details :这个微服务包含了书籍的信息。
reviews :这个微服务包含了书籍相关的评论。它还会调用 ratings 微服务。
ratings :ratings 微服务中包含了由书籍评价组成的评级信息。
reviews 微服务有 3 个版本:

v1 版本不会调用 ratings 服务。
v2 版本会调用 ratings 服务,并使用 1 到 5 个黑色星形图标来显示评分信息。
v3 版本会调用 ratings 服务,并使用 1 到 5 个红色星形图标来显示评分信息。
访问效果如下:


2.安装步骤
cd istio-1.3.1
kubectl label namespace default istio-injection=enabled
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml

kubectl create -f samples/bookinfo/networking/bookinfo-gateway.yaml

3.确认安装成功

[root@iZbp1at8fph52evh70atb0Z istio-1.3.1]# kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details ClusterIP 10.254.148.189 <none> 9080/TCP 14h
kubernetes ClusterIP 10.254.0.1 <none> 443/TCP 57d
productpage ClusterIP 10.254.153.199 <none> 9080/TCP 14h
ratings ClusterIP 10.254.68.130 <none> 9080/TCP 14h
reviews ClusterIP 10.254.12.119 <none> 9080/TCP 14h

[root@iZbp1at8fph52evh70atb0Z istio-1.3.1]# kubectl get po
NAME READY STATUS RESTARTS AGE
details-v1-68fbb76fc-vh2f6 2/2 Running 0 14h
productpage-v1-6c6c87ffff-sp4dv 2/2 Running 0 14h
ratings-v1-7bdfd65ccc-mq5h9 2/2 Running 0 14h
reviews-v1-5c5b7b9f8d-9rrx8 2/2 Running 0 14h
reviews-v2-569796655b-4m584 2/2 Running 0 14h
reviews-v3-844bc59d88-djh6v 2/2 Running 0 14h

 

四.基于Bookinfo的流量管理配置1

在前面我们成功搭建并部署了istio及其其 Bookinfo 示例应用: 

目前搭建 Bookinfo 应用我们只用到了下面两个资源文件:

samples/bookinfo/platform/kube/bookinfo.yaml
[root@iZbp1at8fph52evh70atb0Z istio-1.3.1]# cat samples/bookinfo/platform/kube/bookinfo.yaml
# Copyright 2017 Istio Authors
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
##################################################################################################
# Details service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: details
  labels:
    app: details
    service: details
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: details
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bookinfo-details
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: details-v1
  labels:
    app: details
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: details
      version: v1
  template:
    metadata:
      labels:
        app: details
        version: v1
    spec:
      serviceAccountName: bookinfo-details
      containers:
      - name: details
        image: docker.io/istio/examples-bookinfo-details-v1:1.15.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
##################################################################################################
# Ratings service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: ratings
  labels:
    app: ratings
    service: ratings
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: ratings
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bookinfo-ratings
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ratings-v1
  labels:
    app: ratings
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ratings
      version: v1
  template:
    metadata:
      labels:
        app: ratings
        version: v1
    spec:
      serviceAccountName: bookinfo-ratings
      containers:
      - name: ratings
        image: docker.io/istio/examples-bookinfo-ratings-v1:1.15.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
##################################################################################################
# Reviews service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: reviews
  labels:
    app: reviews
    service: reviews
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: reviews
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bookinfo-reviews
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v1
  labels:
    app: reviews
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v1
  template:
    metadata:
      labels:
        app: reviews
        version: v1
    spec:
      serviceAccountName: bookinfo-reviews
      containers:
      - name: reviews
        image: docker.io/istio/examples-bookinfo-reviews-v1:1.15.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v2
  labels:
    app: reviews
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v2
  template:
    metadata:
      labels:
        app: reviews
        version: v2
    spec:
      serviceAccountName: bookinfo-reviews
      containers:
      - name: reviews
        image: docker.io/istio/examples-bookinfo-reviews-v2:1.15.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v3
  labels:
    app: reviews
    version: v3
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v3
  template:
    metadata:
      labels:
        app: reviews
        version: v3
    spec:
      serviceAccountName: bookinfo-reviews
      containers:
      - name: reviews
        image: docker.io/istio/examples-bookinfo-reviews-v3:1.15.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
##################################################################################################
# Productpage services
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: productpage
  labels:
    app: productpage
    service: productpage
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: productpage
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bookinfo-productpage
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: productpage-v1
  labels:
    app: productpage
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: productpage
      version: v1
  template:
    metadata:
      labels:
        app: productpage
        version: v1
    spec:
      serviceAccountName: bookinfo-productpage
      containers:
      - name: productpage
        image: docker.io/istio/examples-bookinfo-productpage-v1:1.15.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
samples/bookinfo/networking/bookinfo-gateway.yaml
[root@iZbp1at8fph52evh70atb0Z istio-1.3.1]# cat samples/bookinfo/networking/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:
    "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
  "*"
  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

 

前者就是通常的k8s定义的 Deployment 和 Service 的 yaml 文件,只是在部署时使用istioctl kube-inject对这个文件定义的pod注入了sidecar代理,后者定义了这个应用的外部访问入口gateway,以及应用内部 productpage 服务的VirtualService规则,而其他内部服务的访问规则还没有被定义。

可以看到当前集群中的gateway:

[root@iZbp1at8fph52evh70atb0Z istio-1.3.1]# kubectl get gateway --all-namespaces
NAMESPACE NAME AGE
default bookinfo-gateway 14h
[root@iZbp1at8fph52evh70atb0Z istio-1.3.1]# istioctl get gateway
GATEWAY NAME HOSTS NAMESPACE AGE
bookinfo-gateway * default 14h


现在访问应用界面并刷新,会看到 Reviews 有时不会显示评分,有时候会显示不同样式的评分,因为后面有3个不同的Reviews 服务版本,而没有配置该服务的路由规则route rule的情况下,该服务的几个实例会被随机访问到,有的版本服务会进一步调用 Ratings 服务,有的不会。

不同服务版本访问规则的基本使用

现在我们来对 Reviews 服务添加一条路由规则,启用samples/bookinfo/networking/virtual-service-reviews-v3.yaml 定义的VirtualService规则,内容如下:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v3

这样,所有访问 reviews 服务的流量就会被引导到 reviews 服务对应的 subset 为 v3 的 Pod 中。启用这条规则:

[root@iZbp1at8fph52evh70atb0Z istio-1.3.1]# istioctl create -f samples/bookinfo/networking/virtual-service-reviews-v3.yaml

Command "create" is deprecated, Use `kubectl create` instead (see https://kubernetes.io/docs/tasks/tools/install-kubectl)

Created config virtual-service/default/reviews at revision 7715128


然后查看所有的路由规则:

[root@iZbp1at8fph52evh70atb0Z istio-1.3.1]# istioctl get virtualservices

Command "get" is deprecated, Use `kubectl get` instead (see https://kubernetes.io/docs/tasks/tools/install-kubectl)

VIRTUAL-SERVICE NAME   GATEWAYS           HOSTS     #HTTP     #TCP      NAMESPACE   AGE

bookinfo               bookinfo-gateway   *             1        0      default     15h

reviews                                   reviews       1        0      default     25s


我们可以看到 reviews 的VirtualService已经创建成功了,但是此时刷新应用页面,发现访问 Reviews 失败了: 

这是因为我们还没有创建DestinationRuleDestinationRuleVirtualService中指定的subset与 pod 的{labels:{version: v3}}关联起来。

在 samples/bookinfo/networking/destination-rule-all.yaml 文件中有定义所有该应用中要用到的所有DestinationRule,其中有一段就是对 Reviews 相关的 DestinationRule 的定义:

---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
  - name: v3
    labels:
      version: v3

我们可以看到 DestinationRule 中定义了 subsets 集合,其中 labels 就和我们之前 service 的 labelselector 一样是去匹配 Pod 的 labels 标签的,比如我们这里 subsets 中就包含一个名为 v3 的 subset,而这个 subset 匹配的就是具有 version=v3 这个 label 标签的 Pod 集合,再回到之前的 samples/bookinfo/platform/kube/bookinfo.yaml 文件中,我们可以发现 reviews 的 Deployment 确实有声明不同的 labels->version:

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: reviews-v3
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: reviews
        version: v3
    spec:
      containers:
      - name: reviews
        image: istio/examples-bookinfo-reviews-v3:1.8.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080

这样我们就通过 DestinationRule 将 VirtualService 与 service 不同的版本关联起来了。

现在我们直接创建 DestinationRule 资源:

$ istioctl create -f samples/bookinfo/networking/destination-rule-all.yaml
Created config destination-rule/default/productpage at revision 31191609
Created config destination-rule/default/reviews at revision 31191610
Created config destination-rule/default/ratings at revision 31191611
Created config destination-rule/default/details at revision 31191612

创建完成后,我们就可以查看目前我们网格中的 DestinationRules:

$ istioctl get destinationrule
[root@iZbp1at8fph52evh70atb0Z istio-1.3.1]#  istioctl get destinationrule
Command "get" is deprecated, Use `kubectl get` instead (see https://kubernetes.io/docs/tasks/tools/install-kubectl)
DESTINATION-RULE NAME   HOST          SUBSETS                      NAMESPACE   AGE
details                 details       v1,v2                        default     14h
productpage             productpage   v1                           default     14h
ratings                 ratings       v1,v2,v2-mysql,v2-mysql-vm   default     14h
reviews                 reviews       v1,v2,v3                     default     14h

此时再访问应用就成功了,多次刷新页面发现 Reviews 都展示的是 v3 版本带红色星的 Ratings,说明我们VirtualService 的配置成功了。

基于权重的服务访问规则使用

刚刚我们演示的基于不同服务版本的服务网格的控制,现在我们来演示下基于权重的服务访问规则的使用。

首先移除刚刚创建的 VirtualService 对象:

$ istioctl delete virtualservice reviews
Deleted config: virtualservice reviews
$ istioctl get virtualservices
VIRTUAL-SERVICE NAME   GATEWAYS           HOSTS     #HTTP #TCP NAMESPACE AGE
bookinfo               bookinfo-gateway   *             1        0      default     46m

现在我们再去访问 Bookinfo 应用又回到最初随机访问 Reviews 的情况了。现在我们查看文件 samples/bookinfo/networking/virtual-service-reviews-80-20.yaml 的定义:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 80
    - destination:
        host: reviews
        subset: v2
      weight: 20

这个规则定义了 80% 的对 Reviews 的流量会落入 v1 这个 subset,就是没有 Ratings 的这个服务,20% 会落入 v2 带黑色 Ratings 的这个服务,然后我们创建这个资源对象:

$ kubectl create -f samples/bookinfo/networking/virtual-service-reviews-80-20.yaml
virtualservice.networking.istio.io "reviews" created
$ istioctl get virtualservices
VIRTUAL-SERVICE NAME   GATEWAYS           HOSTS     #HTTP #TCP NAMESPACE AGE
bookinfo               bookinfo-gateway   *             1        0      default     55m
reviews                                   reviews       1        0      default     24s

我们查看当前网格中的 virtualservices 对象,可以看到已经有 reviews 了,证明已经创建成功了,由于上面我们已经将应用中所有的 DestinationRules 都已经创建过了,所以现在我们直接访问应用就可以了,我们多次刷新,可以发现没有出现 Ratings 的次数与出现黑色星 Ratings 的比例大概在4:1左右,并且没有红色星的 Ratings 的情况出现,说明我们配置的 VirtualService 规则生效了。

这就是基于权重的服务访问规则的使用方法。

基于请求内容的服务访问规则使用

除了上面基于服务版本和服务权重的方式控制服务访问之外,我们还可以基于请求内容来进行访问控制。

同样,将上面创建的 VirtualService 对象删除:

$ istioctl delete virtualservice reviews
Deleted config: virtualservice reviews
$ istioctl get virtualservices
VIRTUAL-SERVICE NAME   GATEWAYS           HOSTS     #HTTP #TCP NAMESPACE AGE
bookinfo               bookinfo-gateway   *             1        0      default     46m

查看文件 samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml 的定义:

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

这个 VirtualService 对象定义了对 reviews 服务访问的 match 规则。意思是如果当前请求的 header 中包含 jason 这个用户信息,则只会访问到 v2 的 reviews 这个服务版本,即都带星的样式,如果不包含该用户信息,则都直接将流量转发给 v3 这个 reviews 的服务。

我们先不启用这个 VirtualService,现在我们去访问下 Bookinfo 这个应用: 

右上角有登录按钮,在没有登录的情况下刷新页面,reviews 服务是被随机访问的,可以看到有带星不带星的样式,点击登录,在弹窗中 User Name 输入 jason,Password为空,登录: 

再刷新页面,可以看到跟未登录前的访问规则一样,也是随机的。

现在我们来创建上面的 VirtualService 这个对象:

$ kubectl create -f samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml
virtualservice.networking.istio.io "reviews" created
$ istioctl get virtualservice
VIRTUAL-SERVICE NAME   GATEWAYS           HOSTS     #HTTP #TCP NAMESPACE AGE
bookinfo               bookinfo-gateway   *             1        0      default     1h
reviews                                   reviews       2        0      default     47s

此时再回去刷新页面,发现一直都是黑星的 Reviews 版本(v2)被访问到了。 注销退出后再访问,此时又一直是红色星的版本(v3)被访问了。

说明我们基于 headers->end-user->exact:jason 的控制规则生效了。在 productpage 服务调用 reviews 服务时,登录的情况下会在 header 中带上用户信息,通过 exact 规则匹配到相关信息后,流量被引向了上面配置的v2版本中。

这里要说明一下match的匹配规则:

All conditions inside a single match block have AND semantics, while the list of match blocks have OR semantics. The rule is matched if any one of the match blocks succeed.

意思是一个 match 块里的条件是需要同时满足才算匹配成功的,如:

- match:
    - uri:
        prefix: "/wpcatalog"
      port: 443

多个 match 块之间是只要有一个 match 匹配成功了,就会走向它指定的服务版本去,而忽略其他的。我们的示例中在登录的条件下,满足第一个 match,所以服务一直会访问到 v2 版本。退出登录后,没有 match 规则满足匹配,会走向最后一个 route 规则,即 v3 版本。

到这里,我们就和大家一起学习了基于不同服务版本、权重以及请求内容来控制服务流量的配置,后面我们将进一步学习流量管理的其他用法。

 

五.基于Bookinfo的流量管理配置2

上节课我们和大家一起学习了基于不同服务版本、权重以及请求内容来控制服务流量的配置,这节课我们继续和大家学习流量控制的其他方法。

延迟访问故障注入

接上节课的内容,第一步还是需要移除之前创建的 VirtualService:

$ istioctl delete virtualservice reviews
Deleted config: virtualservice reviews
$ istioctl get virtualservice
VIRTUAL-SERVICE NAME   GATEWAYS           HOSTS     #HTTP #TCP NAMESPACE AGE
bookinfo               bookinfo-gateway   *             1        0      default     6d

然后我们查看 istio 样例文件夹下面的文件:samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml 的内容

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - headers:
        end-user:
          exact: jason
    fault:
      delay:
        percent: 100
        fixedDelay: 7s
    route:
    - destination:
        host: ratings
        subset: v1
  - route:
    - destination:
        host: ratings
        subset: v1

这个 VirtualService 定义了一个在 jason 登录的情况下,访问 ratings 服务的 100% 的 7s 访问延迟。前面我们知道,Bookinfo 这个示例 productpage 服务调用 reviews,reviews 的不同版本会对 ratings 进行不同的调用,其中 reviews-v1 不调用 ratings,reviews-v2 和 reviews-v3 会调用 ratings,并做不同样式的渲染。并且在 productpage 访问 reviews 时,代码中有硬编码 6s 中的访问超时限制,而 reviews 访问 ratings 编码了 10s 的访问超时限制。

了解这一点后,我们现在来创建这个 VirtualService 资源对象:

$ kubectl create -f  samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml
virtualservice.networking.istio.io "ratings" created
$ istioctl get virtualservice
VIRTUAL-SERVICE NAME   GATEWAYS           HOSTS     #HTTP #TCP NAMESPACE AGE
bookinfo               bookinfo-gateway   *             1        0      default     6d
ratings                                   ratings       2        0      default     49s

创建完成后,前往 Bookinfo 应用,登录 jason,打开浏览器的Network,刷新页面,发现请求加载很慢,大约 6s 后,出现如下界面: 

看到 productpage 的请求大约耗时 6s,Reviews显示 unavailable 的错误。因为此时 reviews 请求 ratings 的访问超过了 6s 还没有响应,使得 productpage 中的硬编码的超时设置生效了。

当然有的时候我们也能成功访问到 reviews-v1 版本,因为此时并没有进一步访问 ratings 服务,所以一切都是正常的,会显示不带星的界面: bookinfo reviews v1

通过这种超时故障注入,可以帮助我们方便地发现服务间相互访问中存在的潜在问题。

中断访问故障注入

同样移除刚才的 VirutualService 资源对象:

$ istioctl delete virtualservice ratings
Deleted config: virtualservice ratings
$ istioctl get virtualservice
VIRTUAL-SERVICE NAME   GATEWAYS           HOSTS     #HTTP #TCP NAMESPACE AGE
bookinfo               bookinfo-gateway   *             1        0      default     6d

然后我们查看 istio 样例文件夹下面的文件:samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml 的内容

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - headers:
        end-user:
          exact: jason
    fault:
      abort:
        percent: 100
        httpStatus: 500
    route:
    - destination:
        host: ratings
        subset: v1
  - route:
    - destination:
        host: ratings
        subset: v1

通过上面的这个 yaml 文件我们可以看出这个 VirtualService 资源对象配置了在 jason 登录时,reviews 对 ratings 访问时 100% 的返回一个500错误响应。

然后同样创建这个资源对象:(用 kubectl 或者 istioctl 工具都是可以的)

$ istioctl create -f samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml
Created config virtual-service/default/ratings at revision 32143909
$ istioctl get virtualservice
VIRTUAL-SERVICE NAME   GATEWAYS           HOSTS     #HTTP #TCP NAMESPACE AGE
bookinfo               bookinfo-gateway   *             1        0      default     6d
ratings                                   ratings       2        0      default     4s

现在我们回到 BookInfo 应用,登录 jason,刷新页面,可以看到下面的现象: 

我们可以看到 reviews 对 ratings 的访问失败了,服务上面我们 VirtualService 资源对象的配置。

不同环境服务访问

使用 istio 的路由规则管理,还可以配置对不同环境(prod, staging, dev等)的同一服务的访问规则。由于我的实验环境没有搭建多环境的集群,这里指使用官方的demo来做描述。

apiVersion: networking.istio.io/v1alpha3
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

通常在一个集群中如果搭建多环境的情况可以使用namespace来进行划分,而使用上面的方式就可以实现对其他 namepaces 的服务的访问。

上面的 VirtualService 对象定义了对 namespace 为 prod 中的 productpage 服务的访问,会在 5s 的 timeout 后才会调用该服务。这个访问规则没有定义 subset,istio 会获取productpage.prod.svc.cluster.local 服务对应的所有实例并向其他服务实例注入这些实例的信息到他们的 load balancing pool 中去。

同时注意这个 VirtualService 是定义在 istio-system 的namespace中的,此时要使用完整的服务域名:productpage.prod.svc.cluster.local,这样这条规则所属的 namespace 才会解析到其他 namespace 的服务。

服务网格外的流量管理

为了控制服务网格外的服务的流量访问,外部的服务必须首先使用一个ServiceEntry对象加入到 istio 的内部 service registry 中,服务网格才会知道如何导向这些外部服务的流量。

为了测试这个功能,我们使用 istio 样例中的 sleep 应用来验证改功能,查看 samples/sleep/sleep.yaml 文件内容:

apiVersion: v1
kind: Service
metadata:
  name: sleep
  labels:
    app: sleep
spec:
  ports:
  - port: 80
    name: http
  selector:
    app: sleep
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: sleep
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: sleep
    spec:
      containers:
      - name: sleep
        image: tutum/curl
        command: ["/bin/sleep","infinity"]
        imagePullPolicy: IfNotPresent
---

这其实就是一个简单的应用,通过 Deployment 进行控制,通过 Service 暴露服务,现在我们来部署该应用:

$ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml)
service "sleep" created
deployment.extensions "sleep" created

待应用部署完成后,我们进入该应用容器内部执行一些测试操作:

$ export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
$ kubectl exec -it $SLEEP_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
HTTP/1.1 404 Not Found
date: Mon, 15 Oct 2018 17:30:13 GMT
server: envoy
content-length: 0

可以看到会返回上面的404的信息,因为该域名不在当前的服务网格中,默认情况下 istio 不允许访问服务网格外部的 URL,即服务网格中对未知的服务请求会被丢弃。这就需要我们来创建一个 ServiceEntry 对象,将外部的访问服务引入到服务网格中来。

例如下面的规则定义了一个访问 edition.cnn.com 的服务的 ServiceEntry:(cnn-service-entry.yaml)

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: cnn
spec:
  hosts:
  - edition.cnn.com
  ports:
  - number: 80
    name: http-port
    protocol: HTTP
  - number: 443
    name: https
    protocol: HTTPS
  resolution: DNS

现在我们来部署上面的 ServiceEntry 资源:

$ istioctl create -f cnn-service-entry.yaml
Created config service-entry/default/cnn at revision 32149308
$ istioctl get serviceentry
SERVICE-ENTRY NAME   HOSTS             PORTS               NAMESPACE   AGE
cnn                  edition.cnn.com   HTTP/80,HTTPS/443   default     1m

现在我们再去上面的 sleep 容器中执行上面的测试请求:

$ kubectl exec -it $SLEEP_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
HTTP/1.1 301 Moved Permanently
server: envoy
retry-after: 0
content-length: 0
cache-control: public, max-age=600
location: https://edition.cnn.com/politics
accept-ranges: bytes
date: Mon, 15 Oct 2018 17:31:49 GMT
via: 1.1 varnish
set-cookie: countryCode=CN; Domain=.cnn.com; Path=/
set-cookie: geoData=beijing|BJ|100000|CN|AS; Domain=.cnn.com; Path=/
x-served-by: cache-nrt6143-NRT
x-cache: HIT
x-cache-hits: 0
x-envoy-upstream-service-time: 418

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
x-servedByHost: ::ffff:172.17.20.12
access-control-allow-origin: *
cache-control: max-age=60
content-security-policy: default-src 'self' blob: https://*.cnn.com:* http://*.cnn.com:* *.cnn.io:* *.cnn.net:* *.turner.com:* *.turner.io:* *.ugdturner.com:* courageousstudio.com *.vgtf.net:*; script-src 'unsafe-eval' 'unsafe-inline' 'self' *; style-src 'unsafe-inline' 'self' blob: *; child-src 'self' blob: *; frame-src 'self' *; object-src 'self' *; img-src 'self' data: blob: *; media-src 'self' data: blob: *; font-src 'self' data: *; connect-src 'self' *; frame-ancestors 'self' https://*.cnn.com:* http://*.cnn.com https://*.cnn.io:* http://*.cnn.io:* *.turner.com:* courageousstudio.com;
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
Via: 1.1 varnish
Content-Length: 1704385
Accept-Ranges: bytes
Date: Mon, 15 Oct 2018 09:31:53 GMT
Via: 1.1 varnish
Age: 402
Connection: keep-alive
Set-Cookie: countryCode=CN; Domain=.cnn.com; Path=/
Set-Cookie: geoData=beijing|BJ|100000|CN|AS; Domain=.cnn.com; Path=/
Set-Cookie: tryThing00=1284; Domain=.cnn.com; Path=/; Expires=Mon Jul 01 2019 00:00:00 GMT
Set-Cookie: tryThing01=8877; Domain=.cnn.com; Path=/; Expires=Fri Mar 01 2019 00:00:00 GMT
Set-Cookie: tryThing02=9979; Domain=.cnn.com; Path=/; Expires=Wed Jan 01 2020 00:00:00 GMT
X-Served-By: cache-iad2129-IAD, cache-hnd18720-HND
X-Cache: HIT, HIT
X-Cache-Hits: 2, 1
X-Timer: S1539595913.083337,VS0,VE5
Vary: Accept-Encoding

现在我们发现可以正常返回内容了,返回200,证明请求成功了。

说明:-L让 curl 跟随连接进行重定向。这里服务器直接返回的 301 重定向响应,要求客户端再使用HTTPS的方式对 https://edition.cnn.com/politics 地址进行访问,第二次访问才返回了200的成功码。

除此之外,我们还可以进一步配置egress gateway,使这些对外部的流量访问经由egress去到外部。

现在我们在 istio 中定义一个egress gateway对象来注册允许从服务网格出去的服务,创建一个用于edition.cnn.com 的 egress gateway 对象:(cnn-egress-gateway.yaml)

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: istio-egressgateway
spec:
  selector:
    istio: egressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - edition.cnn.com

除了上面的 engress gateway 对象之外,我们还需要创建 VirtualService 和 DestinationRule 这两个资源对象:(cnn-virtual-rule.yaml)

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: direct-cnn-through-egress-gateway
spec:
  hosts:
  - edition.cnn.com
  gateways:
  - istio-egressgateway
  - mesh
  http:
  - match:
    - gateways:
      - mesh
      port: 80
    route:
    - destination:
        host: istio-egressgateway.istio-system.svc.cluster.local
        subset: cnn
        port:
          number: 80
      weight: 100
  - match:
    - gateways:
      - istio-egressgateway
      port: 80
    route:
    - destination:
        host: edition.cnn.com
        port:
          number: 80
      weight: 100

---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: egressgateway-for-cnn
spec:
  host: istio-egressgateway.istio-system.svc.cluster.local
  subsets:
  - name: cnn

然后创建上面3个资源对象:

$ istioctl create -f cnn-virtual-rule.yaml
Created config virtual-service/default/direct-cnn-through-egress-gateway at revision 32149507
Created config destination-rule/default/egressgateway-for-cnn at revision 32149508
$ istioctl create -f cnn-egress-gateway.yaml
Created config gateway/default/istio-egressgateway at revision 32149519

创建完成后,现在我们再去 sleep 容器执行下上面的请求:

$ kubectl exec -it $SLEEP_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
HTTP/1.1 301 Moved Permanently
server: envoy
retry-after: 0
content-length: 0
cache-control: public, max-age=600
location: https://edition.cnn.com/politics
accept-ranges: bytes
date: Mon, 15 Oct 2018 17:33:57 GMT
via: 1.1 varnish
set-cookie: countryCode=CN; Domain=.cnn.com; Path=/
set-cookie: geoData=beijing|BJ|100000|CN|AS; Domain=.cnn.com; Path=/
x-served-by: cache-nrt6151-NRT
x-cache: HIT
x-cache-hits: 0
x-envoy-upstream-service-time: 439

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
x-servedByHost: ::ffff:172.17.25.25
access-control-allow-origin: *
cache-control: max-age=60
content-security-policy: default-src 'self' blob: https://*.cnn.com:* http://*.cnn.com:* *.cnn.io:* *.cnn.net:* *.turner.com:* *.turner.io:* *.ugdturner.com:* courageousstudio.com *.vgtf.net:*; script-src 'unsafe-eval' 'unsafe-inline' 'self' *; style-src 'unsafe-inline' 'self' blob: *; child-src 'self' blob: *; frame-src 'self' *; object-src 'self' *; img-src 'self' data: blob: *; media-src 'self' data: blob: *; font-src 'self' data: *; connect-src 'self' *; frame-ancestors 'self' https://*.cnn.com:* http://*.cnn.com https://*.cnn.io:* http://*.cnn.io:* *.turner.com:* courageousstudio.com;
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
Via: 1.1 varnish
Content-Length: 1704385
Accept-Ranges: bytes
Date: Mon, 15 Oct 2018 09:34:01 GMT
Via: 1.1 varnish
Age: 127
Connection: keep-alive
Set-Cookie: countryCode=CN; Domain=.cnn.com; Path=/
Set-Cookie: geoData=beijing|BJ|100000|CN|AS; Domain=.cnn.com; Path=/
Set-Cookie: tryThing00=6048; Domain=.cnn.com; Path=/; Expires=Mon Jul 01 2019 00:00:00 GMT
Set-Cookie: tryThing01=0013; Domain=.cnn.com; Path=/; Expires=Fri Mar 01 2019 00:00:00 GMT
Set-Cookie: tryThing02=9990; Domain=.cnn.com; Path=/; Expires=Wed Jan 01 2020 00:00:00 GMT
X-Served-By: cache-iad2127-IAD, cache-tyo19949-TYO
X-Cache: HIT, MISS
X-Cache-Hits: 1, 0
X-Timer: S1539596041.954017,VS0,VE471
Vary: Accept-Encoding

现在我们发现可以正常返回内容,这时我们去查看egressgateway的 Pod 中的容器日志:

$ kubectl logs $(kubectl get pod -l istio=egressgateway -n istio-system -o jsonpath='{.items[0].metadata.name}') -n istio-system | tail
......
[2018-10-15T17:33:57.261Z] "GET /politics HTTP/2" 301 - 0 0 437 429 "10.244.4.206" "curl/7.35.0" "6d4f2ac3-0957-97a5-961a-241c7fd72536" "edition.cnn.com" "151.101.129.67:80"
......

可以看到有一条上面的 GET /politics 的日志信息,说明访问经过了 egress gateway 出去了。

规则说明

最后简单总结下 VirtualService 和 DestinationRule 的一些配置规则。

VirtualService rules

 DestinationRule rules

六.监控
在 Istio 中,可以让 Mixer 自动为所有的网格内流量生成和报告新的指标以及新的日志流。下面以 book-info 应用为例,展示分布式追踪。

1.Prometheus
用作指标采集与查询。


Prometheus 指标采集 job


分布式追踪
虽然 Istio 代理能够自动发送 Span 信息,但还是需要一些辅助手段来把整个跟踪过程统一起来。应用程序应该自行传播跟踪相关的 HTTP Header,这样在代理发送 Span 信息的时候,才能正确的把同一个跟踪过程统一起来。

productpage 服务访问总览


调用链追踪


服务拓扑图


2.grafana
使用 grafana 对 istio 本身和服务网格进行监控。

 

服务大盘
client workload
service workload

posted @ 2020-06-02 23:52  $world  阅读(331)  评论(0编辑  收藏  举报