What exactly does nginx.ingress.kubernetes.io/rewrite-target: /$1 mean in minikube annotation?
Asked Answered
D

2

15

While working with minikube ingress, I have to write nginx.ingress.kubernetes.io/rewrite-target: /$1. I have been trying hard to understand why we need this annotation and how to use it.

I know that the doc says the following:

In some scenarios the exposed URL in the backend service differs from the specified path in the Ingress rule. Without a rewrite any request will return 404. Set the annotation nginx.ingress.kubernetes.io/rewrite-target to the path expected by the service.

But I am not able to get the exact point of what exactly the exposed URL in the backend service differs from the specified path in the Ingress rule means. I am not able to get the idea clearly.

Further, upon trying to execute ingress file with services:

code 1:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  namespace: example-namespace
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
    - host: myexample.com
      http:
        paths:
          - path: /
            pathType: Prefix 
            backend:
              service:
                name: example-service
                port:
                  number: 80

code 2:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  namespace: example-namespace
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: myexample.com
      http:
        paths:
          - path: /
            pathType: Prefix 
            backend:
              service:
                name: example-service
                port:
                  number: 80

code 3:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  namespace: example-namespace
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
    - host: myexample.com
      http:
        paths:
          - path: /index
            pathType: Prefix 
            backend:
              service:
                name: example-service
                port:
                  number: 80

what exactly is the difference between each pair of the above 3 code snippets with respect to rewrite-target and path mentioned above?

PS: I'm new to minikube and trying to figure out the exact way things work. Please help.

Dimitry answered 10/4, 2021 at 5:36 Comment(0)
C
20

I don't know if things changes with new versions of the Ingress resource or with new versions of the Nginx Ingress Controller, but this is how I think it works.

Suppose I want to serve 2 different web applications under the same domain, with a Ingress.

  • App A is expecting requests under /
  • App B is expecting requests under /

So, both Apps are expecting their requests directly under root, which (at first glance) seems to make them impossible to be served at the same domain.

Except, with rewrite targets, I can. I could just serve them under a different path, but rewrite the target to /

  • Serve App A under myexample.com/aaa/
  • Serve App B under myexample.com/bbb/

And add a rewrite target to remove the first part of the path. This is just an example of what a rewrite target can be used for, it simply makes you able to serve an application under a different path of the one expected by the app itself.

Example of the ingress:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  namespace: example-namespace
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
    - host: myexample.com
      http:
        paths:
          - path: /aaa(/|$)(.*)
            pathType: Prefix 
            backend:
              service:
                name: app-a
                port:
                  number: 80
          - path: /bbb(/|$)(.*)
            pathType: Prefix 
            backend:
              service:
                name: app-b
                port:
                  number: 80

Notice that, while this works pretty well on Rest API and similar things, it may work less well on web pages, because a web page could try to load resources at a different path (for example if it does not use relative paths). This is why (usually) frontend applications needs to know on which path they are being served under a domain.


Regarding the syntax of rewrite targets, I'll take as example the Ingress I wrote above. There are a couple things to take into consideration:

  • path
  • pathType
  • rewrite-target

Let's start with path and pathType interactions. With the path I can define where to serve my services. Depending on the pathType, it may be just a Prefix of the whole path, the Exact path, or it can depends on the Ingress Controller (aka ImplementationSpecific). Everything is nicely explain in the documentation with a long table of examples ( https://kubernetes.io/docs/concepts/services-networking/ingress/#examples )

I can do almost everything just with path and pathType, except if the applications I want to serve are expecting to be served at different paths from the ones specified in the Ingress; this is when rewrite-target comes into play.

Like in the example above, I can use rewrite-target to serve an application under a different path from the one expected, composing the url as I want. I can also use regex and capture groups (this is what $1, $2 and so on are)

For example, if I write path: /bbb(/|$)(.*) I mean that this path will match everything under /bbb, with or without a / after bbb. And if I then write rewrite-target: /$2 I'm meaning that requests will be rewritten to substitute /bbb with / and then take the second capture group (which means the second regex expression, (.*) )

The documentation explains it pretty well, even if it makes still use of the old Ingress resource ( https://kubernetes.github.io/ingress-nginx/examples/rewrite/ )

Capwell answered 11/4, 2021 at 9:32 Comment(1)
just a small note about the changed behaviour since version 0.22 github.com/kubernetes/ingress-nginx/blob/main/docs/examples/…Tunnell
A
3

Great explanation provided by @AndD!

There are few things I'd like to add:

  • the (/|$)(.*) is sometimes crucial as you want to reach your app under https://example.com and https://example.com/
  • nginx-ingress is an NGINX tailored to work on, and managed by, Kubernetes, so all the NGINX documentation regarding proxying does apply
  • The $1 and $2 variables capture the path elements that aren't changing, docs

So here's how I'd do it (main service under / pathType (Prefix) and all sub-paths excluding the /test pathType (Exact) to point to testing service):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-nginx-dev
  namespace: develop
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          service:
            name: nginx-test-svc
            port:
              number: 80
        path: /test(.*)
        pathType: Exact
  - host: example.com
    http:
      paths:
      - backend:
          service:
            name: nginx-main-svc
            port:
              number: 80
        path: /(.*)
        pathType: Prefix
Attic answered 15/4, 2023 at 14:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.