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?
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.
I had a Jenkins values.yaml file written prior to v1.19, I need some help to change it to be v1.19 compliant.
In the old Values.yaml below, I tried adding http path:/. Should the pathType be ImplementationSpecific?
Only defaultBackend works for some reason, not sure what I'm doing wrong with path and pathType.
ingress:
enabled: true
# Override for the default paths that map requests to the backend
paths:
# - backend:
# serviceName: ssl-redirect
# servicePort: use-annotation
- backend:
serviceName: >-
{{ template "jenkins.fullname" . }}
# Don't use string here, use only integer value!
servicePort: 8080
# For Kubernetes v1.14+, use 'networking.k8s.io/v1'
apiVersion: "networking.k8s.io/v1"
labels: {}
annotations:
kubernetes.io/ingress.global-static-ip-name: jenkins-sandbox-blah
networking.gke.io/managed-certificates: jenkins-sandbox-blah
kubernetes.io/ingress.allow-http: "true"
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
# Set this path to jenkinsUriPrefix above or use annotations to rewrite path
# path: "/jenkins"
# configures the hostname e.g. jenkins.example.com
hostName: jenkins.sandbox.io
There are several changes to the definition of Ingress resources between v1.18 and v1.19.
In v1.18, we defined paths like this (see: A minimal Ingress resource example):
paths:
- path: /testpath
pathType: Prefix
backend:
serviceName: test
servicePort: 80
In version 1.19 it was changed to: (see: A minimal Ingress resource example):
paths:
- path: /testpath
pathType: Prefix
backend:
service:
name: test
port:
number: 80
In your example, you can slightly modified the values.yaml and try again:
NOTE: You may need to change the port number and pathType depending on your configuration. Additionally, I've added the kubernetes.io/ingress.class: nginx annotation because I'm using NGINX Ingress Controller and I didn't configure the hostname.
$ cat values.yaml
controller:
ingress:
enabled: true
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: >-
{{ template "jenkins.fullname" . }}
port:
number: 8080
apiVersion: "networking.k8s.io/v1"
annotations:
kubernetes.io/ingress.global-static-ip-name: jenkins-sandbox-blah
networking.gke.io/managed-certificates: jenkins-sandbox-blah
kubernetes.io/ingress.allow-http: "true"
kubernetes.io/ingress.class: nginx
# configures the hostname e.g. jenkins.example.com
# hostName: jenkins.sandbox.io
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 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/
Help!
I am using Istio to setup a service mesh in Kubernetes. The Virtual Service definition routes the traffic to the desired service:
(...)
http:
- match:
- uri:
prefix: /drill/
rewrite:
uri: /
route:
- destination:
host: drill-service.drill.svc.cluster.local
port:
number: 8047
However, when calling the entrypoint
https://<HOST>:<NODEPORT_INGRESS_GW>/drill
I do see the HTML page, but the URLs are broken and CSS sheets are not loaded correctly. Reason is that the HTML source code points to the wrong targets:
li>Storage</li>
instead of
li>Storage</li>
How can I fix this problem?
Thanks,
Matt
When you use rewrite you need to add path in virtual service for your dependencies like css and js.
The whole process with rewrite and how it should be configured was well explained by #Rinor here.
This Istio in practise tutorial also explains it well.
Let’s break down the requests that should be routed to Frontend:
Exact path / should be routed to Frontend to get the Index.html
Prefix path /static/* should be routed to Frontend to get any static files needed by the frontend, like Cascading Style Sheets and JavaScript files.
Paths matching the regex ^.*.(ico|png|jpg)$ should be routed to Frontend as it is an image, that the page needs to show.
http:
- match:
- uri:
exact: /
- uri:
exact: /callback
- uri:
prefix: /static
- uri:
regex: '^.*\.(ico|png|jpg)$'
route:
- destination:
host: frontend
port:
number: 80
Additionally you can take a look here.
EDIT
Why your example does not work
With your current virtual service your requests will be as follows:
http://www.page.com/drill/
Rewritten: http://www.page.com/
http://www.page.com/drill/storage
Rewritten: http://www.page.com/storage
So now you would have to either change virtual service configuration, for example for paths without rewrite or change your app dependencies location, so istio could actually see /drill/storage path with your current virtual service, for now it see /storage path , and there is nothing here as the real path is /drill/storage.
http:
- match:
- uri:
prefix: /
- uri:
prefix: /drill/storage/
- uri:
prefix: /...
What I would suggest
If you have your domain configured as a virtual service host you might try with this virtual service:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: istio-vs
spec:
hosts:
- "drill.domain.com"
gateways:
- gateway
http:
- match:
- uri:
prefix: /
rewrite:
uri: /drill/
route:
- destination:
host: drill-service.drill.svc.cluster.local
port:
number: 8047
With this virtual service your requests will be as follows:
http://www.page.com/
Rewritten: http://www.page.com/drill/
http://www.page.com/storage
Rewritten: http://www.page.com/drill/storage