本篇来讲一下如何使用 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 ".* "
成功时将看到输出为
。
到目前为止,部署的服务还无法在外网访问,需要配置一个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
处,会有三种呈现形式,如下:
通过查看 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.local
的 endpoint
,应当可以看到三个:
$ 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
此时即可以看到服务的图表状态,并且看到请求的负载和链路: