Kubernetes Ingress:nginx,使用正则表达式匹配精确的 URL 路径

Kubernetes Ingress: nginx, use-regex to match exact URL path

我有一些 pods 正在尝试匹配 URL 以获取它们各自的服务。

请注意我需要使用nginx.ingress.kubernetes.io/rewrite-target来解决这个问题不是nginx.ingress.kubernetes.io/rewrite-target

我的入口配置文件如下所示。请注意 /api/tile-server/ 没有任何正则表达式模式

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress-service
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/use-regex: "true"
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
  namespace: default
spec:
  tls:
    - hosts:
        - example.com
      secretName: tls-secret
  rules:
    - host: example.com
      http:
        paths:
          - path: /?(.*)
            backend:
              serviceName: client
              servicePort: 80
          - path: /api/auth/?(.*)
            backend:
              serviceName: auth
              servicePort: 8000
          - path: /api/data/?(.*)
            backend:
              serviceName: data
              servicePort: 8001
          - path: /api/tile-server/
            backend:
              serviceName: tile-server
              servicePort: 7800
server {
    # listen on port 80
    listen 80;
    # where the root here
    root /usr/share/nginx/html;
    # what file to server as index
    index index.html index.htm;

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to redirecting to index.html
        try_files $uri $uri/ /index.html;
    }

    # Media: images, icons, video, audio, HTC
    location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
        expires 1M;
        access_log off;
        add_header Cache-Control "public";
    }

    # Javascript and CSS files
    location ~* \.(?:css|js)$ {
        try_files $uri =404;
        expires 1y;
        access_log off;
        add_header Cache-Control "public";
    }

    # Any route containing a file extension (e.g. /devicesfile.js)
    location ~ ^.+\..+$ {
        try_files $uri =404;
    }
}

我尝试了以下模式但失败了:

我可以确认 pods/services 在它们正确的端口上 运行,我可以通过节点端口访问它们,但不能通过负载 balancer/domain 访问它们。 完全匹配 /api/tile-server/ URL 的正确模式是什么?

从 v1beta1 移至 v1 并使用路径类型:精确 - https://kubernetes.io/docs/concepts/services-networking/ingress/

第一个解决方案 - 使用重写目标注释为 tile-server 创建单独的入口对象。这将起作用,因为具有相同主机的入口规则由入口控制器合并在一起,并且单独的入口对象允许每个对象使用不同的注释:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: tile-ingress-service
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/rewrite-target: "/"
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
  namespace: default
spec:
  tls:
    - hosts:
        - example.com
      secretName: tls-secret
  rules:
    - host: example.com
      http:
        paths:
          - path: /api/tile-server(/|$)(.*)
            backend:
              serviceName: tile-server
              servicePort: 7800

第二种解决方案 - 重写当前入口以使用重写路径。需要对正则表达式进行一些更改。

注意非捕获组表示法:(?:<regex>)。这允许跳过这些组的编号,因为我需要所有相关的东西都在第一组中才能工作,因为 rewrite-target: "/".

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress-service
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/rewrite-target: "/"
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
  namespace: default
spec:
  tls:
    - hosts:
        - example.com
      secretName: tls-secret
  rules:
    - host: example.com
      http:
        paths:
          - path: /(.*)
            backend:
              serviceName: client
              servicePort: 80
          - path: /(api/auth(?:/|$).*)
            backend:
              serviceName: auth
              servicePort: 8000
          - path: /(api/data(?:/|$).*)
            backend:
              serviceName: data
              servicePort: 8001
          - path: /api/tile-server(?:/|$)(.*)
            backend:
              serviceName: tile-server
              servicePort: 7800

以下是重写的工作方式:

  • 授权服务(数据服务同理)
    /api/auth      --->  /api/auth
    /api/auth/     --->  /api/auth/
    /api/auth/xxx  --->  /api/auth/xxx
  • 磁贴服务器服务:
    /api/tile-server      --->  /
    /api/tile-server/     --->  /
    /api/tile-server/xxx  --->  /xxx
  • 客服
    /xxx  --->  /xxx

注意以下路径将被转发到客户端服务(其中 xxx 是任何字母数字字符串):

    /api/authxxx
    /api/dataxxx
    /api/tile-serverxxx

如果您希望将它们转发到 other/matching 服务,请在路径中的 (?:/|$) 之后添加 ?

这是我的解决方案

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: "/"
  name: ingress-staging
  namespace: staging
spec:
  ingressClassName: nginx
  rules:

  - http:
      paths:
      - path: /(.*)
        pathType: Prefix
        backend:
          service:
            name: acp-service
            port: 
              number: 80
  
  - http:
      paths:
      - path: /service-ecommerce(?:/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: ecommerce-service
            port: 
              number: 80      

谢谢@Matt