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