使用 Istio 进行路由策略的配置

本篇来讲一下如何使用 Istio 进行路由的配置,在这里直接使用 Istio 官方提供的案例应用来进行演示,首先部署 bookinfo 服务

$ kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml

部署完成后可以通过以下命令来看到 Pod 和 Service:

$ kubectl get pods
$ kubectl get services

用以下命令来验证部署成功:

$ kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -s productpage:9080/productpage | grep -o ".*"

成功时将看到输出为 Simple Bookstore App

到目前为止,部署的服务还无法在外网访问,需要配置一个Istio 网关来映射相应的路由。

$ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml

完成后用以下命令来验证,若是验证无误则表示网关已成功部署:

$ istioctl analyze

下面需要确定外网访问的 IP 和端口,在此之前,先确认自己的集群是否支持外部的负载均衡:

$ kubectl get svc istio-ingressgateway -n istio-system

这里的关键点就是看有没有 EXTERNAL-IP,若是有,则表示支持外部负载均衡,若没有则不支持。对于我们自己部署的 K8S 单机集群,默认是不支持的。

对于支持外部负载均衡的集群,使用以下命令来确认外部访问的 IP 和端口:

$ export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
$ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
$ export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].port}')

对于不支持外部负载均衡的集群,使用以下命令来确认外部访问的 IP 和端口:

$ export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')
$ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
$ export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')

如我的集群,得到的信息是以下:

$ echo $INGRESS_HOST
10.211.55.16
$ echo $INGRESS_PORT
30625
$ echo $SECURE_INGRESS_PORT
32307

此时在外部的浏览器上,即可以用以下 URL 访问到部署好的服务了:

http://10.211.55.16:30625/productpage

打开页面后进行几次刷新,会发现在页面右侧的 Books Reviews 处,会有三种呈现形式,如下:

image.png
image.png
image.png

通过查看 kubectl get pods 也可以发现,reviews 服务有三个,也就是说对于 reviews 的请求,被路由到了不同的 Pod 进行处理。

那这个过程中发生了什么呢?我们有必要来一探究竟。


首先通过 kubectl get pods 命令,查找到 productpage 的容器名称,在我本机上是 productpage-v1-65576bb7bf-gncds,有了这个名称后,就可以做很多事情了, 先查一下 Istio 的集群信息:

$ istioctl pc cluster productpage-v1-65576bb7bf-gncds | grep reviews

将会得到的输出是:

reviews.default.svc.cluster.local  9080  -  outbound  EDS

再看一下 reviews.default.svc.cluster.localendpoint,应当可以看到三个:

$ istioctl pc endpoint productpage-v1-65576bb7bf-gncds --cluster "outbound|9080||reviews.default.svc.cluster.local"

得到的结果如下,确实是三个,即是说请求确实会被路由到这三个 endpoint 之中

ENDPOINT             STATUS  OUTLIER CHECK  CLUSTER
192.168.235.243:9080 HEALTHY OK             outbound|9080||reviews.default.svc.cluster.local
192.168.235.244:9080 HEALTHY OK             outbound|9080||reviews.default.svc.cluster.local
192.168.235.246:9080 HEALTHY OK             outbound|9080||reviews.default.svc.cluster.local

那么具体是怎么进行路由的呢,我们需要查看路由信息:

$ istioctl pc route productpage-v1-65576bb7bf-gncds --name 9080 -o json

将会打出一个 json,这里只截取 reviews 的那一段:

{
    "name": "reviews.default.svc.cluster.local:9080",
    "domains": [
        "reviews.default.svc.cluster.local",
        "reviews.default.svc.cluster.local:9080",
        "reviews",
        "reviews:9080",
        "reviews.default.svc.cluster",
        "reviews.default.svc.cluster:9080",
        "reviews.default.svc",
        "reviews.default.svc:9080",
        "reviews.default",
        "reviews.default:9080",
        "10.109.41.164",
        "10.109.41.164:9080"
    ],
    "routes": [
        {
            "name": "default",
            "match": {
                "prefix": "/"
            },
            "route": {
                "cluster": "outbound|9080||reviews.default.svc.cluster.local",
                ... ...
            }
        }
    ]
}

这个配置即是表示,发往 reviews.default.svc.cluster.local:9080 的流量,将会被转发到 outbound|9080||reviews.default.svc.cluster.local,而这个 集群后面有三个 endpoint,所以在访问的时候,是轮询出现的,这直接解释了在请求时,三种不同的页面会轮询出现的现象。


那么,如果要只允许路由到一个 endpoint 要怎么办呢?我们就需要给 endpoint 进行标号:

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

再看一下集群的情况:

$ istioctl pc cluster productpage-v1-65576bb7bf-gncds | grep reviews
reviews.default.svc.cluster.local 9080 -  outbound EDS reviews.default
reviews.default.svc.cluster.local 9080 v1 outbound EDS reviews.default
reviews.default.svc.cluster.local 9080 v2 outbound EDS reviews.default
reviews.default.svc.cluster.local 9080 v3 outbound EDS reviews.default

可以看到已成功添加了,接着再看一下 endpoint 的情况:

$ istioctl pc endpoint productpage-v1-65576bb7bf-gncds --cluster "" | grep reviews
192.168.235.243:9080 HEALTHY OK outbound|9080|v2|reviews.default.svc.cluster.local
192.168.235.243:9080 HEALTHY OK outbound|9080||reviews.default.svc.cluster.local
192.168.235.244:9080 HEALTHY OK outbound|9080|v3|reviews.default.svc.cluster.local
192.168.235.244:9080 HEALTHY OK outbound|9080||reviews.default.svc.cluster.local
192.168.235.246:9080 HEALTHY OK outbound|9080|v1|reviews.default.svc.cluster.local
192.168.235.246:9080 HEALTHY OK outbound|9080||reviews.default.svc.cluster.local

可以看到的是,endpoint 也都被成功添加了。

下面就可以写一个配置,来让流量只转发到 v1:

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

然后执行命令让配置生效:

$ kubectl apply -f virtual-service-reviews-v1.yaml

再看一下路由的情况,会发现只能转发到 v1 了,如下:

{
    "name": "reviews.default.svc.cluster.local:9080",
    "domains": [
        "reviews.default.svc.cluster.local",
        "reviews.default.svc.cluster.local:9080",
        "reviews",
        "reviews:9080",
        "reviews.default.svc.cluster",
        "reviews.default.svc.cluster:9080",
        "reviews.default.svc",
        "reviews.default.svc:9080",
        "reviews.default",
        "reviews.default:9080",
        "10.109.41.164",
        "10.109.41.164:9080"
    ],
    "routes": [
        {
            "name": "default",
            "match": {
                "prefix": "/"
            },
            "route": {
                "cluster": "outbound|9080|v1|reviews.default.svc.cluster.local",
                ... ...
            }
        }
    ]
}

此时再刷新页面,就只有一种样式了,证明了流量只进入了 v1。

同理,我们还可以配置转发到 v2, v3:

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

如果要删除路由的规则,可以使用以下命令:

$ kubectl delete -f virtual-service-reviews-v1.yaml

这样在页面刷新时,就又会重回在三种样式里切换的状态了。


最后,再来看一个可视化的 DashBoard,有了 DashBoard 之后,可以方便直观的看到配置的情况,要安装 DashBoard 也不难:

$ kubectl apply -f samples/addons
$ kubectl rollout status deployment/kiali -n istio-system

部署成功后,可以用 kubectl get serivces -A 命令看到 kiali 服务,并获知其监听 20001 端口。按官方文档,可以用以下命令在本机访问 Kiali:

$ istioctl dashboard kiali

但是我们部署的是 Ubuntu Server 版,没有桌面,也没有浏览器,所以这一步注定会失败。解决方法也很容易,编辑一下服务:

$ kubectl edit service kiali -n istio-system

在 spec 配置下加入 externalIPs 即可:

spec:
  clusterIP: 10.105.225.205
  clusterIPs:
  - 10.105.225.205
  externalIPs:
  - 10.211.55.16
  ports:

直接保存即可,然后从外部浏览器使用以下 URL 即可以访问 Kiali:

http://10.211.55.16:20001/kiali

此时即可以看到服务的图表状态,并且看到请求的负载和链路:

image.png

你可能感兴趣的:(使用 Istio 进行路由策略的配置)