I have nginx ingress installed on my cluster. Here is the yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-client
annotations:
kubernetes.io/ingress.class: nginx
namespace: dev
spec:
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: client-service
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
When I hit / prefix it is good.
curl http://example.com (All Good)
Problem:
But when I hit / api prefix, it returns /api of the service not / of the service
curl http://example.com/api (It should link to api-service, but it is linking to api-service/api)
Any help will be appreciated!
This is because a path / with type Prefix will match / and everything after, including /api. So your first rule overshadows the second rule in some sense.
I don't know if it's an option for you, but it would be probably most elegant and idiomatic to use different hostnames for both services. If you deploy cert-manager, this shouldn't be a problem.
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: client-service
port:
number: 80
# use a different hostname for the api
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
Another option could be to use regex in your frontend path rule. And let it not match when the slash is followed by api. For that, you need to set an annotation.
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
Then you can do something like the below for your frontend service. Using a negative lookahead.
- path: /(?!api).*
Alternatively, but less pretty, you could add a path prefix to your frontend service and strip it away via path rewrite annotation. But then you may have to write two separate ingress manifests as this is annotation counts for both, or you need to use a more complex path rewrite rule.
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
- path: /ui(/|$)(.*)
Perhaps it's also sufficient to move the more specific route, /api, before the generic / route. In that case, switch the path around in the list. If they end up in that order in the nginx config, nginx should be able to handle it as desired.
You could use nginx.ingress.kubernetes.io/rewrite-target:
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.
So, here you could change your ingress as next:
metadata:
name: ingress-client
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
namespace: dev
The ingress definition above will result in the following rewrites:
api-service/api rewrites to api-service/
Related
I am trying to automate the hosts in Ingress Controller and I'm facing the problem of generating many hosts into one file. What I mean is, I have this ingress.yaml:
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-host
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/default-backend: a
spec:
rules:
- host: a.example.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: a
port:
number: 80
- host: b.example.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: b
port:
number: 80
...
- host: x.example.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: x
port:
number: 80
...
in this example I have multiple instances: a, b, all the way to x and I anticipate a lot more. Right now I am programmatically regenerating the whole ingress.yaml to add/remove certain hosts. This is prone to errors and hard to maintain, as I must constantly be aware about ingress.yaml to be broken for one reason or another.
What would really help me is to put every host into a separate file and (maybe) just tell ingress.yaml to scan the whole directory where those files are to be stored. This way, I can just add/remove a single file and reload Ingress
Is there an option for that? I found somewhere that IngressSpec could be somehow defined, but I do not see any usefull link with a valid example. Maybe someone found a solution to that already and can point me to the right direction?
Hostname wildcards
Hosts can be precise matches (for example “foo.bar.com”) or a wildcard (for example “*.foo.com”).
Or use template system, such as helm or Kustomize
As #jordanm suggested in the comment, I went with multiple Ingress objects on one IngressController, being sure I get rid of nginx.ingress.kubernetes.io/default-backend annotation:
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-x-host
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: x.example.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: x
port:
number: 80
I generate a unique file for each of hosts, replacing x with my unique name.
I also have to make sure that metadata.name is unique. If metadata.name is the same for every object, then it just gets replaced as I apply the new configuration. This works perfectly.
According to nginx path match policy: https://kubernetes.github.io/ingress-nginx/user-guide/ingress-path-matching/
Path Priority¶
In NGINX, regular expressions follow a first match policy. In order to enable more accurate path matching, ingress-nginx first orders the paths by descending length before writing them to the NGINX template as location blocks.
My rules are defined like this:
spec:
ingressClassName: some-lb
rules:
- host: "example.com"
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: cs-stage-backend
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: cs-stage-frontend
port:
number: 80
So, according to the path rule, if I go to example.com/api/v1/docs it should go to cs-stage-backend and rest all go to cs-stage-frontend. But it always goes to cs-stage-frontend.
Can anyone please help me if I am missing something?
I am trying to learn .NET Microservice. I have been following a great tutorial on Youtube (Time: 4:44:55, Adding An API Gateway). Everything worked well until NGINX Ingress came into the picture. I pasted the same YAML file from the GitHub account of the trainer I doubled checked all the things but couldn't find anything:
I can see all the pods and services are working fine:
I updated my host file.
What did I miss?
URL, I am using: http://acme.com/api/platforms/
Error: HTTP Error 404. The requested resource is not found.
The output of the Ingress YAML:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"networking.k8s.io/v1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx","nginx.ingress.kubernetes.io/use-regex":"true"},"name":"ingress-srv","namespace":"default"},"spec":{"rules":[{"host":"acme.com","http":{"paths":[{"backend":{"service":{"name":"platforms-clusterip-srv","port":{"number":80}}},"path":"/api/platforms","pathType":"Prefix"},{"backend":{"service":{"name":"commands-clusterip-srv","port":{"number":80}}},"path":"/api/c/platforms","pathType":"Prefix"}]}}]}}
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/use-regex: "true"
creationTimestamp: "2021-09-18T00:12:41Z"
generation: 1
name: ingress-srv
namespace: default
resourceVersion: "2274742"
uid: a7376202-8b1b-4f1a-a42f-08de5f602192
spec:
rules:
- host: acme.com
http:
paths:
- backend:
service:
name: platforms-clusterip-srv
port:
number: 80
path: /api/platforms
pathType: Prefix
- backend:
service:
name: commands-clusterip-srv
port:
number: 80
path: /api/c/platforms
pathType: Prefix
status:
loadBalancer:
ingress:
- hostname: localhost
Services:
UPDATE: Tried below commands and got some new information:
UPDATE: Result of
Kubectl get pods --namespace=ingress-nginx
Try removing the regex annotation from th ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
name: ingress-srv
namespace: default
spec:
rules:
- host: acme.com
http:
paths:
- backend:
service:
name: platforms-clusterip-srv
port:
number: 80
path: /api/platforms
pathType: Prefix
- backend:
service:
name: commands-clusterip-srv
port:
number: 80
path: /api/c/platforms
pathType: Prefix
or just try this nginx.ingress.kubernetes.io/rewrite-target: /
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: acme.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: commands-clusterip-srv
port:
number: 80
in above ingress, all requests will go to service commands-clusterip-srv so from browser side you pass anything either /api or /api/c ingress will route the traffic to that service if your host is acme.com
Error 404 clearly means there is some issue with your Nginx configuration path is not matching or host issue, Nginx not able to find upstream or target so it throws 404.
Update
Try adding IP and entry into the host file for
192.168.1.28 acme.com
i am not sure you have used the IP POD to curl ideally you should me using the acme.com as you can to access the data.
also hope you service, deployment and ingress are in same namespace.
First of all, Thank you Harsh for your precious time. I tried all the things but no error was found.
It was really a miracle that I am able to resolve it issue on HTTPS. I am able to access "https://acme.com/api/platforms". But still, HTTP is giving me the same error. However, I am fine with HTTPS
Here is my ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: 8link-app-kubernetes-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: link8.in
http:
paths:
- backend:
service:
name: link8-app-prod-svc
port:
number: 80
path: /
pathType: Prefix
- host: test.link8.in
http:
paths:
- backend:
service:
name: link8-app-prod-svc
port:
number: 80
path: /
pathType: Prefix
In the above ingress, I have the same Front-end service which is defined to be run on both Domain and sub-domain (for the testing), it is working for sub-domain but not for the domain.
I get Error 404 on domain path:
Following is my DNS settings, where value is my Ingress Address:
UPDATE:
In order to clear things for anyone, who will try to figure out the answer.
The question was answered by the author.
The problem was not in Kubernetes resources of any kind, it was a browser-specific issue, clearing the browser storage solved the problem.
my problem wasn't related to k8s;
it was working from start.
Just I had to clear everything for my domain in chrome storage
I am trying to create an ingress controller that points to a service that I have exposed via NodePort.
Here is the yaml file for the ingress controller (taken from https://kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/):
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: example-ingress
spec:
rules:
- host: hello-world.info
http:
paths:
- path: /
backend:
serviceName: appName
servicePort: 80
I can connect directly to the node port and the frontend is displayed.
Please note that I am doing this because the frontend app is unable to connect to other deployments that I have created and I read that an ingress controller would be able to solve the issue. Will I still have to add an Nginx reverse proxy? If so how would I do that? I have tried adding this to the nginx config file but with no success.
location /middleware/ {
proxy_pass http://middleware/;
}
You must use a proper hostname to reach the route defined in the Ingress object. Either update your /etc/hosts file or use curl -H "hello-world.info" localhost type command. Alternatively, you can delete the host mapping and redirect all traffic to one default service.
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: example-ingress
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: appName
servicePort: 80