Kubernetes nginx-ingress how to deal with routing in Express

7/17/2019

I have an Azure Kubernetes Cluster on which a couple of NodesJS Express Applications runs. I handle the incoming request by nginx-ingress

nginx-ingress

controller: https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml

service: https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/cloud-generic.yaml

ingress:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    #nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  rules:
  - http:
      paths:
      - path: /app1(/|$)(.*)
        backend:
          serviceName: app1-service
          servicePort: 80
      - path: /app2(/|$)(.*)
        backend:
          serviceName: app2-service
          servicePort: 80

example app1-service

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: app1
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: app1
    spec:
      nodeSelector:
        "beta.kubernetes.io/os": linux
      containers:
      - name: nodejs
        image: xxx.azurecr.io/app1:v1.0
        imagePullPolicy: Always
        ports:
        - containerPort: 80
          protocol: TCP
---
kind: Service
apiVersion: v1
metadata:
  name: app1-service
spec:
  selector:
    app: app1
  ports:
    - port: 80
      protocol: TCP
  type: NodePort

Like you can see all traffic on kubernetesurl.com/app1 gets forwarded to app1-service. And until there everything works.

example app1

Dockerfile: FROM node:8 WORKDIR /opt

COPY package.json /opt
RUN npm install

COPY . /opt

CMD ["npm", "start"]

server.js:

app.get('/', function(request, response) {
    response.sendFile(path.join(__dirname + '/login.html'));
});
app.post('/auth', function(request, response) {
    ... some auth stuff
    response.redirect('/home');
});
app.get('/home', function(request, response) {
    response.sendFile(path.join(__dirname + '/home.html'));
})

login.html:

<form action="auth" method="POST">
    <input type="text" name="username" placeholder="Username" required>
    <input type="password" name="password" placeholder="Password" required>
    <input type="submit">
</form>

Question

  1. If I submit my form, I get redirected to kubernetesurl.com/auth.

    But I need kubernetesurl.com/app1/auth.

  2. If I use a response.redirect('/home') inside '/', I get redirected to kubernetesurl.com/home.

    But I need kubernetesurl.com/app1/home.

  3. If I add a link with relative url to index.html like home, I get redirected to kubernetesurl.com/home.

    But I need kubernetesurl.com/app1/home.

When I start express as a service on my VM, everything works (of course, because the app runs on '/' without proxying).

How I get it running with proxying?

-- Nico Schuck
express
kubernetes
nginx
node.js

1 Answer

7/18/2019

Since you have two different locations, pointed to two different services, you can try grouping and rewriting the relative URL.

annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /app$2/$3
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /(location)(1)/(.*)
        backend:
          serviceName: service1
          servicePort: 80
      - path: /(location)(2)/(.*)
        backend:
          serviceName: service2
          servicePort: 80

So basically you're only using the first group (location1 and location2) to route to the correct service at Ingress level.

Then, this group can be dismissed by the rewrite rule which will only keep the second group for rewriting the correct application number and the third to wild-match everything else that you need to pass in your URL.

-- yyyyahir
Source: StackOverflow