Reverse proxy not routing to APIs using nginx and kubernetes

4/10/2019

I am trying to get a reverse proxy working on kubernetes using nginx and a .net core API.

When I request http://localhost:9000/api/message I want something like the following to happen:

[Request] --> [nginx](localhost:9000) --> [.net API](internal port 9001)

but what appears to be happening is:

[Request] --> [nginx](localhost:9000)!
Fails because /usr/share/nginx/api/message is not found.

Obviously nginx is failing to route the request to the upstream servers. This works correctly when I run the same config under docker-compose but is failing here in kubernetes (local in docker)

I am using the following configmap for nginx:

error_log /dev/stdout info;
events {
  worker_connections 2048;
}
http {
  access_log /dev/stdout;
  upstream web_tier {
    server webapi:9001;
  }
  server {
    listen 80;
    access_log /dev/stdout;
    location / {
      proxy_pass http://web_tier;
      proxy_redirect     off;
      proxy_set_header   Host $host;
      proxy_set_header   X-Real-IP $remote_addr;
      proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header   X-Forwarded-Host $server_name;
    }
    location /nginx_status {
      stub_status on;
      access_log   off;
      allow all;
    }
  }
}

The load-balancer yaml is:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: load-balancer
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: load-balancer
    spec:
      containers:
      - args:
        - nginx
        - -g
        - daemon off;
        env:
        - name: NGINX_HOST
          value: example.com
        - name: NGINX_PORT
          value: "80"
        image: nginx:1.15.9
        name: iac-load-balancer
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /var/lib/nginx
          readOnly: true
          name: vol-config
        - mountPath: /tmp/share/nginx/html
          readOnly: true
          name: vol-html
      volumes:
      - name: vol-config
        configMap:
          name: load-balancer-configmap
          items:
            - key: nginx.conf
              path: nginx.conf
      - name: vol-html
        configMap:
          name: load-balancer-configmap
          items:
            - key: index.html
              path: index.html
status: {}
---
apiVersion: v1
kind: Service
metadata:
  name: load-balancer
spec:
type: LoadBalancer
ports:
- name: http
    port: 9000
    targetPort: 80
selector:
    app: load-balancer
status:
loadBalancer: {}

Finally the error messages are:

2019/04/10 18:47:26 [error] 7#7: *1 open() "/usr/share/nginx/html/api/message" failed (2: No such file or directory), client: 192.168.65.3, server: localhost, request: "GET /api/message HTTP/1.1", host: "localhost:9000",
192.168.65.3 - - [10/Apr/2019:18:47:26 +0000] "GET /api/message HTTP/1.1" 404 555 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36" "-",

It seems like nginx is either not reading the config correctly for some reason, or it is failing to communicating with the webapi servers and is defaulting back to trying to serve static local content (nothing in the log indicates a comms issue though).

Edit 1: I should have included that /nginx_status is also not routing correctly and fails with the same "/usr/share/nginx/html/nginx_status" not found error.

-- SecretDeveloper
kubernetes
nginx

2 Answers

4/10/2019

Can you share how you created the configmap? Verify that the configmap has a data entry named nginx.conf. It might be related to the readOnly flag maybe you can also try to remove it or change the path to /etc/nginx/ as stated in docker image documentation.

-- tomaaron
Source: StackOverflow

4/12/2019

Here what i understood is you are requesting a Api, which is giving 404.

http://localhost:9000/api/message

I have solved this issue by creating backend service as nodeport, and i am trying to access the api from my Angular App.

Here is my configure.conf file which get replaced by original nginx configuration file

server {
listen 80;
server_name  localhost;    

location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
  }
}
server {
listen 5555;

location / {
    proxy_pass http://login:5555;
  }
}
server {
listen 5554;

location / {
    proxy_pass http://dashboard:5554;
  }
}

here i have route my external traffic coming on port 5554/5555 to the service [selector-Name]

here login and dashboards are my services having Type as NodePort

Here is my Docker file

from nginx:1.11-alpine
copy configure.conf /etc/nginx/conf.d/default.conf
copy dockerpoc /usr/share/nginx/html
expose 80
expose 5555
expose 5554
cmd ["nginx","-g","daemon off;"]

Here i kept my frontend service's Type as LoadBalancer which will expose a public endpoint and,

I am calling my backend Api from frontend as :

http://loadbalancer-endpoint:5555/login

Hope this will help you.

-- Abhishek Chudekar
Source: StackOverflow