skip to Main Content

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.

2

Answers


  1. 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/ )

    Login or Signup to reply.
  2. 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 htpps://example.com and https://example.com/
    • nginx-ingress is an NGINX tailed to work on and managed by Kubernetes, so all the NGINX documentation regarding proxying does apply
    • The $1 and $2variables capture the path elements that aren’t changing, docs

    So here’s how I’d do it (main service under pathType 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
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search