Routing issues with nginx ingress controller and basic django app

4/29/2021

EDIT: I rewrote the question with a fully reproducible example.

I have a sample Django app with the base getting started https://docs.djangoproject.com/en/3.2/intro/tutorial01/, that is, there are two paths /admin and /polls.

If I deploy the app using NodePort, I can access both paths without issues. However, I haven't managed to do the same with Nginx ingress controller. I have tried several combinations of annotations and paths to no avail.

So, assume this yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: django
  name: django
spec:
  selector:
    matchLabels:
      app: django
  template:
    metadata:
      labels:
        app: django
    spec:
      containers:
      - image: "ay0o/django-ingress:latest"
        name: django
# ---
# apiVersion: v1
# kind: Service
# metadata:
#   name: django
# spec:
#   ports:
#   - nodePort: 31000
#     port: 8000
#     targetPort: 8000
#   selector:
#     app: django
#   type: NodePort
---
apiVersion: v1
kind: Service
metadata:
  name: django
spec:
  ports:
  - port: 8000
  selector:
    app: django
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: django
spec:
  rules:
  - http:
      paths:
      - path: /django
        pathType: Prefix
        backend:
          service:
            name: django
            port:
              number: 8000

when I use NodePort, http://localhost:31000/admin and http://localhost:31000/polls work fine.

when I use Ingress, http://localhost/django returns a 404 from django (because the path is neither admin nor polls), but http://localhost/django/admin and http://localhost/django/polls return a 404 from nginx, meaning the ingress is not properly routing.

so, what should I change so that http://localhost/django/admin and http://localhost/django/polls will not return 404?

-- The Illusive Man
django
kubernetes
kubernetes-ingress
nginx-ingress

2 Answers

11/17/2021

I think you shouldn't has both of them managing the routing path. You have to choose one of them. This is because Ingress was built to routing the traffic through cluster for microservices. If you want to really use it, you have to split your application on two separate services that accepts requests just at /. And let the routing with Ingress. Look at this page:

https://kubernetes.io/docs/concepts/services-networking/ingress/#simple-fanout

If you don't want to change your application or if it's just for testing purposes. The way it's deploy a Ingress with two rules:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: django
  namespace: default
spec:
  ingressClassName: nginx
  rules:
  - host: localhost
    http:
      paths:
      - path: /admin
        pathType: Prefix
        backend:
          service:
            name: django
            port: 
              number: 80
      - path: /polls
        pathType: Prefix
        backend:
          service:
            name: django
            port: 
              number: 80

This will accept the requests on both of the path's.

-- Lurian
Source: StackOverflow

4/30/2021

I have come to the conclusion that it's not possible to use path-based Ingress for a Django app, probably due to something related to Django's internals.

Every example out there uses host-based rules, and indeed, that just work. For example, the Ingress above can be changed to the following, and it will work.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: django
spec:
  rules:
  - host: localhost
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: django
            port:
              number: 8000

If anyone come up with a solution using path-based routing, feel free to answer the question.

-- The Illusive Man
Source: StackOverflow