参考大佬:https://blog.csdn.net/remix_xy/article/details/127001584

示例 - ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    emr-vke/ray-cluster-uuid: 221167282729208548-emr-4yw63nfsim3u4ruc1oim-rayjob-sample-raycluster-b5x8f
    emr/role: JOB
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    ray.io/enable-ray-history-server: "true"
  creationTimestamp: "2026-05-15T08:11:57Z"
  generation: 1
  labels:
    app.kubernetes.io/created-by: kuberay-operator
    app.kubernetes.io/name: kuberay
    ray.io/cluster: rayjob-sample-raycluster-b5x8f
    ray.io/identifier: rayjob-sample-raycluster-b5x8f-head
  name: rayjob-sample-raycluster-b5x8f-head-ingress
  namespace: emr-4yw63nfsim3u4ruc1oim-ray
  ownerReferences:
  - apiVersion: ray.io/v1
    blockOwnerDeletion: true
    controller: true
    kind: RayCluster
    name: rayjob-sample-raycluster-b5x8f
    uid: 75e96b29-689a-40b3-8a38-281712e3a123
  resourceVersion: "3967321"
  uid: a083035f-0e6f-446d-9ba5-de1b4d6c405a
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - backend:
          service:
            name: rayjob-sample-raycluster-b5x8f-head-svc
            port:
              number: 8265
        path: /rayjob-sample-raycluster-b5x8f/(.*)
        pathType: Exact
status:
  loadBalancer:
    ingress:
    - ip: 118.196.47.109

解释

1. (.*)

(.*) 是一个正则表达式,配合 nginx ingress 的 rewrite(重写) 功能使用。

  拆开看:

  • . 表示任意一个字符
  • * 表示前面的字符出现 0 次或多次
  • () 表示捕获分组,把匹配到的内容“抓出来”,可以在后面引用

  所以 (.*) 的意思是:匹配任意长度的任意字符,并把它捕获下来。

2. annotations

结合annotations一起看

annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
  ...
  path: /rayjob-sample-raycluster-b5x8f/(.*)

  工作流程:

  1. 用户访问:http://118.196.47.109/rayjob-sample-raycluster-b5x8f/api/jobs
  2. nginx 用正则 /rayjob-sample-raycluster-b5x8f/(.*) 去匹配路径
  3. (.*) 捕获到的内容是:api/jobs → 这就是 $1
  4. rewrite-target: /$1 告诉 nginx 把请求重写成 /api/jobs
  5. 最后转发给后端 Service(Ray dashboard)的就是 /api/jobs


 

3. 为什么$1就是api/jobs呢

示例 - ingress2

代码

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    k8s.apisix.apache.org/rewrite-target-regex: /[^/]+/(.*)
    k8s.apisix.apache.org/rewrite-target-regex-template: /$1
  generation: 1
  labels:
    app.kubernetes.io/created-by: kuberay-operator
    app.kubernetes.io/name: kuberay
    ray.io/cluster: rayjob-sample-ingress-3-pzkcp
    ray.io/identifier: rayjob-sample-ingress-3-pzkcp-head
  name: rayjob-sample-ingress-3-pzkcp-head-ingress
  namespace: ray-test
  ownerReferences:
  - apiVersion: ray.io/v1
    blockOwnerDeletion: true
    controller: true
    kind: RayCluster
    name: rayjob-sample-ingress-3-pzkcp
    uid: 1af0cafb-d409-491c-90b6-928aabb07a2d
  resourceVersion: "221515669"
  uid: dce80917-8116-438b-9e88-8a8b4317699f
spec:
  ingressClassName: apisix
  rules:
  - http:
      paths:
      - backend:
          service:
            name: rayjob-sample-ingress-3-pzkcp-head-svc
            port:
              number: 8265
        path: /rayjob-sample-ingress-3-pzkcp/(.*)
        pathType: Exact
status:
  loadBalancer:
    ingress:
    - ip: 10.117.16.218

解释

1. [^/]

区分:[] 和 ()

  • [] 字符集 —— 限定一个字符能是什么("允许的字符列表")

  [] 在管"一个字符"

  • [abc] = 一个字符,是 a、b、c 中的任一个
  • [0-9] = 一个字符,是 0~9 中的任一个数字
  • [^/] = 一个字符,只要不是 / 就行(^ 在 [] 开头表示"取反")
  注意:[] 默认只匹配 1 个字符。要匹配多个,得在后面加量词 +、*、{n}:

  • [^/] → 1 个非 / 字符(比如 r)
  • [^/]+ → ≥1 个非 / 字符(比如 rayjob-sample-ingress-3-pzkcp)

所以我的正则里的 [^/]+ 正好可以吞掉 rayjob-sample-ingress-3-pzkcp 这整段,直到遇到下一个 / 才停。

  • () 捕获组 —— 把一段匹配结果打包,方便用 $1 引用

  () 在管"打包 + 捕获"
  () 本身不限制能匹配什么字符,它只是"画个圈",把圈里匹配到的内容存起来,给后面 $1、$2 用。

  • (.*) → 把"任意字符任意多个"这一整段打包成 $1
  • 在我的例子里,圈住的是 api/jobs,所以 $1 = "api/jobs"

结合我的正则来看:

最后小测:

如果把你的正则改成:
/([^/]+)/(.*)
那匹配 /rayjob-sample-ingress-3-pzkcp/api/jobs 时:
• $1 = "rayjob-sample-ingress-3-pzkcp"
• $2 = "api/jobs"
这就是 [] 和 () 同时用上的效果——[] 决定每个字符能是什么,() 决定哪一段要被拎出来用。

2. annotation配合使用

APISIX 拿到原始 URI 后,再用 rewrite-target-regex 重新跑一次正则

再代入 k8s.apisix.apache.org/rewrite-target-regex-template: /$1

把 $1 替换成 api/jobs,最终 /api/jobs 转发给后端 Service 的路径

更多推荐