When using ingress-nginx in Kubernetes, is is possible to configure backends with captured groups from the path?

10/1/2021

Is it possible to configure an nginx class ingress in Kubernetes with a backend reference to a captured group from a path regex? There is no indication of this in the ingress-nginx docs https://kubernetes.github.io/ingress-nginx/user-guide/ingress-path-matching/

I am trying to reduce the complexity of ingress path / backend definitions, e.g. from this:

...
spec:
  rules:
    - http:
      paths:
        - path: /some/backend1/*
          backend: 
            serviceName: backend1
        - path: /some/otherbackend/*
          backend:
            serviceName: otherbackend

to something like this:

spec:
  rules:
    - http:
      paths:
        - path: /some/([^/]+)/(.+) 
          backend: 
            serviceName: $1  # or \1 - possible to ref a capture group here?

In the above example, the match regex for path matches "any character that isn't a '/' repeated" - i.e. it will match the next URI part until '/'. Am then looking to pass into serviceName.

Is this possible?

edit

I have found a way to shoe horn this into working. This is not an ideal way of doing it, because I am injecting an override directly into nginx configs. Would sort of functionality similar to this be worth requesting as an nginx controller feature?

I have posted a solution to get it working below, even though there are concerns with it - see the disclaimer / concerns below.

-- Brett
kubernetes
nginx
nginx-ingress

1 Answer

10/2/2021

disclaimer: Before reproducing this, it is useful to know some of the concerns around working with nginx config directly - see this -

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: dynamic-routing-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      set $proxy_upstream_name "default-$BackendService-8088";
spec:
  rules:
  - http:
    paths:
    - path: /dynamci/(?<BackendService>[^/]+)(.+)?
      pathType: ImplementationSpecific
      backend:
        service:
          name: backendservice
          port:
            number: 8088

Now requests to /dynamic/x-backend will get routed to x-backend service, if it exists. Heavily caveated - assuming you have consistent spec for the service definitions (e.g. host / port / namespace / etc).

The link above that discusses lack of robustness is that the nginx controller translates to nginx config in a correlated way, and now you are taking that + sanity checks (e.g. by the admission verifier), as well as understanding internal controller naming conventions into the ingress definition. Without the configuration-snippet annotation, the nginx location block would set proxy_upstream_name to something like default-backendservice-8088, but then the config snippet injects another set $proxy_upstream_name parameter later, that matches the name of the captured group from the regex - so you have to know how the back references are created and manually maintain this, while ensuring that the override proxy parameter is consistent with how all your services are defined (e.g. if you have different backend services running on different ports, this won't solve for it and it starts becoming much more complex pretty quick).

While it does get the desired functionality, am not sure if I'll take this forward because of reliability / robustness concerns....

-- Brett
Source: StackOverflow