K8s nginx ingress path return 404 - nginx

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

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

Handle overlapping ingress paths

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

How to handle kubernetes Ingress Rule with two backends

I try to run my web application with two backend containers.
/ should be routed to the frontend container
everything starting with /backend/ should go to the backend container.
So fare, so good, but now the css & js files from the /backend are not loaded because the files are referenced in the HTML file like "/bundles/css/style.css" and now ingress controller route this request to the frontend container instead of to the backend.
How can I fix this issue?
Can I fix that with a smart Ingress rule?
Do I need to update the app root of the backend container?
Here my Ingress resource
apiVersion: networking.k8s.io/v1 # for versions before 1.14 use extensions/v1beta1
kind: Ingress
metadata:
name: example
namespace: example
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
tls:
- hosts:
- www.example.ch
secretName: tls-example.ch
rules:
- host: www.example.ch
http:
paths:
- path: /backend(/|$)(.*)
pathType: Prefix
backend:
service:
name: example-backend-svc
port:
number: 8081
- path: /
pathType: Prefix
backend:
service:
name: example-frontend-svc
port:
number: 8080
You can add another path if all files are located in /bundles/* path.
I have given an example manifest file below.
apiVersion: networking.k8s.io/v1 # for versions before 1.14 use extensions/v1beta1
kind: Ingress
metadata:
name: example
namespace: example
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
tls:
- hosts:
- www.example.ch
secretName: tls-example.ch
rules:
- host: www.example.ch
http:
paths:
- path: /backend(/|$)(.*)
pathType: Prefix
backend:
service:
name: example-backend-svc
port:
number: 8081
- path: /bundles
pathType: Prefix
backend:
service:
name: example-backend-svc
port:
number: 8081
- path: /
pathType: Prefix
backend:
service:
name: example-frontend-svc
port:
number: 8080

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 rule for changing path on the fly

I would like to change the path of request coming to ingress-nginx on the fly to match what different backend services expect. For example, imagine these are the two services I have got:
foo service:
http://foo:8080/api/v1
bar service:
http://bar:8080/api/v1
I would like to expose foo service as http://test.com/foo/api and bar service as http://test.com/bar/api. However, I am not sure how I can change the path on the fly to match what the underlying service expects.
Example ingress.yaml file:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
rules:
- host: test.com
http:
paths:
- path: /foo/api/
backend:
serviceName: foo
servicePort: 8080
- path: /bar/api
backend:
serviceName: bar
servicePort: 8080
- path: /
backend:
serviceName: ui
servicePort: 80
You can try with rewrite annotations.
Look at the example provided in this documentation:
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(/|$)(.*)
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.
For example, the ingress definition above will result in the following rewrites:
rewrite.bar.com/something rewrites to rewrite.bar.com/
rewrite.bar.com/something/ rewrites to rewrite.bar.com/
rewrite.bar.com/something/new rewrites to rewrite.bar.com/new
Just adjust the path and other variables with your data.
Please let me know if that helped.

Resources