nginx-ingress works well for /, but not for subpaths - nginx

I have setup a name based ingress controller, but it doesn't seem to work for anything other than /.
So http://metabase.domain.com works but http://metabase.domain.com/style/app.css does not.
This is my config:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
namespace: domain
annotations:
kubernetes.io/ingress.global-static-ip-name: "domain"
name: domain-ingress
spec:
rules:
- host: metabase.domain.com
http:
paths:
- path: /
backend:
serviceName: metabase
servicePort: 80
- host: jenkins.domain.com
http:
paths:
- path: /
backend:
serviceName: jenkins
servicePort: 80
From the nginx.conf in the everything looks normal too. For some reason the nginx access and error logs are also empty so can't find anything from there too

As you mentioned, there is no error in the log files, and everything looks normal from
your perspective. I may suggest to tune up ingress using annotations tags.
I've checked documentation of ingress-nginx and found that below annotations may help a bit.
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.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
name: rewrite
namespace: default
spec:
rules:
- host: rewrite.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /something
If the Application Root is exposed in a different path and needs to be redirected, set the annotation
nginx.ingress.kubernetes.io/app-root
to redirect requests for /.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/app-root: /app1
name: approot
namespace: default
spec:
rules:
- host: approot.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /
If the application contains relative links, it is possible to add an additional annotation
nginx.ingress.kubernetes.io/add-base-url
that will prepend a base tag in the header of the returned HTML from the backend.

I got around to solving this, turns out somehow there was another ingress on my namespace that was a very old version of the nginx controller. I cleared my cluster and relaunched my ingress. Things worked out. Thanks for all the help everyone!

Related

nginx ingress: Cannot redirect to backend service

I have scoured the Net to try to resolve something that seems to be a common issue, but unfortunately all of the documentation and suggestions have not solve my problem. I hope that you can help me and others with it.
We are migrating from another ingress to nginx-ingress. To validate our installation, I am using httpbin as the backend service.
When I create the following ingress with a path of '/' and send the query, I receive a proper response.
curl -I -k http://abczzz.com/anything
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mikie-ingress
namespace: mikie
spec:
ingressClassName: nginx
rules:
- host: abczzz.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: httpbin-service
port:
number: 8999
What we really need is to be able to redirect to different services off of this single host, so I changed the ingress to the following, but the query always fails with a 404. Basically, I want the /httpbin to disappear and pass the path onto the backend service, httpbin.
curl -I -k http://abczzz.com/httpbin/anything
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mikie-ingress
namespace: mikie
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^(/httpbin)$ $1/ redirect;
spec:
ingressClassName: nginx
rules:
- host: abczzz.com
http:
paths:
- path: /httpbin(/|$)(.*)
pathType: Prefix
backend:
service:
name: httpbin-service
port:
number: 8999
I'd really appreciate your help to resolve what must be a simple routing issue.
Thanks for your time and interest.
I finally figured things out... Hopefully, the following snippet will help others...
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mikie-ingress
namespace: mikie
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
ingressClassName: nginx
rules:
- host: abczzz.com
http:
paths:
- backend:
service:
name: httpbin-service
port:
number: 8999
path: /httpbin/(.*)
pathType: Prefix

Stripprefix Middleware in NGINX Ingress controller

We have deployed Traefik 2.2 on our Kubernetes cluster with following ingress-route created to access our application. This configuration is working fine for us and is currently the same for our Production system as well.
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: application-xyz
spec:
tls: {}
entryPoints:
- web
- websecure
routes:
- match: "HostRegexp(`application-xyz.com`) && PathPrefix(`/`)"
kind: Rule
priority: 1
services:
- name: application-xyz-service
port: 80
- match: "PathPrefix(`/application-xyz/`)"
kind: Rule
services:
- name: application-xyz-service
port: 80
middlewares:
- name: application-xyz-stripprefix
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: application-xyz-stripprefix
namespace: frontend
spec:
stripPrefix:
prefixes:
- /application-xyz/
forceSlash: false
Question 1:
We are now planning to migrate from Traefik to Nginx Ingress Controller. Is there any way we can replicate the same on Nginx similar to Traefik configuration. I'm unsure if I'm comparing this in the right way or not. Would be grateful if we can get any pointers.
Question 2:
We wish to achieve stripprefix functionality in Nginx but didn't find any helpful documentation. Any leads in this regard is highly appreciated.
StripPrefix functionality in nginx ingress you can achieve using rewrite-target annotation.
When rewrite-target is used, regexp path matching is enabled and it allows you to match eny part of path into groups and rewrite path based on that.
In your case it would look like following:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
name: rewrite
namespace: default
spec:
rules:
- host: application-xyz.com
http:
paths:
- backend:
serviceName: application-xyz-service
servicePort: 80
path: /(.*)
- http:
paths:
- backend:
serviceName: application-xyz-service
servicePort: 80
path: /application-xyz/(.*)
Feel free to ask questions if you feel like my answer needs more detailed explaination.
#HelloWorld, thanks for the response. I have tried this config but didn't work as expected. Please check the code below which I tried.
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: application-xyz-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: cname.application-xyz.com
http:
paths:
- backend:
serviceName: application-xyz-service
servicePort: 80
path: /(.*)
- host: application-xyz.com
http:
paths:
- path: /cname-sample/(.*)
backend:
serviceName: application-xyz-service
servicePort: 80
With this config, cname.application-xyz.com is working fine but application-xyz/cname-sample/ isn't working which is the prime thing I'm looking to resolve. Please let me know your thoughts.
This issue is now fixed. We haven't deployed some of the application dependencies which put us in wrong direction. The pods were showing Running status for and the application was waiting for the dependencies to load and didn't receive any requests to serve. Thank you HelloWorld for suggesting the right approach.

Hosting two web apps with nginx ingress in Kubernetes

I have a kubernetes cluster running in Azure Kubernetes Service (AKS). I've been following a series of workshops and I've set up an NGINX ingress controller. Right now I'm using nip.io in order to access my site. They had me create an ingress resource to expose the front end:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ratings-web-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: frontend.<redacted ip>.nip.io
http:
paths:
- backend:
serviceName: ratings-web
servicePort: 80
path: /
This works fine. I can brows the nip.io address and everything works right.
I wanted to extend this and create a separate site. I want it at the same address, just served at /foo
I tried to create an ingress resource:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: foo-web-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: frontend.<redacted ip>.nip.io
http:
paths:
- backend:
serviceName: foo-web
servicePort: 80
path: /foo
When I browse frontend.<redacted ip>.nip.io/foo I get a 404 not found from nginx.
I tried added the following annotation based on another SO post:
nginx.ingress.kubernetes.io/rewrite-target: /
Now when I browse /foo it responds, but all the content is blank. In the web app it's referencing everything at the root level like:
<link href="/assets/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
When it sees this path, I think it's going to the original website so I get strict MIME type errors or 404 errors.
What do I need to do to host two websites on the same nginx ingress controller at different paths?
Ingress controller will be confused when merging these two ingresses, what the correct order should be because more than one ingress resource is defined for same host.
Referring from docs you could use a single ingress resource as fanout.
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: simple-fanout-example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: <redacted ip>.nip.io
http:
paths:
- path: /foo
backend:
serviceName: foo-web
servicePort: 80
- path: /bar
backend:
serviceName: bar-web
servicePort: 80

Kubernetes NGINX Ingress changes HTTP request from a POST to a GET

I'm using Kubernetes that is bundled with Docker-for-Mac. I'm trying to configure an Ingress that routes http requests starting with /v1/ to my backend service and /ui/ requests to my Angular app.
My issues seems to be that the HTTP method of the requests are changed by ingress (NGINX) from a POST to a GET.
I have tried various rewrite rules, but to no avail. I even switched from Docker-for-Mac to Minikube, but the result is the same.
If I use a simple ingress with no paths (just the default backend) then the service is getting the correct HTTP method.
The ingress below works:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
spec:
backend:
serviceName: backend
servicePort: 8080
But this ingress does not:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- http:
paths:
- path: /v1
backend:
serviceName: backend
servicePort: 8080
- path: /ui
backend:
serviceName: webui
servicePort: 80
When I debug the "backend" service I see that the HTTP Request is a GET instead of a POST.
I read somewhere that NGINX rewrites issue a 308 (permanent) redirect and the HTTP method is changed from a GET to a POST, but if that is the case how can I configure my ingress to support different paths for different services that require POST calls?
I found the solution to my problem. When I add host: to the configuration then the http method is not changed. Here is my current ingress yaml (the rewrite and regex are used to omit sending the /v1 as part of the backend URL)
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host: localhost
http:
paths:
- path: /v1(/|$)(.*)
backend:
serviceName: gateway
servicePort: 8080

nginx ingress sub path redirection

I have an ingress controller and ingress resource running with all /devops mapped to devopsservice in the backend. When I try to hit "http://hostname/devops" things work and I get a page (although without CSS and styles) with a set of hyperlinks for e.g one of them is "logs".
When I click on the "logs" hyperlink, it is redirecting me to http://hostname/logs whereas I need it to be http://hostname/devops/logs.
Any idea what I can do?
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
namespace: ingress-nginx
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/add-base-url : "true"
spec:
rules:
- host: master1.dev.local
http:
paths:
- backend:
serviceName: devops1
servicePort: 10311
path: /devops
Looks like your ingress is not serving anything /devops/*. Try adding another path /devops/* with the same backend. Basically this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
namespace: ingress-nginx
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/add-base-url : "true"
spec:
rules:
- host: master1.dev.local
http:
paths:
- backend:
serviceName: devops1
servicePort: 10311
path: /devops/*
- backend:
serviceName: devops1
servicePort: 10311
path: /devops
Update: the above has been deprecated in favor of something like this:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: rewrite
namespace: default
spec:
rules:
- host: master1.dev.local
http:
paths:
- backend:
serviceName: devops1
servicePort: 10311
path: /devops(/|$)(.*)
If you access http://hostname/devops/logs directly from your browser, certainly you will get what you want. But since you click the hyperlink in the homepage, then you can only get http://hostname/logs, which will be certainly failed.
So, you need /logs backend configured in your ingress yaml to get it processed, and configure nginx.ingress.kubernetes.io/configuration-snippet to ensure /logs not get rewrote, like this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
namespace: ingress-nginx
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/add-base-url : "true"
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^/logs /logs break;
spec:
rules:
- host: master1.dev.local
http:
paths:
- backend:
serviceName: devops1
servicePort: 10311
path: /logs
- backend:
serviceName: devops1
servicePort: 10311
path: /devops
I met the similar issue recently.
Assuming the "logs" hyperlink in your html uses a relative path, which means the hyperlink doesn't start with '/', then I think you can try to hit the page at http://hostname/devops/ instead of http://hostname/devops. (Note a / suffix in the first url.).
Then the "logs" hyperlink will be formed as http://hostname/devops/logs.
I think it's about how the browser identifies the 'base' url. With accessing 'http://hostname/devops/, if there is no 'base' tag in the html header, the 'base' url will be figured out to be http://hostname/devops; while with 'http://hostname/devops', the base url will be http://hostname.
If it's not the case, there is discussion at https://github.com/kubernetes/ingress-nginx/issues/4149. It's suggested a workaround to use the nginx directive subs_filter with a configuration-snippet to make the href attributes relative and also add the base tag in the html header.
The ingress used is as below,
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: rewrite
namespace: default
spec:
rules:
- host: master1.dev.local
http:
paths:
- backend:
serviceName: devops1
servicePort: 10311
path: /devops(/|$)(.*)
The nginx.ingress.kubernetes.io/x-forwarded-prefix annotation can be used for this purpose.
It adds x-forwarded-prefix header to http request with a value from this annotation. You can use it, if your backend support such header.
For example, Spring Boot application can handle it by using property:
server.forward-headers-strategy=framework
In your case ingress would look like the following:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
namespace: ingress-nginx
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/x-forwarded-prefix: /devops
spec:
rules:
- host: master1.dev.local
http:
paths:
- backend:
serviceName: devops1
servicePort: 10311
path: /devops
This solution has its downsides. It forces you to declare each service in separate ingress.

Resources