Handle overlapping ingress paths - nginx

I have one ingress which handles all requests to my-domain.example.com/api and forwards them to backend-service/api:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: default-backend
spec:
ingressClassName: nginx
rules:
- host: my-domain.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: backend-service
port:
number: 8080
Now I added this second ingress, which should only handle the sub-path my-domain.example.com/api/log and forward it to logger-service/api:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: logger
annotations:
ingress.kubernetes.io/rewrite-target: /log/$2
spec:
ingressClassName: nginx
rules:
- host: my-domain.example.com
http:
paths:
- path: /api/log(/|$)(.*)
pathType: Prefix
backend:
service:
name: logger-service
port:
number: 8080
But this doesn't work reliable. The log of the ingress controller tells me, that the request to my-domain.example.com/api/log was forwarded to the backend-service. I guess the overlapping paths make it unpredictable.
How do I have to configure my ingresses if I have one service which should handle all defaults (/api/) and some other services which should handle specific sub-paths (/api/log)?

Each path in an Ingress is required to have a corresponding path type. Paths that do not include an explicit pathType will fail validation.
The only supported wildcard character for the path field of an Ingress is the * character. The * character must follow a forward slash (/) and must be the last character in the pattern. For example, /, /foo/, and /foo/bar/* are valid patterns, but , /foo/bar, and /foo//bar are not.A more specific pattern takes precedence over a less specific pattern. If you have both /foo/ and /foo/bar/, then /foo/bar/bat is taken to match /foo/bar/.For more information about path limitations and pattern matching, see the URL Maps documentation.
Suggestion : For second ingress try by mentioning the path as /api/log .*
As shown below
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/rewrite-target: /
name: logger
spec:
ingressClassName: nginx
rules:
-
host: my-domain.example.com
http:
paths:
-
backend:
service:
name: logger-service
port:
number: 8080
path: /api/log*
pathType: Prefix
Above YAML is working, find below Screenshot :
Additional reference doc :
Link1
Link2

Related

Kubernetes ingress nginx route to same path (different service; different port)

I have some simple deployments, pods, services and nginx ingress in Kubernetes. I want to use ingress to route to the services (cluster-ip).
However, there are 2 services for 2 pods with the same path (i.e /abc/def). After I applied the ingress.yaml file, I got an error message saying "nginx: [emerg] duplicate location "/abc/def/" in /tmp/nginx/nginx-cfg728288520:2893".
May I know how to let ingress accepts the same paths with different service and different port?
Here is the ingress.yaml file:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/use-regex: "true"
name: ingress-nginx-default
namespace: default
spec:
rules:
- host:
http:
paths:
- path: /abc/def/
pathType: Prefix
backend:
service:
name: service1
port:
number: 8090
- path: /abc/def
backend:
service:
name: service2
port:
number: 8068
pathType: Prefix
ingressClassName: nginx
"nginx: [emerg] duplicate location "/abc/def/" in /tmp/nginx/nginx-cfg728288520:2893". This error indicates the same host with two same paths which is a duplicate location.
You can use simple fanout based on path or name based virtual hosting.
In order to do this you need to have two hosts that need to be mentioned in the ingress.
based on your example you'd most likely want to have something like foo.bar.com and bar.foo.com. Here's the example from the Kubernetes docs:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: foo.bar.com
http:
paths: #path_name
- backend:
serviceName: service1
servicePort: 80
- host: bar.foo.com
http:
paths: #path_name
- backend:
serviceName: service2
servicePort: 80

K8s nginx ingress path return 404

I am trying to setup my services inside nginx ingress. In this case, I want to have a mail service along the path test.io/mail/. I make a request to test.io/mail/send_mail/ the response comes 404.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: test-backend
spec:
ingressClassName: nginx
rules:
- host: test.io
http:
paths:
- path: /mail/
pathType: Exact
backend:
service:
name: email-test
port:
number: 80
If I change the settings and remove the prefix, then everything will work.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: test-backend
spec:
ingressClassName: nginx
rules:
- host: test.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: email-test
port:
number: 80
How do I properly set the prefix?
Please have ingress yaml as below to use "pathType: Prefix" instead of "pathType: Exact"
rules:
- host: test.io
http:
paths:
- path: /mail/
pathType: Prefix
Please refer official documentation for more details for
pathType: Prefix
Each path in an Ingress is required to have a corresponding path type. Paths that do not include an explicit pathType will fail validation.
The only supported wildcard character for the path field of an Ingress is the * character. The * character must follow a forward slash (/) and must be the last character in the pattern. For example, /, /foo/, and /foo/bar/* are valid patterns, but , /foo/bar, and /foo//bar are not.A more specific pattern takes precedence over a less specific pattern. If you have both /foo/ and /foo/bar/, then /foo/bar/bat is taken to match /foo/bar/.For more information about path limitations and pattern matching, see the URL Maps documentation.
Suggestion :
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: test-backend
spec:
ingressClassName: nginx
rules:
- host: test.io
http:
paths:
- path: /mail/*
pathType: Exact
backend:
service:
name: email-test
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: email-test
port:
number: 80
Additional reference doc :
Refer1
Refer2

nginx ingress: Cannot redirect to backend service

I have scoured the Net to try to resolve something that seems to be a common issue, but unfortunately all of the documentation and suggestions have not solve my problem. I hope that you can help me and others with it.
We are migrating from another ingress to nginx-ingress. To validate our installation, I am using httpbin as the backend service.
When I create the following ingress with a path of '/' and send the query, I receive a proper response.
curl -I -k http://abczzz.com/anything
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mikie-ingress
namespace: mikie
spec:
ingressClassName: nginx
rules:
- host: abczzz.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: httpbin-service
port:
number: 8999
What we really need is to be able to redirect to different services off of this single host, so I changed the ingress to the following, but the query always fails with a 404. Basically, I want the /httpbin to disappear and pass the path onto the backend service, httpbin.
curl -I -k http://abczzz.com/httpbin/anything
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mikie-ingress
namespace: mikie
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^(/httpbin)$ $1/ redirect;
spec:
ingressClassName: nginx
rules:
- host: abczzz.com
http:
paths:
- path: /httpbin(/|$)(.*)
pathType: Prefix
backend:
service:
name: httpbin-service
port:
number: 8999
I'd really appreciate your help to resolve what must be a simple routing issue.
Thanks for your time and interest.
I finally figured things out... Hopefully, the following snippet will help others...
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mikie-ingress
namespace: mikie
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
ingressClassName: nginx
rules:
- host: abczzz.com
http:
paths:
- backend:
service:
name: httpbin-service
port:
number: 8999
path: /httpbin/(.*)
pathType: Prefix

kubernetes ingress server-alias only applies to one ingress host

According to this doc (https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#server-alias), I'm able to add additional server_name to the nginx config file.
However, it adds the extra server_name to all of my hosts, which cause conflicts for sure.
Is there a way to add server-alias only for one of my hosts? Say I only want to add 10.10.0.100 to my test1 host.
Ingress example:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/server-alias: 10.10.0.100
spec:
rules:
- host: test1.com
http:
paths:
- path: /
backend:
service:
name: test1-service
port:
number: 8000
pathType: Prefix
- host: test2.com
http:
paths:
- path: /
backend:
service:
name: test2-service
port:
number: 8000
pathType: Prefix
TL;DR
You can split your Ingress resource on multiple objects (which will work together) to add Annotations to only specific hosts.
Annotations can only be set on the whole kubernetes resource, as they are part of the resource metadata. The ingress spec doesn't include that functionality at a lower level.
-- Stackoverflow.com: Questions: Apply nginx-ingress annotations at path level
Extending on the answer to give an example of how such setup could be created. Let's assume (example):
All required domains pointing to the Service of type LoadBalancer of nginx-ingress-controller:
hello.kubernetes.docker.internal - used in host .spec
hello-two.kubernetes.docker.internal - used in annotations .metadata
--
goodbye.kubernetes.docker.internal - used in host .spec
goodbye-two.kubernetes.docker.internal- used in annotations .metadata
Skipping the Deployment and Service definitions, the Ingress resources should look like below:
hello-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-ingress
annotations:
nginx.ingress.kubernetes.io/server-alias: "hello-two.kubernetes.docker.internal"
spec:
rules:
- host: hello.kubernetes.docker.internal # <-- IMPORTANT
http:
paths:
- path: /
backend:
service:
name: hello-service
port:
number: 80
pathType: Prefix
goodbye-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: goodbye-ingress
annotations:
nginx.ingress.kubernetes.io/server-alias: "goodbye-two.kubernetes.docker.internal"
spec:
rules:
- host: goodbye.kubernetes.docker.internal # <-- IMPORTANT
http:
paths:
- path: /
backend:
service:
name: goodbye-service
port:
number: 80
pathType: Prefix
Above definitions will create 2 Ingress resources that will be merged:
hello-service will respond for:
hello.kubernetes.docker.internal
hello-two.kubernetes.docker.internal
goodbye-service will respond for:
goodbye.kubernetes.docker.internal
goodbye-two.kubernetes.docker.internal
Running:
$ kubectl get ingress:
NAME CLASS HOSTS ADDRESS PORTS AGE
goodbye-ingress <none> goodbye.kubernetes.docker.internal localhost 80 36m
hello-ingress <none> hello.kubernetes.docker.internal localhost 80 36m
Additional resources:
Kubernetes.io: Docs: Concepts: Services networking: Ingress
Kubernetes.github.io: Ingress NGINX: Annotations: Server alias

nginx-ingress works well for /, but not for subpaths

I have setup a name based ingress controller, but it doesn't seem to work for anything other than /.
So http://metabase.domain.com works but http://metabase.domain.com/style/app.css does not.
This is my config:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
namespace: domain
annotations:
kubernetes.io/ingress.global-static-ip-name: "domain"
name: domain-ingress
spec:
rules:
- host: metabase.domain.com
http:
paths:
- path: /
backend:
serviceName: metabase
servicePort: 80
- host: jenkins.domain.com
http:
paths:
- path: /
backend:
serviceName: jenkins
servicePort: 80
From the nginx.conf in the everything looks normal too. For some reason the nginx access and error logs are also empty so can't find anything from there too
As you mentioned, there is no error in the log files, and everything looks normal from
your perspective. I may suggest to tune up ingress using annotations tags.
I've checked documentation of ingress-nginx and found that below annotations may help a bit.
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.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
name: rewrite
namespace: default
spec:
rules:
- host: rewrite.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /something
If the Application Root is exposed in a different path and needs to be redirected, set the annotation
nginx.ingress.kubernetes.io/app-root
to redirect requests for /.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/app-root: /app1
name: approot
namespace: default
spec:
rules:
- host: approot.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /
If the application contains relative links, it is possible to add an additional annotation
nginx.ingress.kubernetes.io/add-base-url
that will prepend a base tag in the header of the returned HTML from the backend.
I got around to solving this, turns out somehow there was another ingress on my namespace that was a very old version of the nginx controller. I cleared my cluster and relaunched my ingress. Things worked out. Thanks for all the help everyone!

Resources