Kubernetes: Issue with 2 Ingress object with regex path

Viewed 274

I have 2 ingress objects

first-ingress.yml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: first-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt"
    acme.cert-manager.io/http01-edit-in-place: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  tls:
    - hosts:
        - www.example.com
      secretName: example-tls
  rules:
    - host: www.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: first-service
                port:
                  number: 80

second-ingress.yml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: second-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    cert-manager.io/cluster-issuer: "letsencrypt"
    acme.cert-manager.io/http01-edit-in-place: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  tls:
    - hosts:
        - www.example.com
      secretName: example-tls
spec:
  rules:
    - host: www.example.com
      http:
        paths:
          - path: /test(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: second-service
                port:
                  number: 80

The expectation is:

www.example.com/test/whatever -> second-service

www.example.com -> first-service

What I saw is that both www.example.com/test/whatever and www.example.com reach to the first-service

If I change the second-ingress to replace the regex with a static path, it will work. www.example.com/test/whatever will hit the second-service

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: second-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt"
    acme.cert-manager.io/http01-edit-in-place: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  tls:
    - hosts:
        - www.example.com
      secretName: example-tls
spec:
  rules:
    - host: www.example.com
      http:
        paths:
          - path: /test
            pathType: Prefix
            backend:
              service:
                name: second-service
                port:
                  number: 80

Any idea why regex does not work? I need the rewrite-target rule, which is the reason I use the regex

1 Answers

The regex that you posted is exactly the same as from the example from the NGINX Ingress Controller docs, but the yaml file is wrong (one mistake with the double spec, below more information) - I tested your yamls files on Kubernetes v.1.21, NGINX Controller version v.1.0.2 and Cert Manager v1.6.1.

A few notes/thoughts about what may be wrong:


Instead of using twice spec: (second-ingress.yaml) , use spec only once. I did not observe the change in the behaviour in the prefixes itself, but in the kubectl get ing command for the second ingress there was no 443 port specified. When I ran kubectl get ing second-ingress -o yaml, there was missing TLS part.

Before (wrong setup): second-ingress.yaml file:

spec:
  tls:
    - hosts:
        - www.example.com
      secretName: example-tls
spec:
  rules:

kubectl get ing output (missing port 443 for the second ingress):

user@cloudshell:~/ingress-two-services $ kubectl get ing
NAME             CLASS    HOSTS             ADDRESS       PORTS     AGE
first-ingress    <none>   www.example.com   xx.xx.xx.xx   80, 443   5h7m
second-ingress   <none>   www.example.com   xx.xx.xx.xx   80        50m

kubectl get ing second-ingress -o yaml output (missing tls part):

user@cloudshell:~/ingress-two-services $ kubectl get ing second-ingress -o yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
...
spec:
  rules:
  - host: www.example.com
    http:
      paths:
      - backend:
          service:
            name: second-service
            port:
              number: 80
        path: /test(/|$)(.*)
        pathType: Prefix
status:
...

After (good setup): second-ingress.yaml file:

spec:
  tls:
    - hosts:
        - www.example.com
      secretName: example-tls
  rules:

kubectl get ing output:

user@cloudshell:~/ingress-two-services $ kubectl get ing
NAME             CLASS    HOSTS             ADDRESS       PORTS     AGE
first-ingress    <none>   www.example.com   xx.xx.xx.xx  80, 443   5h18m
second-ingress   <none>   www.example.com   xx.xx.xx.xx  80, 443   61m

kubectl get ing second-ingress -o yaml output:

user@cloudshell:~/ingress-two-services $ kubectl get ing second-ingress -o yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
...
spec:
  rules:
  - host: www.example.com
    http:
      paths:
      - backend:
          service:
            name: second-service
            port:
              number: 80
        path: /test(/|$)(.*)
        pathType: Prefix
  tls:
  - hosts:
    - www.example.com
    secretName: example-tls
status:
...

Another thing worth noting that the modified configuration for the second ingress is behaving differently than the one that does not work for you.

Using nginx.ingress.kubernetes.io/rewrite-target: /$2 + path: /test(/|$)(.*):

  • www.example.com/test/ will rewrite the request to the pod to /
  • www.example.com/test/whatever will rewrite the request to the pod to /whatever

However, using only path: /test:

  • www.example.com/test/ will rewrite the request to the pod to /test
  • www.example.com/test/whatever will rewrite the request to the pod to /test/whatever

Please make sure that you are using a proper setup for which your app is designed to.


Other tips:

  • make sure that ingress is applied by running kubectl get ing command
  • get the logs of the NGINX Ingress Controller. Get the name of the Ingress Controller pod (kubectl get pods -n ingress-nginx) and then run kubectl logs -n ingress-nginx ingress-nginx-controller-{...}. Check how your requests are handled and where (which service) they are forwarded to
  • check the logs of the pods from the deployments and check how they are handling request (kubectl logs {pod-name})
  • if you are using some out-dated version of the Kubernetes better upgrade it
Related