Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

URL重写 #54

Closed
zhugelianglongming opened this issue Feb 10, 2022 · 6 comments · Fixed by #82
Closed

URL重写 #54

zhugelianglongming opened this issue Feb 10, 2022 · 6 comments · Fixed by #82
Assignees
Labels
enhancement New feature or request

Comments

@zhugelianglongming
Copy link
Member

zhugelianglongming commented Feb 10, 2022

背景

BFE 支持对流量进行URL重写,希望 bfe-ingress-controller 实现该功能。

配置方式

Ingress 资源内

  • spec.rules 定义路由规则
  • metadata.annotations 定义对符合路由规则的流量,修改 URL的行为
    • 定义修改覆盖的流量范围
    • 定位修改 URL 的行为

设计方案

#54 (comment)

参考格式:

重写时机

  • 默认确认目标后端实例后,执行重写

确认目标后端前

确认目标后端后

重写 Host

通过特定 annotation 配置Host重写,可设置为以下模式其中之一:

  • 静态 Host
  • 动态 Host

静态 Host

对应示例

动态 Host

对应示例

重写 Path

通过特定 annotation 配置Path重写,可设置为以下模式其中之一:

  • 静态 Path
  • 动态 Path

静态 Path

对应示例

动态 Path

支持:

  • PATH_PREFIX_ADD:添加Path前缀
  • PATH_PREFIX_TRIM:删除Path前缀

添加前缀

对应示例

删除前缀

对应示例

重写 Query

支持:

  • RAW_QUERY_ADD:添加指定Query
  • RAW_QUERY_RENAME:重命名指定Query
  • RAW_QUERY_DEL:删除指定Query
  • RAW_QUERY_DEL_ALL_EXCEPT:仅保留指定Query,删除指定Query外的其他 Query

新增

对应示例

重命名

对应示例

删除

对应示例

仅保留

对应示例

BFE rewrite
Nginx ingress rewrite

@mengtao97
Copy link
Contributor

mengtao97 commented Nov 10, 2022

URL重写需求

需求目标

BFE引擎提供了丰富的URL重写能力,包含对host、path、query等三部分url信息的修改操作。

基于bfe-Ingress-controller的注解解析能力,将用户配置的注解转换成BFE引擎的相关配置文件,结合BFE引擎URL重写能力,实现流量的URL重写。

竞品调研

功能 NGINX Ingress Traefik Contour Kong
host重写 不支持 不支持(可保留host信息) 不支持 不支持host重写(可保留)
path重写 1. 支持静/动态重写(正则捕获组)
2. root路径修改
1. 支持静态path
2. path添加、替换
支持静态替换 支持添加和删除前缀(全部)
query重写 不支持 不支持 不支持 不支持

需求分析

  • 重写时机,租户可配置URL重写时机,具体含义如下。
    • 确认目标服务(集群)前:在确认目标实例前,执行URL重写(路由会受影响)。
    • 确认目标服务(集群)后:确认目标服务后,执行URL重写。
    • 确认目标实例后:确定服务实例(子集群与实例)后,转发给服务实例前,执行URL重写。

bfe引擎基于回调点机制,可在每个回调点注册相关回调函数,实现对流量的处理逻辑。目前开源bfe引擎版本中,URL重写仅支持确认目标服务后,进行URL重写。设计中,需考虑兼容引擎升级后支持不同的重写时机。

  • Host 重写,Host信息可用于路由时确认服务实例信息,对于实例服务,可验证请求头中的Host字段,检查请求的合法性。

    • host替换为固定值,用户给出值,BFE引擎中可通过HOST_SET实现。
    • host信息需从请求中动态设置,BFE引擎目前支持HOST_SET_FROM_PATH_PREFIX操作,可从path前缀中提取出新的host信息,从而实现动态设置host信息。
  • Path重写,path重写是最常用的场景,对请求的path进行重写,从而获取到指定的后端资源。

    • 租户可以将该Ingress中的path路由都重写到某个固定的path下,可通过BFE引擎中PATH_SET实现。
    • 租户对路由的path进行动态修改,如移除前缀或增加前缀等,可通过PATH_PREFIX_ADDPATH_PREFIX_TRIM实现。
    • 租户可设置path前缀截断长度,基于BFE的PATH_PREFIX_TRIM实现,对Ingress中的path进行前缀删除(path长度需大于等于截断长度)。
    • 租户在使用时,可选择静态重写或动态重写path信息,可根据实际需求,设置注解顺序字段。
  • Query重写,query重写,可用于解决系统迁移、多客户-服务端面临的字段不一致问题与中间层参数设置。

    • 租客可添加、删除或仅保留请求中的参数信息,基于BFE引擎的QUERY_ADDQUERY_DELQUERY_DEL_ALL_EXCEPT实现。
    • 租户可重命名请求参数,实现基于BFE引擎QUERY_RENAME
    • 同path重写,租户需根据实际需求,定义query重写注解顺序。

Annotation设计

需求描述 BFE 引擎实现 BFE Ingress实现 示例 params类型约束
host设置为固定值。 HOST_SET bfe.ingress.kubernetes.io/rewrite-url.host bfe.ingress.kubernetes.io/rewrite-url.host: '[{"params": "baidu.com"}]'
host值为baidu.com
字符串,且符合host命名规范。
从path前缀中动态提取host HOST_SET_FROM_PATH_PREFIX bfe.ingress.kubernetes.io/rewrite-url.host-from-path-prefix bfe.ingress.kubernetes.io/rewrite-url.host-from-path-prefix: '[{"params": "true"}]',默认为false
path设置:/baidu.com/xxx ,取出baidu.com为host信息,path设置为/xxx
bool值,值仅可为true
path信息设置为固定值。 PATH_SET bfe.ingress.kubernetes.io/rewrite-url.path bfe.ingress.kubernetes.io/rewrite-url.path: '[{"params": "/foo/bar"}]'
请求路径为/foo/bar
字符串,符合path定义规范。
修改Path信息,添加前缀。 PATH_PREFIX_ADD bfe.ingress.kubernetes.io/rewrite-url.path-prefix-add bfe.ingress.kubernetes.io/rewrite-url.path-add: '[{"params": "/bar"}]'
/foo请求实际访问路径为/bar/foo
路径前缀字符串
移除path前缀 PATH_PREFIX_TRIM bfe.ingress.kubernetes.io/rewrite-url.path-prefix-trim bfe.ingress.kubernetes.io/rewrite-url.path-prefix-trim: '[{"params": "/foo"}]'
删除前缀,/foo/bar变为/bar,/rea/bar不变化。
路径前缀字符串
截断指定长度path PATH_PREFIX_TRIM bfe.ingress.kubernetes.io/rewrite-url.path-prefix-strip bfe.ingress.kubernetes.io/rewrite-url.path-prefix-strip: '[{"params": 1}]'
截断前缀长度为1,/foo/bar变为/bar
字符串,需为有效整数。
添加请求中参数 QUERY_ADD bfe.ingress.kubernetes.io/rewrite-url.query-add bfe.ingress.kubernetes.io/rewrite-url.query-add:'[{"params": "{"name": "alice"}"}]'
query参数中添加name=alice,由https://example.org/bar变为https://example.org/bar?name=alice
字典类型的json字符串,如 {"name": "bob"}
删除请求中的参数 QUERY_DEL bfe.ingress.kubernetes.io/rewrite-url.query-delete bfe.ingress.kubernetes.io/rewrite-url.query-delete: '[{"params": "["name"]}]'
query中移除name参数,https://example.org/bar?name=alice变为https://example.org/bar
数组类型的json字符串
重命名请求中的参数 QUERY_RENAME bfe.ingress.kubernetes.io/rewrite-url.query-rename bfe.ingress.kubernetes.io/rewrite-url.query-rename: '[{"params": "{"name": "user"}"}]'
https://example.org/bar?name=alice变为https://example.org/bar?user=alice
字典类型的json字符串,如 {"name": "user"}
删除请求中除指定key外所有其他key QUERY_DEL_ALL_EXCEPT bfe.ingress.kubernetes.io/rewrite-url.query-delete-all-except bfe.ingress.kubernetes.io/rewrite-url.query-delete-all-except: '[{"params": "name"}]'
https://example.org/bar?name=alice&gender=man&age=18变为https://example.org/bar?name=alice
字符串

rewrite-url param格式

配置项 描述
callbackList[] 不同回调点的配置参数列表
callbackList[].params rewrite actions参数
callbackList[].order rewrite actions动作顺序,仅作用于同一回调点
callbackList[].when rewrite actions回调点,默认为AfterLocation(目前只支持该回调点)

Example

bfe.ingress.kubernetes.io/rewrite-url.host: '[{"params": "baidu.com", "when": "AfterLocation"}]'
bfe.ingress.kubernetes.io/rewrite-url.path: '[{"params": "/bar"}]'
bfe.ingress.kubernetes.io/rewrite-url.query-rename: >-
 [
   {
      "params": {"name": "user"}, 
      "when": "AfterLocation", 
      "order": 1
   }
 ]

重写时机兼容

Ingress注解参数值为列表,列表中的每一项对应一个回调点的rewrite动作。用户可通过设置参数中的when字段来指定回调点,默认为AfterLocation

需注意,在同一个注解中,回调点不可重复。

优先级设定

Ingress注解参数中的order字段决定对应action执行顺序,由用户确定注解生效顺序,从而实现url重写目标。

// 下例中,先执行query rename,再删除其他query中的kv键值对
// 最终结果:仅保留user键值对,且该参数是由name重写的。
bfe.ingress.kubernetes.io/rewrite-url.query-rename: '[{"params": {"name": "user"}, "order": 1}}]'
bfe.ingress.kubernetes.io/rewrite-url.query-del-all-except: '[{"params": "user", "order": 2}}]'

规则约束

  • host注解数量约束为1,不能同时设置bfe.ingress.kubernetes.io/rewrite-url.hostbfe.ingress.kubernetes.io/rewrite-url.host-from-path-prefix
  • path注解不能同时设置静态path与动态path。设置后bfe.ingress.kubernetes.io/rewrite-url.path,不可设置bfe.ingress.kubernetes.io/rewrite-url.path-prefix-add bfe.ingress.kubernetes.io/rewrite-url.path-prefix-delete

@mengtao97
Copy link
Contributor

mengtao97 commented Nov 11, 2022

设计方案

主要任务

  1. Ingress配置转换

从用户的Ingress配置中,解析出重写时机、流量识别条件与重写动作,并转换成BFE引擎的URL重写配置文件。

  1. hook点升级兼容

BFE引擎的URL重写时机是确认目标集群后,若引擎升级后,可支持更多重写时机。如下所示。

  • 确定目标集群前,先对URL进行重写,再进行路由确定。

  • 确定目标实例后,转发流量前,即支持不同的子服务应用不同的URL重写规则。

设计中需考虑兼容BFE引擎hook点升级。

实现方案

Ingress 配置转换

Ingress 配置

kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
  name: ingress-test
  namespace: ingress-bfe
  annotations:
    kubernetes.io/ingress.class: bfe
    bfe.ingress.kubernetes.io/rewrite-url.host: >-
      [
        { 
          "params": "bar.com",
          "when": "AfterLocation"
        }
      ]
    bfe.ingress.kubernetes.io/rewrite-url.path-prefix-add: >-
      [      
        {
          "params": "/service"
          "when": "AfterLocation"
        }
      ]
spec:
  rules:
    - host: "foo.com"
      http:
        paths:
          - path: /whoami
            pathType: Prefix
            backend:
              service:
                name: whoami
                port:
                  number: 80

Ingress配置文件中,共有四个字段。kindapiVersionmetadataspec

  • kind:服务类型
  • apiVersion:版本信息
  • metadata:服务元信息,包含名称、命名空间及用户自定义注解等。
  • spec:包含http rules,每条rule包含可选的host、路径列表、后端等信息。

BFE URL重写配置

{
    "Version": "1",
    "Config": {
        "default": [
            {
                "Cond": "req_host_in(\"foo.com\") && req_path_prefix_in(\"/whoami\", false)",
                "Actions": [
                    {
                        "Cmd": "HOST_SET",
                        "Params": ["bar.com"]
                    },
                    {
                        "Cmd": "PATH_PREFIX_ADD",
                        "Params": ["/service"]
                    }
                ],
                "Last": true
            }
        ]
    }
}

配置具体含义如下。

  • default :与hook点一一对应,包含及该hook点下的流量重写规则。

  • CondBFE条件表达式,为流量识别条件,符合条件,则执行重写URL Action。

  • Actions:BFE重写动作列表。

    • Cmd: 重写动作,详情可见URL重写中Actions。
    • Params:重写参数
  • Last:规则匹配后,是否结束后续规则匹配。

转换规则

  • hook点:URL重写注解中的when字段确定

  • Actions:识别流量重写条件与重写动作

  • Condmetadata.annotations注解中定义的header、cookie与spec.rules中路由规则的host与path信息确定(复用路由http rule的Cond信息)

  • Cmd:由metadata.annotations中相关URL重写动作确定,具体转换规则可见需求分析中的Annotations设计

  • Params: URL重写注解中的Params确定

  • Last:暂定为true(目前BFE引擎版本中,路由信息与流量重写识别条件绑定)

hook点升级兼容

  • URL注解中的when字段,可根据不同hook点,设置不同的值。BFE配置文件根据不同的hook点,创建不同的URL 重写规则列表。
  • Cond:目前重写识别条件与路由条件为强绑定,即路由确定集群,并对该集群下的流量全部进行相关URL重写。后续升级支持确定目标集群前或确定子服务(子集群)后进行URL重写,可考虑注解中增加相关识别条件。

This was referenced Nov 28, 2022
@zhugelianglongming
Copy link
Member Author

zhugelianglongming commented Dec 5, 2022

      { 
        "params": bar.com,
        "when": AfterLocation
      }

预期这个 annotation的值是 JSON 格式还是自定义格式?

@zhugelianglongming
Copy link
Member Author

zhugelianglongming commented Dec 5, 2022

字符串,值仅可为truet,默认为false

这个 t 的设计是为了便利吗? t 的缩写使用是否直观,是否通用? 整体参数使用 JSON 格式用户都忍受了,这个 t 带来的便利收益价值还大么?
这部分使用的设计里,考虑易用性、便利性、可读性、可扩展性,哪个为主要考虑因素?
另外 false 这个值用户什么场景下会设置使用?

@mengtao97
Copy link
Contributor

mengtao97 commented Dec 6, 2022

      { 
        "params": bar.com,
        "when": AfterLocation
      }

预期这个 annotation的值是 JSON 格式还是自定义格式?

JSON格式,已修改样例。

@mengtao97
Copy link
Contributor

字符串,值仅可为truet,默认为false

这个 t 的设计是为了便利吗? t 的缩写使用是否直观,是否通用? 整体参数使用 JSON 格式用户都忍受了,这个 t 带来的便利收益价值还大么? 这部分使用的设计里,考虑易用性、便利性、可读性、可扩展性,哪个为主要考虑因素? 另外 false 这个值用户什么场景下会设置使用?

移除tfalse

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants