Rewriting Kubernetes services in an Nginx ingress - kubernetes

I have multiple APIs all listening on '/api' and a web front end listening on '/'.
Is there a way which I can write my ingress definition to rewrite the paths to something like the following?
/api/ -> /api/ on service1
/api2/api/ -> /api/ on service2
/api3/api/ -> /api/ on service3
/ -> / on service4
I know I can change the APIs to listen to something else but don't want to do that. I know I can also just rewrite all to /api/ and let service3 act as the default but there may be other services which need routing elsewhere in the future.
I've heard that you could use multiple ingresses but I'm not sure how that would affect performance and if it's best practice to do so.
Also, is there any way to debug which route goes to which service?
Thanks,
James

With help from #Rahman - see other answer. I've managed to get this to work with a single ingress.
I've had to post this as an additional answer because of the character limit.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-name
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
tls:
- secretName: tls-secret
rules:
- host: localhost
http:
paths:
- path: /(api/.*)
backend:
serviceName: service1
servicePort: 80
- path: /api2/(api.*)
backend:
serviceName: service2
servicePort: 80
- path: /api3/(api.*)
backend:
serviceName: service3
servicePort: 80
- path: /(.*)
backend:
serviceName: service4
servicePort: 80
Just for context for anyone else stumbling upon this in the future, service 1 is a main API, service 2 and 3 are other APIs under another subdomain and service 4 is a web frontend.

If you are using Nginx, you should be able to configure your Ingress for path matching like this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: test.com
http:
paths:
- path: (/api/.*)
backend:
serviceName: service1
servicePort: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress-2
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
rules:
- host: test.com
http:
paths:
- path: /api2/.*
backend:
serviceName: service2
servicePort: 80
- path: /api3/.*
backend:
serviceName: service3
servicePort: 80
- path: /.*
backend:
serviceName: service4
servicePort: 80
More info

Related

EKS Ingress ALB add HTTP listener for some services and HTTPS for others

I have the following ingress.yaml file
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: in
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=600
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/certificate-arn: xxxx
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
spec:
rules:
- http:
paths:
- path: /api/bulk-api/*
backend:
serviceName: dg-bulk-api
servicePort: 5000
- path: /api/adjuster-selection
backend:
serviceName: dg-adjuster-selection
servicePort: 5050
- path: /api/cockpit/*
backend:
serviceName: dg-cockpit
servicePort: 5050
- path: /api/regression/*
backend:
serviceName: dg-regression
servicePort: 5005
- path: /api/lp/task-details*
backend:
serviceName: lp-task-detail
servicePort: 5050
- path: /api/tool-setup/*
backend:
serviceName: dg-tool-setup
servicePort: 5000
- path: /api/guideline/*
backend:
serviceName: dg-guideline
servicePort: 5050
- path: /*
backend:
serviceName: dg-ui
servicePort: 80
The above mentioned yaml creates an ALB with listener at 80 and 443 added for all the routes. However, I want listener 80 for for all routes except dg-ui service and 443 for dg-ui service only. Let me know how can this be done.
I have been able to solve the issue. Thought it would be helpful for everyone.
Updated my ALB Ingress Controller to v2.1. Instructions can be found at: AWS LoadBalancer Controller
Create separate Ingress Yaml for Http and Https listener rules.
Add annotation: alb.ingress.kubernetes.io/group.name: my-team.awesome-group to both Ingress. This would create 2 Ingress and attach the rules to 1 common ALB. More on this annotation can be found here: IngressGroups
If you want to ensure some urls working with just https or http you need to define ingress.kubernetes.io/ssl-redirect: "true" annotation for http or ingress.kubernetes.io/ssl-redirect: "false" for using just http. The fact is that declared annotation affect whole path that you define in ingress object that is why you need to seperate Ingress definitions like below examples. So that for http you need to use like below yaml;
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: https-ingress
annotations:
ingress.kubernetes.io/ssl-redirect: "true"
spec:
tls:
- hosts:
- example.com
secretName: tls-secret
rules:
- host: example.com
http:
paths:
- path: /secured
backend:
serviceName: my-service
servicePort: 8080
For just http you need to use like below yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: http-ingress
annotations:
ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- host: example.com
http:
paths:
- path: /unsecured
backend:
serviceName: my-service
servicePort: 8080

Redirect trafic from one app (workload) to other if there is prefix?

I have two apps (workloads): app1 and app2. My goal is to redirect trafic from app1 to app2 if there is the diona prefix. For example:
app1/diona > app2/<api>
Now I have such rules:
rules:
- host: host
http:
paths:
- backend:
serviceName: ingress-37ce1ad1e8214375784d1e50805c056c
servicePort: 80
path: /diona
When I check app1/diona endpoint in logs of app2 there is an error:
Not Found: /diona
How can I redirect trafic correctly without realizing diona prefix in app2?
You can achieve it using nginx ingress controller. You code will look like this
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
name: rewrite
spec:
rules:
- host: host
http:
paths:
- backend:
serviceName: ingress-37ce1ad1e8214375784d1e50805c056c
servicePort: 80
path: /diona
If you want to redirect app1/diona/* to app2/*, change annotations to
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
name: rewrite
spec:
rules:
- host: host
http:
paths:
- backend:
serviceName: ingress-37ce1ad1e8214375784d1e50805c056c
servicePort: 80
path: /diona/(.*)
Reference

same path with different service names in ingress resources

I'm having some issues when using a path to point to different service names, my ingress resource looks as below
nginx-static service is a nginx container which has static content... I have to load this static content while calling service-1, since both nginx-static and service-1 but I cannot keep the sme same host path.... Please suggest how to correct the below ingress resources...
kindly note static content has lot of files(csv,js,html,directories, files etc)
kind: Ingress
metadata:
name: myingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- http:
paths:
- path: "/"
backend:
serviceName: nginx-static
servicePort: 80
- path: "/"
backend:
serviceName: service1
servicePort: 8989
- path: "/test1"
backend:
serviceName: service2
servicePort: 9001
Any expert help is appreciated!!!
You cannot have the same path pointing to different backend resources. You have to put either your static files or the service into a different path, and rewrite the URL, for instance:
rewrite annotation:
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: rewrite
namespace: default
paths:
- backend:
serviceName: nginx-statix
servicePort: 80
path: /static(/|$)(.*)
- backend:
path: /
serviceName: service1
With this, your static content will be exposed under /static/, and all /static/name will be rewritten as /name by the ingress.
More info here: https://kubernetes.github.io/ingress-nginx/examples/rewrite/
Unfortunately, requirements from the initial questions aren't' clear and there were no additional clarifications given. However, I'd like to elaborate on Burak Serdar's answer and add , that Kubernetes Ingress allows you listing the same path ad port for a multiple services under condition that you are listing these for different hosts.
foo.bar.com --| |-> foo.bar.com nginx-static:80
| 178.91.123.132 |
bar.foo.com --| |-> bar.foo.com service1:8989
you can achieve that scenario with the following config:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: nginx-static
servicePort: 80
- host: bar.foo.com
http:
paths:
- backend:
serviceName: service2
servicePort: 8989
However that would work only if you can split your web site between two hosts.
Hope that helps.
You can check more on Ingress on K8s documentation.

Kubernetes nginx ingress rewrite issue

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
namespace: default
name: my-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: $2
spec:
rules:
- host: hostname.com
http:
paths:
- path: /
backend:
serviceName: frontend
servicePort: 80
- path: /api/v1(/|$)(.*)
backend:
serviceName: backend
servicePort: 80
What I am trying to accomplish here is:
hostname.com/api/v1/anyurl should become hostname.com/anyurl when it goes to the backend.
hostname.com/anyurl should remain hostname.com/anyurl and go to the frontend.
The /api/v1 rewrite seems to work, but any urls going to the frontend gets rewrited to /.
What I need is the rewrite rule to only apply to the /api/v1 path
I guess this should work for you -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
namespace: default
name: my-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: $1
spec:
rules:
- host: hostname.com
http:
paths:
- path: /(.*)
backend:
serviceName: frontend
servicePort: 80
- path: /api/(.*)
backend:
serviceName: backend
servicePort: 80
I have just edited this, it works for me, please check for this. I guess we can troubleshoot

Dynamic redirect using ingress

I have 2 questions:
1) I have a kubernetes cluster with multiple services and I want to use ingress to dynamically redirect the traffic to the cluster.
I expect the configuration to look something like this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /service1/*
backend:
serviceName: service1
servicePort: 80
path: /*
- path: /service2/*
backend:
serviceName: service2
servicePort: 80
path:/*
So basically I want all the traffic to /service1/endpoint to be redirected to s1:80/endpoint dynamically.
2) Let's say I have 2 web services - service1 & service2.
I want the users to work with the following URL in their browser:
kube/serviceN/endpoint
Is there a way to do that without having my users redirected to service1/endpoint?
Thanks!
I believe your ingress definition to be almost correct:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /service1
backend:
serviceName: service1
servicePort: 80
- path: /service2
backend:
serviceName: service2
servicePort: 80
This should work if you have an ingress correctly deployed!
I hope I have understood your question properly but if so, what you have provided as an example is pretty close to the mark. The below config should work as described.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /service1/
backend:
serviceName: service1
servicePort: 80
- path: /service2/
backend:
serviceName: service2
servicePort: 80
Good luck :)