Istio VirtualService - broken URLs - url

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

Related

Many different hosts in Ingress configuration file

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.

k8s ingress path match not working as expected

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?

nginx-ingress shows HTTP Error 404 for a react app deployed on Domain path, but works for subdomain path

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

Nginx Ingress path is not pointing to service / path

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/

How to redirect with envoy proxy

We use envoy proxy as an ingress HTTP proxy. Now we would like to have a redirect from https:/our_domain/ to https:/our_domain/static/index.html.
All our attempts failed so far, for example
routes:
- match:
path: "/"
redirect: { path_redirect: "/static/index.html" }
- match:
prefix: "/"
route:
prefix_rewrite: "/"
cluster: our_cluster
How to configure routing for this use case? Please no Lua solution.
The problem was that the envoy proxy is behind a tls-terminating proxy. The redirect is therefore always with a http scheme, which is not served by the tls-terminating proxy.
The solution is
https_redirect
(bool) The scheme portion of the URL will be swapped with “https”.
The correct routing must thus be
routes:
- match:
path: "/"
redirect:
https_redirect: true
path_redirect: "/static/index.html"
- match:
prefix: "/"
route:
cluster: our_cluster
Prefix “/“ matches any request so you just redirect endlessly. Set up a route that matches prefix “/static” in front of the catch all one and forward to it to an upstream cluster to provide a response. (For static files you could also serve them directly from Envoy.)
- name: listener_http
address:
socket_address:
address: 0.0.0.0
port_value: 80
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type : auto
stat_prefix: ingress_http
route_config:
virtual_hosts:
- name: backend
domains:
- "*"
routes:
- match:
prefix: "/"
redirect:
path_redirect: "/"
https_redirect: true
http_filters:
- name: envoy.router
config: {}
put this code before your listerner of https section to redirect all request

Resources