Usually ingress rewrite target works as follows:
nginx.ingress.kubernetes.io/rewrite-target: /
This will rewrite the target of your service names as they are in the root directory. So if I have this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: demo-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
rules:
http:
paths:
- path: /
backend:
serviceName: front-main
servicePort: 80
- path: /api
backend:
serviceName: back-main
servicePort: 80
My services are going to receive data as they are in /. However, I would like for my service front-main to send root / and for the server back-main to send /someotherpath/. How can I do this?
Is there something like the following line?
nginx.ingress.kubernetes.io/rewrite-target: "front-main: / ; back-main: /someotherpath"
I don't seem to find the answer in the documentation.
Unfortunately, Ingress based on free version of Nginx do not have that feature.
But, if you can use Nginx Plus based Ingress, you can do it by annotation.
Here is an example from official repo:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: cafe-ingress
annotations:
nginx.org/rewrites: "serviceName=tea-svc rewrite=/;serviceName=coffee-svc rewrite=/beans/"
spec:
rules:
- host: cafe.example.com
http:
paths:
- path: /tea/
backend:
serviceName: tea-svc
servicePort: 80
- path: /coffee/
backend:
serviceName: coffee-svc
servicePort: 80
Below are the examples of how the URI of requests to the tea-svc are rewritten (Note that the /tea requests are redirected to /tea/).
/tea/ -> /
/tea/abc -> /abc
Below are the examples of how the URI of requests to the coffee-svc are rewritten (Note that the /coffee requests are redirected to /beans/).
/coffee/ -> /beans/
/coffee/abc -> /beans/abc
Another solution is create two ingress yaml files
Each one using different annotations. It works!
The new syntax for the rewrite annotation allows you to use capture groups to define the rewrite-target, which can be used in some situations to achieve what you're looking for.
For instance, if you want one of your services to keep the matching url in its rewrite but not the other, you could use matching groups as follow:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-ingress
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$1$2 # Here we concatenate the two matched groups
spec:
rules:
- http:
paths:
- path: /front()(.*) # Here the first matching group is always empty
pathType: Prefix
backend:
service:
name: front-main
port:
number: 80
- path: /(back)(.*) # Here the first matching group matches 'back'
pathType: Prefix
backend:
service:
name: back-main
port:
number: 80
So /back/foo would redirect to the back-service on /back/foo, but /front/foo would redirect to the front-service simply to /foo.
As far as I know, this can't be used for the more general case you asked for, like rewriting /back/foo to /some-completely-different-path.
Related
Given this yaml:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress-2
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: test.com
http:
paths:
- backend:
serviceName: admin
servicePort: 8080
path: /admin/*
pathType: ImplementationSpecific
- backend:
serviceName: keycloak
servicePort: 8080
path: /auth/*
pathType: ImplementationSpecific
I would like the rewrite-target to only apply to the service admin. Requests to keycloak should not be affected. How can I achieve that?
You can separate out ingress file or config, just make sure you keep the different name
So you can you create TWO ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress-1
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: test.com
http:
paths:
- backend:
serviceName: admin
servicePort: 8080
path: /admin/*
pathType: ImplementationSpecific
Ingress: 2 with different config, you can edit anything as per need now remove annotation.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress-2
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: test.com
http:
paths:
- backend:
serviceName: keycloak
servicePort: 8080
path: /auth/*
pathType: ImplementationSpecific
If you want to store everything in a single YAML file you can also do it by merging them with ---.
User Harsh Manvar's answer is good and shows the correct solution. But I am going to expand it a bit and tell you why. Always create deployments that are as little interdependent as possible. For example, if you need to change something in the keycloak, it shouldn't have any effect on admin. Additionally, if the ingress breaks down, you will have 2 broken services instead of one. You should practically always create one ingress to one service.
Additionally, you may want to create completely different rewrite rules. Then, creating separate ingress will be a very good idea. Look at this question.
See also documentation about rewrite rules.
I have two deffinitions for Nginx Ingress Controller. Each of them routes to services for web app(React app hosted on nginx) and web api(.Net Core).
First is workig fine, but it is cumbresome since I need to add entry in etc file for each specified host to make it work:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx-controller
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: testapp-web-dev
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: testapp-portal-web-service
port:
number: 80
- host: testapp-api-dev
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: testapp-portal-api-service
port:
number: 80
I decided to modify it to have single host with multiple paths, so I will have only one entry in etc file. But it does not work. First request is routed correctly to http://testapp//testapp-web-dev but every other next
request fails i.e. request for manifest goes to http://testapp/manifest.json but it should go to http://testapp/testapp-web-dev/manifest.json.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx-controller
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host: testapp
http:
paths:
- path: /testapp-web-dev(/|$)(.*)
pathType: Prefix
backend:
service:
name: testapp-portal-web-service
port:
number: 80
- path: /testapp-api-dev(/|$)(.*)
pathType: Prefix
backend:
service:
name: testapp-portal-api-service
port:
number: 80
Tried couple different url rewrite but without luck.
If you want to preserve the requested path, you need to remove the nginx.ingress.kubernetes.io/rewrite-target: /$2 annotation.
As per Nginx Ingress Rewrite:
In this ingress definition, any characters captured by (.*) will be
assigned to the placeholder $2, which is then used as a parameter in
the rewrite-target annotation.
i.e., the annotation is redirecting http://testapp/testapp-web-dev/manifest.json to http://testapp/manifest.json.
My backend has 5 different deployments, each serving the request in a specific port.
Frontend service contacts the backend service with the necessary details. The backend service should be able to decide the required pod (from one of the 5 deployments) to serve the request.
Instead of creating 5 different services, is it possible to link a single service to multiple deployments?
Kubernetes version: 1.12
Cloud being used: Amazon EKS
PS: My requirement is different from https://github.com/kubernetes/kubernetes/issues/24875
Similar question is unanswered: "Wire" multiple Deployments to one Service in Kubernetes
The exact answer to your quest is: it is not possible today.
As you have correctly seen in the issue and in the question (both facing the same situation) this could be a future implementation.
A possible solution/workaround is to delegate the problem to an upper layer but basically it depends on the situation and different services are always required.
Assuming that your deployments are 5 different application that do different things (otherwise why 5 different deployment and not 1 with n replicas?) and assuming they are http applications, you can use the ingress resource to ruote the traffic to the right deployment/service (assuming one service per deployment).
If your 5 deployment are created/updated/managed together (eg: are all in the same helm deployment) you can create a fanout ingress:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: simple-fanout-example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
backend:
serviceName: service1
servicePort: 4200
- path: /bar
backend:
serviceName: service2
servicePort: 8080
- path: /aaaa
backend:
serviceName: service3
servicePort: 4200
- path: /bbbbb
backend:
serviceName: service4
servicePort: 8080
- path: /ccc
backend:
serviceName: service5
servicePort: 8080
Or, if your 5 deployment are separated you can create 5 Different ingress serources with the same idea:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-for-app-1
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
backend:
serviceName: service1
servicePort: 4200
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-for-app-1
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /bar
backend:
serviceName: service2
servicePort: 8080
and so on....
Creating 5 ingress or 1 fanout should produce the same result.
This approach works well with a nginx ingress controller but pay attention only to two things
path match: with the nginx controller version > 0.22 nginx.ingress.kubernetes.io/rewrite-target: / is an exact match. For example, if you wold like to redirect from /foo to / preserving all the uri after /foo (/foo/something?parameter=parameter_value to /something?parameter=parameter_value) your ingress rewrite rule should be like this:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-for-app-1
annotations:
nginx.ingress.kubernetes.io/rewrite-target: "/$1"
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo/(.*)
backend:
serviceName: service1
servicePort: 4200
conflict route: avoid conflicting rout, eg path: /foo/(.*) and path: /foo/bar/(.*) where a request for /foo/bar/something would match both the paths. The behavior could be difficult to predict and, if it worked as expected, it would not be stable
I'm trying to make a simple example of ingress-nginx on google cloud, but it's not matching the subpaths:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /one
backend:
serviceName: test-one-backend
servicePort: 80
- path: /two
backend:
serviceName: test-two-backend
servicePort: 80
When I call, http://server/one works, but when I call http://server/one/path I get a 404.
I'd tried several things like using regex, but is simply not working
The backends are just, echo servers that reply always on any path.
You need to use a /* at the end of the path:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /one/*
backend:
serviceName: test-one-backend
servicePort: 80
- path: /two
backend:
serviceName: test-two-backend
servicePort: 80
It's not really documented widely as of today, but in essence the path translates to a location {} block in the nginx.conf
Attention it changed in version 0.22.0 of ingress-nginx. checkout example at https://github.com/kubernetes/ingress-nginx/blob/master/docs/examples/rewrite/README.md
Now you have to work with captured groups to pass a subpath to the rewrite-target.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: rewrite
namespace: default
spec:
rules:
- host: rewrite.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /something(/|$)(.*)
This definition matches the exact string for the path. If you want to include subdirectories you can use the wildcard *. Your modified definition should look like this:
- path: /one/*
backend:
serviceName: test-one-backend
servicePort: 80
I am not sure if http://server/one (without the slash at the end) still works. In that case you have to keep your old definition and add another one like the above.
I want exposing various services with a single ingress.
rules:
- http:
paths:
# The path is the URL prefix for the service, e.g. /api/* or just /*
# Note that the service will receive the entire URL with the prefix
- path: /service1/*
backend:
serviceName: service1
servicePort: 5000
- path: /service2/*
backend:
serviceName: service2
servicePort: 5000
The problem is the whole URL including the prefix is passed to the underlying services so all requests return 404 errors: service1 and api don't respond on /service1/some/path but directly on /some/path
How can I specify a prefix to the underlying services?
UPDATE
I tried using rewrite-target as follows. Requests are sent to the rasa-nlu service, but they all trigger 404 because rasa-nlu still gets the /nlu
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /nlu
backend:
serviceName: rasa-nlu
servicePort: 5000
This might be what you are looking for;
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/rewrite-target: /
name: rewrite
namespace: default
spec:
rules:
- host: rewrite.bar.com
http:
paths:
- backend:
serviceName: echoheaders
servicePort: 80
path: /something
Note the annotation to rewrite-target.
Found this here
This thread might be solved till now, but just for the sake of solution.
below will solve the issue, the default path will be /nlu when it is added to the re-write annotation.
It is from the nginx re-write rule which gets applies to the definition of location directive.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
ingress.kubernetes.io/rewrite-target: /nlu
spec:
rules:
- http:
paths:
- path: /nlu
backend:
serviceName: rasa-nlu
servicePort: 5000