本文实验链路:h5 > demo-a > demo-b
在实验过程出现跨域问题,直接使用istio解决,没有调整后端代码
h5应用版本准备
版本代码区分
实验需要h5项目有两个版本,为了区分,在istioDemo页面最显眼的位置显示不同的文字。
v1版本:
latest版本:
打包docker镜像
打包方法参考 docker: 打包h5项目的镜像
本文打了两个版本的镜像,如下:
部署h5应用
应用部署到命名空间:istio-demos
关于命名空间的创建以及添加istio-injection标签参考istio gateway入口流量路由管控#二、应用部署
创建Service和Deployment
创建yaml文件: demo-h5-vault.yaml
apiVersion: v1
kind: Service
metadata:
name: demo-istio-h5
labels:
app: demo-istio-h5
service: demo-istio-h5
spec:
ports:
- name: http
port: 80
targetPort: 80
selector:
app: demo-istio-h5
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-istio-h5-v1
spec:
replicas: 1
selector:
matchLabels:
app: demo-istio-h5
version: v1
template:
metadata:
labels:
app: demo-istio-h5
version: v1
spec:
serviceAccountName: istio-demo
containers:
- image: demo-istio-h5:v1.0
imagePullPolicy: IfNotPresent
name: demo-istio-h5
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-istio-h5-latest
spec:
replicas: 1
selector:
matchLabels:
app: demo-istio-h5
version: latest
template:
metadata:
labels:
app: demo-istio-h5
version: latest
spec:
serviceAccountName: istio-demo
containers:
- image: demo-istio-h5:latest
imagePullPolicy: IfNotPresent
name: demo-istio-h5
ports:
- containerPort: 80
执行kubectl命令创建service和deployment
kubectl apply -f demo-h5-vault.yaml -n istio-demos
h5 路由管理
创建定义istio Gateway和VirtualService的yaml文件:demo-h5-gateway-multiversion.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: demo-istio-h5-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "demoh5.istiodemos.com"
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: demo-istio-h5-dr
spec:
host: demo-istio-h5
trafficPolicy:
loadBalancer:
simple: LEAST_CONN
subsets:
- name: v1
labels:
version: v1
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
- name: latest
labels:
version: latest
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: demo-istio-h5-vs
spec:
hosts:
- "demoh5.istiodemos.com"
gateways:
- demo-istio-h5-gateway
http:
- match:
- queryParams:
v:
exact: v1
# regex: ae\d+$
route:
- destination:
host: demo-istio-h5
subset: v1
- route:
- destination:
host: demo-istio-h5
subset: latest
该yaml文件中将v1版本和latest版本做了路由定义,规则如下:
将url参数v=v1时,路由到v1版本的demo-istio-h5
否则都路由到latest版本的demo-istio-h5
创建istio Gateway和VirtualService。
kubectl apply -f demo-h5-gateway-multiversion.yaml -n istio-demos
接下来就可以通过域名 demoh5.istiodemos.com 访问demo-istio-h5应用了,且还会根据参数路由到不同的版本。
关于域名映射的方法可以参考istio gateway入口流量路由管控三、外部访问应用
下面以访问url做示例:
http://demoh5.istiodemos.com/?v=v1#/istioDemo => v1版本
http://demoh5.istiodemos.com/#/istioDemo => latest版本
部署后端应用
demo-a和demo-b的部署参考以下两篇文章:
istio gateway入口流量路由管控
istio 访问网格内的服务(路由管理)
istio 解决跨域问题
现在测试通过h5访问后端接口: http://demoa.istiodemos.com/test/request-b?forward=istio-springboot-demo-b&a=av356
访问结果:
出现跨域问题,调整下VirtualService istio-springboot-demo-a-vs, 添加跨域的策略(corsPolicy),yaml内容在demo-a-gateway-multiversion.yaml
...
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: istio-springboot-demo-a-vs
spec:
hosts:
- "*"
gateways:
- istio-springboot-demo-a-gateway
http:
- match:
- queryParams:
a:
# exact: ad
regex: av\d+$
route:
- destination:
host: istio-springboot-demo-a
subset: v1
corsPolicy:
allowOrigins:
- regex: "http://.*"
allowMethods:
- POST
- GET
allowHeaders:
- XSRF-TOKEN
- xsrfHeaderName
- X-XSRF-TOKEN
- maxContentLength
- maxBodyLength
- route:
- destination:
host: istio-springboot-demo-a
subset: latest
corsPolicy:
allowOrigins:
- regex: "http://.*"
allowMethods:
- POST
- GET
allowHeaders:
- XSRF-TOKEN
- xsrfHeaderName
- X-XSRF-TOKEN
- maxContentLength
- maxBodyLength
执行kubectl apply 命令将调整后的内容生效
kubectl apply -f demo-a-gateway-multiversion.yaml -n istio-demos
再来看看访问结果,跨域问题没有了
实验结果
路由规则
应用 | 规则 | 描述 |
---|---|---|
h5 | queryParams.v.exact: v1 | url参数v=v1时路由到v1版本,否则都路由到latest版本 |
demo-a | queryParams.a.regex: av\d+$ | url参数a匹配正则av\d+$时路由到v1版本,否则路由到latest版本| |
demo-b | queryParams.a.regex: ae\d+$ | url参数a匹配正则ae\d+$时路由到v1版本,否则路由到latest版本| |
访问结果
h5应用
请求URL | h5版本 |
---|---|
http://demoh5.istiodemos.com/?v=v1#/istioDemo | v1版本 |
http://demoh5.istiodemos.com/?v=v1f#/istioDemo | latest版本 |
http://demoh5.istiodemos.com/#/istioDemo | latest版本 |
后端应用
请求url | demo-a版本 | demo-b版本 |
---|---|---|
http://demoa.istiodemos.com/test/request-b?forward=istio-springboot-demo-b&a=av356 | v1版本 | latest版本 |
http://demoa.istiodemos.com/test/request-b?forward=istio-springboot-demo-b&a=ae356 | latest版本 | v1版本 |
http://demoa.istiodemos.com/test/request-b?forward=istio-springboot-demo-b&a=a356 | latest版本 | latest版本 |
下面是以上三个url返回的内容截图
-
http://demoa.istiodemos.com/test/request-b?forward=istio-springboot-demo-b&a=av356
-
http://demoa.istiodemos.com/test/request-b?forward=istio-springboot-demo-b&a=ae356
-
http://demoa.istiodemos.com/test/request-b?forward=istio-springboot-demo-b&a=a356
小结
通过istio可以非常方便的定义http 入口请求的路由规则和网格内的访问的路由规则,不管是后端API还是h5应用。
但是对于更复杂的路则规则本文并没有去尝试。
附录
h5 istioDemo页面的代码
<template>
<div>
<h2> Istio Demo Latest</h2>
<el-form>
<el-form-item label="Domain">
<el-input placeholder="域名" v-model="domain"> </el-input>
</el-form-item>
<el-form-item label="Api Path">
<el-input placeholder="Api Path" v-model="apiPath"></el-input>
</el-form-item>
<el-form-item label="Heanders">
<el-input type="textarea" placeholder="Heanders" v-model="headers" rows="6" cols="6"></el-input>
</el-form-item>
<el-form-item label="Parameters">
<el-input type="textarea" placeholder="Parameters" v-model="params" rows="6" cols="6"></el-input>
</el-form-item>
<el-form-item>
<el-button
type="primary"
style="width:100%"
@click="doGoFunc">GO!</el-button>
</el-form-item>
<el-form-item label="Response">
<el-input type="textarea" placeholder="Response" rows="6" cols="6" v-model="res" readonly></el-input>
</el-form-item>
</el-form>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'IstioDemo',
data () {
return {
domain:"http://demoa.istiodemos.com",
apiPath:"/test/request-b",
params:"{\"forward\":\"istio-springboot-demo-b\", \"a\":\"av356\"}",
headers:"{}",
res:""
}
},created(){
this.init()
},methods:{
init(){//获取数据
},
doGoFunc(){
var parameters = JSON.parse(this.params)
var headers = JSON.parse(this.headers)
axios({
url: this.domain + this.apiPath,
method: 'get',
headers: headers,
params: parameters
}).then(res => {
this.res = "success\n" + res.data;
}).catch(res=>{
this.res = "fail\n" + JSON.stringify(res);
})
}
}
}
</script>
参考
https://istio.io/latest/zh/docs/reference/config/networking/virtual-service/#CorsPolicy