GKE ingress; apply rewrite to specific service - kubernetes

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.

Related

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.

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.

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

Kubernetes ingress nginx not matching sub paths

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.

kubernetes ingress with multiple target-rewrite

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.