ingress-nginx: Multiple ingress definitions for the same host with rewrite-target lead to ordering problems

I’m trying to use kube-lego and the nginx-ingress-controller together with the rewrite-target annotation, but I’m running an issue: the way the location is build for the ingress gets picked always, and kube-lego’s acme-challenge location is never selected.

nginx.conf snippets for illustration:

    server {
        server_name media.DOMAIN;
        listen [::]:80 proxy_protocol;
        vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name;

        location /.well-known/acme-challenge {
            set $proxy_upstream_name "kube-lego-nginx-8080";
            ....
        }

        location ~* / {
	        ....
                rewrite /(.*) /media/$1 break;
                proxy_pass http://app-http;
        }

This was generated by this ingress:

kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: media
  annotations:
    ingress.kubernetes.io/class: nginx
    ingress.kubernetes.io/rewrite-target: /media
    kubernetes.io/tls-acme: "true"
spec:
  tls:
  - hosts:
    - "media.DOMAIN"
    secretName: media-tls
  rules:
  - host: "media.DOMAIN"
    http:
      paths:
      - path: /
        backend:
          serviceName: app
          servicePort: http

Is there any way I can use “disable” the use of the “~*” operator, and still map from frontend / to backend /media/?

(FWIW: I’m trying right now to build a container from master, to try the app-root annotation)

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 4
  • Comments: 31 (14 by maintainers)

Most upvoted comments

I strongly believe one should be able to set the order of rules explicitly or at least disable regex matching . Consider this example:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: main-ingress
  annotations:
    ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: example.com
    http:
      paths:
        - path: /a
          backend:
            serviceName: a-service
            servicePort: 80
        - path: /b
          backend:
            serviceName: b-service
            servicePort: 80

This creates rules like this:

  • location ~* /b
  • location ~* /a

Now suppose you have a route in your app like this /a/foo/b . This will first match the rule for b-service which just wrong.

UPDATE: As a very hacky workaround I am going to set /b to /0?b so it appers after /a but this is just ridiculous and even finding out about the ordering requires reading the ingress-nginx code.

no… I ended up removing some edge cases, etc and found a sweet spot where the reverse alphabetical order worked for me.

I honestly feel I am not asking for anything uncommon, I think the ordering should be removed (in that the current behaviour should remain for backwards compatibility and annotations should be added to change the behaviour) or I have seen many requests/issues for the nginx controller supporting regex paths, those issues and resulting PR’s should answer/solve the question of order(ing) as well.

@aledbf I have created two different namespaces for different environment. one is devops-qa and another is devops-dev. I created two ingress in different namespaces. So while creating ingress of qa env in devops-qa namespace, the rules written inside ingress of qa is working fine. Means I am able to access the webpage of qa env. The moment I will create the ingress of dev env in devops-dev namespace, I will be able to access the webpage of dev env but wont be able to access the webpage of qa. And when I delete the dev ingress then again I will be able to access the qa env website

Below is the ingree of both dev and qa env.

Dev Ingress

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: cafe-ingress-dev
  namespace: devops-dev
spec:
  tls:
  - hosts:
    - cafe.example.com
    secretName: default-token-jhtx3
  rules:
  - host: cafe.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: miqpdev-svc
          servicePort: 80

QA Ingress

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: cafe-ingress-qa
  namespace: devops-qa
spec:
  tls:
  - hosts:
    - cafe.example.com
    secretName: default-token-bjg3z
  rules:
  - host: cafe.example.com
    http:
      paths:
      - path: /greentea
        backend:
          serviceName: greentea-svc
          servicePort: 80
      - path: /blackcoffee
        backend:
          serviceName: blackcoffee-svc
          servicePort: 80

The token mentioned in the ingress file is of each namespace. How can i run both the ingress and will be able to get all the websites deployed in both dev and qa env ? I am using Nginx Plus controller which is deployed right now in qa namespace but able to read the ingress of qa as well as dev namespace.Pls help me in this issue … I am struggling from 1 whole day.

I’ve found out what I’m trying to do doesn’t work on GCE. Womp womp

I know… How can i disable that?

This is not possible.

I don’t think ingress should be thinking for us here and we should be able to set the order or atleast honour the order it was configured in.

We honour the order using the resource version of the ingress rule.

Yeah, I know.

I am finding that all of the locations for one host are ordered in reverse alphabetical order.

NGINX process the request as defined in the cfg file. We use reverse alphabetical order to allow things like /foo/bar/baz and /foo/bar

I know… How can i disable that? I don’t think ingress should be thinking for us here and we should be able to set the order or atleast honour the order it was configured in.