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

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

Related

nginx ingress redirect traffic

I deployed nginx ingress controller and randomApp to minikube cluster.
I have 2 requirements:
All traffic for "random/.*" should go to the random service
Other paths should go to the nginx.
This configuration is correct?
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-rule-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
defaultBackend:
service:
name: ingress-nginx-controller
port:
number: 80
rules:
- host: random.localdev.me
http:
paths:
- path: /random/(.*)
backend:
service:
name: random
port:
number: 8000
pathType: Prefix
You also need to add metadata.annotations: kubernetes.io/ingress.class: "nginx" or spec.ingressClassName: nginx to allow nginx-ingress-controller to discover the ingress.
Also you shouldn't define default backend service as ingress-nginx-controller. Because you will get 503 Service Temporarily Unavailable since nginx-ingress-controller's nginx.conf didn't be configured for this. You can give another nginx server's service for it.

NGINX Ingress Routing based on Header

I have an nginx-ingress calling a custom auth-service before sending requests to the backend service, using this simple ConfigMap and Ingress:
apiVersion: v1
kind: ConfigMap
metadata:
...
data:
global-auth-url: auth-service-url:8080/authenticate
global-auth-method: GET
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
...
spec:
rules:
- host: host1
http:
paths:
- backend:
serviceName: backend-service
servicePort: 8080
Now I need something different.
How can I send requests, all with the same "Host" header, through different flows, one with auth-service and connected to backend-service1 and the other without any authentication and connecting to backend-service2?
To be clear, and using the custom header "Example-header: test"
If "Example-header" is "test", authenticate via my auth-service before sending to backend-service, as it's done now.
If "Example-header" is not defined, I want to send requests to a different backend service and do not use auth-service in the process.
I tried a couple of things, namely having 2 Ingresses, one with global-auth-url and the other with nginx.ingress.kubernetes.io/enable-global-auth: "false" but the auth-service is always called.
Can I do this with NGINX, or do I have to use Istio or Ambassador?
One way you can achieve this behavior is by abusing the canary feature.
For your backend-service, create a normal Ingress, e. g.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-backend
spec:
ingressClassName: nginx
rules:
- host: localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend-service
port:
number: 80
Create a second Ingress for you auth-service with enabled canary and set the header name and value, e. g.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-auth
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: Example-header
nginx.ingress.kubernetes.io/canary-by-header-value: test
spec:
ingressClassName: nginx
rules:
- host: localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: auth-service
port:
number: 80
Now, every request with Example-header: test routes to auth-service. Any other value, e. g. Example-header: some-value, will not route to auth-service but rather go to your backend-service.

Kubernetes Nginx Ingress pod subpath

I have a pod that exposes an HTTP service.
This pod has some HTTP endpoints which are available under /accounts.
My goal is to access this sub-path via accounts.example.com.
For example if the url accounts.example.com/test is requested, the nginx ingress should route the request to /accounts/test on my pod.
In the nginx ingress documentation I cannot find a use-case with examples like this.
You should use rewrite to accomplish your request.
https://kubernetes.github.io/ingress-nginx/examples/rewrite/
Here is an example:
Focus on this line: path: /something(/|$)(.*)
apiVersion: networking.k8s.io/v1
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(/|$)(.*)
Look on the different annotations for the re-write:

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

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

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!

Resources