Kubernetes Ingress Exact not prioritized over Prefix - nginx

In Kubernetes we need a new service to handle the root path, but but still a catch everything else on our current frontend.
Current frontend Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: current-frontend
labels:
app: current-frontend
tier: frontend
annotations:
kubernetes.io/ingress.class: nginx
spec:
tls:
- hosts:
- my.domain.com
secretName: tls-secret
rules:
- host: my.domain.com
http:
paths:
- backend:
service:
name: current-frontend
port:
number: 80
path: /
pathType: Prefix
New service Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: new-service
labels:
app: new-service
tier: frontend
annotations:
kubernetes.io/ingress.class: nginx
spec:
tls:
- hosts:
- my.domain.com
secretName: tls-secret
rules:
- host: my.domain.com
http:
paths:
- backend:
service:
name: new-service
port:
number: 80
path: /someendpoint
pathType: ImplementationSpecific
- backend:
service:
name: new-service
port:
number: 80
path: /
pathType: Exact
According to the documentation of Kuberntes Ingress, it should prioritize Exact over Prefix
If two paths are still equally matched, precedence will be given to paths with an exact path type over prefix path type.
https://kubernetes.io/docs/concepts/services-networking/ingress/#multiple-matches
The problem is that everything else then my.domain.com/someendpoint goes to the current-frontend, while the expected would be that my.domain.com/ would go to new-service.
How do I achieving this?
Solution
I got it working, even If it doesn't seams to be the optimal solution (According to the Documentation)
I Followed Hemanth Kumar's answer and changed the Current Frontend to use Regex, with (.+) instead of (.*) as I wanted at least one char after the slash for it to be hit.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: current-frontend
labels:
app: current-frontend
tier: frontend
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
kubernetes.io/ingress.class: nginx
spec:
tls:
- hosts:
- my.domain.com
secretName: tls-secret
rules:
- host: my.domain.com
http:
paths:
- backend:
service:
name: current-frontend
port:
number: 80
path: /(.+)
pathType: Prefix
At the same time I needed to change the New service to use Prefix instead of Exact as it does not work, event if there is no other services to hit.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: new-service
labels:
app: new-service
tier: frontend
annotations:
kubernetes.io/ingress.class: nginx
spec:
tls:
- hosts:
- my.domain.com
secretName: tls-secret
rules:
- host: my.domain.com
http:
paths:
- backend:
service:
name: new-service
port:
number: 80
path: /someendpoint
pathType: ImplementationSpecific
- backend:
service:
name: new-service
port:
number: 80
path: /
pathType: Prefix

Ingress path matching can be enabled by setting the
nginx.ingress.kubernetes.io/use-regex annotation to true .
See the description of the use-regex annotation :
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
ingressClassName: nginx
rules:
- host: test.com
http:
paths:
- path: /foo/.*
pathType: Prefix
backend:
service:
name: test
port:
number: 80
Refer to this ingress path matching for more information on path priority

The solution is to use a regular expression (regex) to match all paths except /someendpoint.

Related

How to use Ingress Nginx to route requests by url query string?

We would like to use annotation for redirecting requests to a different backend service based on url args (query)
Example:
https://example.com/foo?differentQueryString=0 -> service-a
https://example.com/foo/bar?queryString=0 - service-b
Notes: path does not matter, this can be either /foo/bar or /foo or /bar/foo
We followed up on this
Kubernetes NGINX Ingress controller - different route if query string exists
and this
Kubernetes ingress routes with url parameter
But we don't want to setup ConfigMap just for this and also we don't want to duplicate requests to the ingress but rewriting
This is what we tried
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($args ~ queryString=0){
backend.service.name = service-b
}
spec:
ingressClassName: nginx
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service-a
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: service-b
port:
number: 80
We were expecting to get the response but we got 502 from the Ingress Nginx
We managed to find a nice solution without rewriting and ConfigMap
Works great and also include Nginx Ingress metrics so we can do HPA accordingly
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($args ~ queryString=0){
set $proxy_upstream_name "default-service-b-80";
set $proxy_host $proxy_upstream_name;
set $service_name "service-b";
}
spec:
ingressClassName: nginx
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service-a
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: service-b
port:
number: 80
$proxy_upsteam_name convention is NAMESPACE-SERVICE_NAME-PORT

Example needed: How to migrate ingress routing from Nginx to Traefik-V1 (or V2)?

I try to switch from nginx to traefik in a Kubernetes cluster. I am totally new to Traefik.
I have an app with Frontend and Backend:
demo.myapp.com/ # frontend
demo.myapp.com/backend # backend
With Nginx I did that following code, which worked like a charm:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host: demo.myapp.at
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-app
port:
number: 80
- path: /backend(/|$)(.*)
pathType: Prefix
backend:
service:
name: backend-api
port:
number: 80
Do I need two Ingresses for one domain, if I wanna route to a subfolder?
It seems with Traefik V1 and Traefik V2 (where V2 also needs a CRD for IngressRoute and/or Middleware manifest) more complex.
But I am totally lost with the examples in the docs as well with the mix of Version1 and Version2.
At the moment I use rancher/library-traefik:1.7.19 but I also can give V2 a try.
my V1 approach at the moment:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: demo-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: traefik
traefik.frontend.rule.type: PathPrefixStrip
spec:
rules:
- host: demo.myapp.com
http:
paths:
- path: /
pathType: Prefix
backend:
serviceName: frontend-app
servicePort: 80
- path: /backend # old nginx regex -> (/|$)(.*)
pathType: Prefix
backend:
serviceName: backend-api
servicePort: 80
Problem with that V1 example:
all paths below /backend are not rewritten correctly.
Instead of routing to /backend/someImage.png it routes to /someImage.png
If someone can help me with an example (optimal would be one for V1 and one for V2), would be great.
Thank you in advance
These examples are allegories from the Nginx questioned examples above
For V1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: demo-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: traefik
# traefik.ingress.kubernetes.io/redirect-permanent: "true"
traefik.ingress.kubernetes.io/redirect-regex: /backend$
traefik.ingress.kubernetes.io/redirect-replacement: /backend/
traefik.ingress.kubernetes.io/request-modifier: "ReplacePathRegex: ^/backend/(.*) /$1"
spec:
rules:
- host: demo.myapp.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
serviceName: frontend-app
servicePort: 80
- path: /backend # (/|$)(.*)
pathType: ImplementationSpecific
backend:
serviceName: backend-api
servicePort: 80
V2
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
annotations:
kubernetes.io/ingress.class: traefik
name: demo-ingress-route
namespace: default
spec:
entryPoints:
- web
routes:
- kind: Rule
match: Host(`demo.myapp.com`)
priority: 0
services:
- name: frontend-app
port: 80
- kind: Rule
match: Host(`demo.myapp.com`) && PathPrefix(`/backend/`)
middlewares:
- name: middleware-to-strip-backend-path
priority: 0
services:
- name: backend-api
port: 80
---
# this middleware will strip /backend from your request to align the requested url to the root / path of your API
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: middleware-to-strip-backend-path
namespace: default
spec:
stripPrefix:
prefixes:
- /backend

NGINX Ingress giving 503 Service Temporarily Unavailable. nginx/1.19.1 error in frontend

I am trying to install the Cyclos Mobile app on GCP Everything setup perfectly but when I am trying to access the setup on browser it always showing either default backend - 404 or 503 Service Temporarily Unavailable. nginx/1.19.1. I have tried everything as per stack overflow several previous questions but still same error.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencypt-staging
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"networking.k8s.io/v1beta1","kind":"Ingress","metadata":{"annotations":{"cert-manager.io/cluster-issuer":"letsencypt-staging","kubernetes.io/ingress.class":"nginx","nginx.ingress.kubernetes.io/proxy-connect-timeout":"3600"},"name":"cyclos-ingress-nginx-https","namespace":"cyclos-name-space"},"spec":{"backend":{"serviceName":"default-http-backend","servicePort":80},"rules":[{"host":"ip-address.xip.io","http":{"paths":[{"backend":{"serviceName":"cyclos-app-stateful","servicePort":80},"path":"/*"}]}}],"tls":[{"hosts":["ip-address.xip.io"],"secretName":"ip-address.xip.io-tls-secret"}]}}
kubernetes.io/ingress.class: nginx
creationTimestamp: "2020-09-29T07:00:01Z"
generation: 11
name: cyclos-ingress-nginx-https
namespace: cyclos-name-space
resourceVersion: "643221534"
selfLink: /apis/extensions/v1beta1/namespaces/cyclos-name-space/ingresses/cyclos-ingress-nginx-https
uid: uid
spec:
backend:
serviceName: default-http-backend
servicePort: 80
rules:
- host: ip-address.xip.io
http:
paths:
- backend:
serviceName: cyclos-app-stateful
servicePort: 80
path: /*
tls:
- hosts:
- ip-address.xip.io
secretName: ip-address.xip.io-tls-secret
status:
loadBalancer:
ingress:
- ip: IP
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencypt-staging
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"networking.k8s.io/v1beta1","kind":"Ingress","metadata":{"annotations":{"cert-manager.io/cluster-issuer":"letsencypt-staging","kubernetes.io/ingress.class":"nginx","nginx.ingress.kubernetes.io/proxy-connect-timeout":"3600"},"name":"cyclos-ingress-nginx-https","namespace":"cyclos-name-space"},"spec":{"backend":{"serviceName":"default-http-backend","servicePort":80},"rules":[{"host":"ip-address.xip.io","http":{"paths":[{"backend":{"serviceName":"cyclos-app-stateful","servicePort":80},"path":"/*"}]}}],"tls":[{"hosts":["ip-address.xip.io"],"secretName":"ip-address.xip.io-tls-secret"}]}}
kubernetes.io/ingress.class: nginx
creationTimestamp: "2020-09-29T07:00:01Z"
generation: 11
name: cyclos-ingress-nginx-https
namespace: cyclos-name-space
resourceVersion: "643221534"
selfLink: /apis/extensions/v1beta1/namespaces/cyclos-name-space/ingresses/cyclos-ingress-nginx-https
uid: uid
spec:
backend:
serviceName: default-http-backend
servicePort: 80
rules:
- host: ip-address.xip.io
http:
paths:
- backend:
serviceName: cyclos-app-stateful
servicePort: 80
path: /*
tls:
- hosts:
- ip-address.xip.io
secretName: ip-address.xip.io-tls-secret
status:
loadBalancer:
ingress:
- ip: IP

ingress multiple path mismatch

I have two service
serviceOld
serviceNew
I want to achieve the following effect
http://host/any => http://serviceOld/any
http://host/any/aaa => http://serviceOld/any/aaa
http://host/feature => http://serviceNew/feature
http://host/feature/bbb => http://serviceNew/feature/bbb
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: new
nginx.ingress.kubernetes.io/rewrite-target: /
name: v2
namespace: api
spec:
rules:
- host: xxx.com
http:
paths:
- path: /
backend:
serviceName: serviceOld
servicePort: 80
- path: /feature/*
backend:
serviceName: serviceNew
servicePort: 8080
I tried multiple methods and failed to achieve the goal. Can anyone help me?
All you need about rewrite annotation and path can be found in Ingress Rewrite Docs.
As per example on the site:
apiVersion: networking.k8s.io/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(/|$)(.*)
It will redirect:
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
In your case it should looks like:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: v2
namespace: api
spec:
rules:
- host: xxx.com
http:
paths:
- path: /any(/|$)(.*)
backend:
serviceName: serviceOld
servicePort: 80
- path: /feature(/|$)(.*)
backend:
serviceName: serviceNew
servicePort: 8080
I found that my version is relatively old. Under the old version, if the ports are different, it will not work properly. Change to the same port or upgrade the ingress version

Nginx ingress controller doesn't keep url over redirect

I am trying to setup a nginx ingress controller; here is the yaml of the ingress:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-rules
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
spec:
rules:
- host:
http:
paths:
- path: /discover-service
backend:
serviceName: discover-service
servicePort: discover-port
When I hit http://IP/discover-service it shows an HTML without CSS and JS. As I can see, they are looked under http://IP/eureka/css/file.css instead of http://IP/discover-service/css/file.css.
How can I preserve the original url in this case?
UPDATE #1
Now I can serve the static files by creating two ingresses like:
ingress-rules-discover-root.yaml
[..]
metadata:
name: ingress-rules-discover-root
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
[...]
spec:
rules:
- host:
http:
paths:
- path: /discover-service
backend:
serviceName: discover-service
servicePort: discover-port
and another one
[...]
metadata:
name: ingress-rules-discover-path
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
[...]
spec:
rules:
- host:
http:
paths:
- path: /eureka
backend:
serviceName: discover-service
servicePort: discover-port
I believe in this case you need to remove the annotation:
nginx.ingress.kubernetes.io/rewrite-target: /
This annotation makes the ingress rewrite http://IP/discover-service/css/file.css to http://IP/eureka/css/file.css

Resources