Search code examples
djangokuberneteskubernetes-ingressnginx-ingress

Routing issues with nginx ingress controller and basic django app


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?


Solution

  • 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.