前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Knative根据Path转发请求

Knative根据Path转发请求

作者头像
李鹤
发布2023-03-06 11:20:37
4040
发布2023-03-06 11:20:37
举报
文章被收录于专栏:k-cloud-labs

背景

knative 0.14.0 实际修改可能与贴出来的代码不符,贴出来的代码只是为了方便快速实现功能

最近在搭建公司级的serverless平台,需要用到域名来访问内部服务,采取的是通过PATH来区分不同的服务,域名采用同一个。这与原生knative的设计存在差异,原生的做法是每个服务一个自己的域名,通过域名把流量打到不同的服务上,我们已经在上一篇中解决了自定义域名无法访问knative集群的问题,这一篇来解决如何通过不同的Path访问到不同的服务

方案

两个问题需要我们来解决:

  1. 不同服务的Path可能相同,如何区分
  2. 原生通过ksvc的方式不支持设置Path(通过自己创建各种类型的资源可以实现,但是控制比较复杂,而且上层需要修改适配)

解决方案:

  1. 每个服务一个USN,使用USN作为唯一标识
  2. 修改knative,支持通过Path访问
  3. 转发后需要rewrite url,把USN去掉,因为业务代码中的路由里不可能包含USN

其中第一点不需要代码改动,我们主要来实现第二、三点。

vs本身是支持根据Path转发的功能的,但是并没有在ksvc中暴露出来,所以我们需要在king创建vs的时候动态注入进去,同时在destination中添加url rewrite的逻辑。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74

func makeVirtualServiceSpec(ing *v1alpha1.Ingress, gateways map[v1alpha1.IngressVisibility]sets.String, hosts sets.String) *istiov1alpha3.VirtualService { spec := istiov1alpha3.VirtualService{ Hosts: hosts.List(), } // 自定义功能 usn := ing.Annotations["serverless.kakuchuxing.com/usn"] if usn != "" { usn = "/" + strings.Trim(usn, "/") + "/" } gw := sets.String{} for _, rule := range ing.Spec.Rules { for _, p := range rule.HTTP.Paths { hosts := hosts.Intersection(sets.NewString(rule.Hosts...)) if hosts.Len() != 0 { http := makeVirtualServiceRoute(hosts, usn, &p, gateways, rule.Visibility) // Add all the Gateways that exist inside the http.match section of // the VirtualService. // This ensures that we are only using the Gateways that actually appear // in VirtualService routes. for _, m := range http.Match { gw = gw.Union(sets.NewString(m.Gateways...)) } // rewrite path,重定向,消除USN if usn != "" { if http.Rewrite == nil { http.Rewrite = &istiov1alpha3.HTTPRewrite{} } http.Rewrite.Uri = "/" } spec.Http = append(spec.Http, http) } } } spec.Gateways = gw.List() return &spec } func makeVirtualServiceRoute(hosts sets.String, usn string, http *v1alpha1.HTTPIngressPath, gateways map[v1alpha1.IngressVisibility]sets.String, visibility v1alpha1.IngressVisibility) *istiov1alpha3.HTTPRoute { ... for _, host := range hosts.List() { g := gateways[visibility] if strings.HasSuffix(host, clusterDomainName) && len(gateways[v1alpha1.IngressVisibilityClusterLocal]) > 0 { // For local hostname, always use private gateway g = gateways[v1alpha1.IngressVisibilityClusterLocal] } matches = append(matches, makeMatch(host, usn, http.Path, g)...) } ... } func makeMatch(host string, usn string, pathRegExp string, gateways sets.String) []*istiov1alpha3.HTTPMatchRequest { ... // add custom usn filter,添加USN的过滤条件 if usn != "" { if i == 0 { matches[i].Uri = &istiov1alpha3.StringMatch{ MatchType: &istiov1alpha3.StringMatch_Prefix{Prefix: usn}, } } else { matches[i].Uri = &istiov1alpha3.StringMatch{ MatchType: &istiov1alpha3.StringMatch_Exact{Exact: strings.TrimRight(usn, "/")}, } } } ... }

修改比较简单,完全就是按照之前说的两点进行的。其中有一个比较tricky的地方就是实现url rewrite的方式,因为社区中的vs(istio里的crd)其实是存在问题的,我们为了规避这个问题,特意做了一些特殊设置。参考这里,大致意思就是目前vs不支持url rewrite为空,rewrite为空之后,实际访问的时候需要在url的最后加上/,否则会返回400,但是我们很多前端网站主页就是一个域名,后面不跟任何内容,那这时候就有问题了,总不能再告诉用户在最后输入一个/。规避方案其实也比较简单,就是上面代码中最后makeMatch处的if else语句,且一定要保证顺序,即最长的要在前面,因为遇到第一个匹配的规则后,后续规则会被忽略。

1 2 3 4 5 6 7 8

http: - match: - uri: prefix: "/echo/" - uri: prefix: "/echo" rewrite: uri: "/"

如果顺序颠倒,那么当访问/echo/abc时,会重定向到//abc,返回404错误。

总结

至此,已经支持通过统一域名访问,且通过Path把请求转发到不通的服务

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-08-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 方案
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档