Is there a way url redirect internally to particular service based on context path? - kubernetes

There are multiple same pods running in one cluster but different namespaces. This is the web application running in Kubernetes. I have the URL <HOSTNAME>:<PORT>/context/abc/def/...... I want to redirect to particular service based on the context. Is there a way i can achieve it using ingress controller ? Or Is there any way i can achieve it using different ports through ingress ?
My web application works fine if the URL is <HOSTNAME>:<PORT>/abc/def/...... Since i have to access the different pods using the same URL, I am adding context to it. Do we have any other way to achieve this use case ?

You can do that with rewrite-target. In example below i used <HOSTNAME> value of rewrite.bar.com and <PORT> with value 80.
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: context-service
servicePort: 80
path: /context1(/|$)(.*)
- backend:
serviceName: context-service2
servicePort: 80
path: /context2(/|$)(.*)
For example, the ingress definition above will result in the following rewrites:
rewrite.bar.com/context1 rewrites to rewrite.bar.com/ for context 1 service.
rewrite.bar.com/context2 rewrites to rewrite.bar.com/ for context 2 service.
rewrite.bar.com/context1/new rewrites to rewrite.bar.com/new for context 1 service.
rewrite.bar.com/context2/new rewrites to rewrite.bar.com/new for context 2 service.

You can manage how the traffic is pointed to the correct service by using the rules configuration of the ingress, here is a simple example from the documentation:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: app-ingress
spec:
rules:
- http:
paths:
- path: /abc
backend:
serviceName: abc-service
servicePort: 80
- path: /context
backend:
serviceName: context-service
servicePort: 80

Related

GKE ingress; apply rewrite to specific service

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.

REST URI with NGINX Ingress Controller

I'm trying to configure NGINX Ingress controller as the correct entry point to my Kubernetes cluster. Inside the cluster, I've created two REST Web services as well as frontend application. I'm trying to achieve the following scenario.
When the ingress IP is hit without any parameters it should be routed
to the frontend app. Example: 192.168.1.20 should lead to frontend
service on port 80.
When parameters are given, the request should be
routed to correct REST service. Example:
192.168.1.20/first-rest/api/flower?id=1 should route the request to
the first-rest service so that it could return the flower with id =
1.
I can correctly access the frontend application but when trying to access any REST service I'm getting 404 error or no response at all. First-rest, Second-rest and frontend are running correctly and are accessible when configured as LoadBalancer services. With Nginx, they are configured as ClusterIp services.
My ingress configuration
------------------------
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: main-routes
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- http:
paths:
- path: /first-rest(/|$)(.*)
backend:
serviceName: first-rest
servicePort: 8090
- path: /second-rest(/|$)(.*)
backend:
serviceName: second-rest
servicePort: 9000
- path: /(.*)
backend:
serviceName: frontend
servicePort: 80
It seems like NGINX is cutting short my URL parameters that are required for my REST API. Is there any way to pass the right URL path so that `192.168.1.20/first-rest/api/flower?id=1` would be routed to `[first-rest add and port]/api/flower?id=1` ?
You need to specify the ingress path type otherwise , depending on the ingress class specific implementation it will default to either exact or prefix (I assume in your case it is defaulting to exact)
So, you need to do something like
spec:
rules:
- http:
paths:
- path: /first-rest
pathType: Prefix
backend:
serviceName: first-rest
servicePort: 8090
see docs on ingress path here

Do I have to define an ingress per service with Linkerd?

Looking at the linkerd ingress documentation here it says that I need to create an ingress with an annotation of
ingress.kubernetes.io/custom-request-headers: l5d-dst-override:web-svc.emojivoto.svc.cluster.local:80
this annotation is specific to a single service, which makes it sound like there must be a new ingress with it's own annotation for every service. I couldn't have something like the following for example:
spec:
rules:
- host: example.com
http:
paths:
- path: /path-one
backend:
serviceName: service-1
servicePort: 80
- path: /path-two
backend:
serviceName: service-2
servicePort: 80
where I could define paths to different services in a single ingress class.
Is my reading of these docs accurate? or am I missing something? I am hoping to avoid creating an ingress for every service I run in linkerd.
Yes, unfortunately you understood correctly about creating separate ingress for each service if you want use ingress.kubernetes.io/custom-request-headers.
Yes, if you would have 1000 services - you should create 1000 ingresses to make it work properly.
Ingress1:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-ingress
namespace: marcus
annotations:
kubernetes.io/ingress.class: "traefik"
ingress.kubernetes.io/custom-request-headers: l5d-dst-override:service1.marcus.svc.cluster.local:80
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
path: /
Ingress2:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-ingress
namespace: marcus
annotations:
kubernetes.io/ingress.class: "traefik"
ingress.kubernetes.io/custom-request-headers: l5d-dst-override:service2.marcus.svc.cluster.local:80
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80
path: /
Traefik is a great solution, and in this case it would be great if it had the option to dynamically set the service in a header.
There is an open issue on this in the traefik project that has been open for a while. The last update is to use an Ingress per service in these scenarios.
Here's similar question.

Disable path rewrite for Kubernetes fan out Ingress

My Kubernetes application uses an Ingress to proxy requests to different servers, according to the URL given: I want a fanout configuration. I want the URLs of the requests not to be rewritten when forwarded to the servers. How do I do that?
I want all the /api URLs forwarded to the be service, and all others forwarded to the fe service. But I want the URLs forwarded unchanged.
For example
a request for /api/users should be forwarded to the be service as a request for /api/users.
a request for /foo should be forwarded to the fe service as a request for /foo.
My current Ingress resource is like this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
...
spec:
...
rules:
- host: ...
- http:
paths:
- path: /api
backend:
serviceName: be
servicePort: 8080
- path: /
backend:
serviceName: fe
servicePort: 80
but that does not work; it gives 404 Not Found for requests.
The Kubernetes ingress isn't rewriting your request URLs, the ingress controller is doing this (whatever you happen to be using). For instance, if your ingress controller is Nginx, you can control this behavior with annotations on the ingress.
Old question but i got a similar problem solved with nginx ingress annotations as suggested by Grant David Bachman:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
...
spec:
...
rules:
- host: ...
- http:
paths:
- path: "/(api.*)"
backend:
serviceName: be
servicePort: 8080
- path: "/(.*)"
backend:
serviceName: fe
servicePort: 80

Multiple deployments in single service

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