Setup nginx-ingress to match two paths to the same serviceName and servicePort

10/22/2019

What I'm trying to do

  • Traffic to / needs to go to the FE client running on 3000.
  • Traffic to /api needs to go to the BE server.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-service
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/add-base-url: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
    - http:
        paths:
          - path: /?(.*)
            backend:
              serviceName: client-cluster-ip-service
              servicePort: 3000
          - path: /api?/(.*)
            backend:
              serviceName: server-cluster-ip-service
              servicePort: 5000

The problem

# urls.py
urlpatterns = [
    path('auth/', include('authentication.urls')),
    path('admin/', admin.site.urls),
]
  • Fetches to /api/auth work fine.
  • Fetches to /api/admin do not. Django removes the /api from the URL making it just /admin which doesn't exist. This seems to be the default behavior of Django. As far as I can tell there is no way to override it.

What does work

- path: /?(.*)
  backend:
    serviceName: server-cluster-ip-service
    servicePort: 5000
  • Navigating to /admin works fine.
  • However, this removes the ability for traffic to be routed to the client.

Somehow, I need to prevent Django from stripping off the prefix. Or maybe there is a way to handle this type of routing from nginx-ingress.

What doesn't work

Any variation of the following:

- http:
    paths:
      - path: /?(.*)
        backend:
          serviceName: client-cluster-ip-service
          servicePort: 3000
      - path: /api?/(.*)
        backend:
          serviceName: server-cluster-ip-service
          servicePort: 5000
      - path: /admin?/(.*)
        backend:
          serviceName: server-cluster-ip-service
          servicePort: 5000

urlpatterns = [
    path('auth/', include('authentication.urls')),
    path('/', admin.site.urls),
]

urlpatterns = [
    path('auth/', include('authentication.urls')),
    path('', admin.site.urls),
]

urlpatterns = [
    path('auth/', include('authentication.urls')),
    path('api/admin/', admin.site.urls), # this justmakes it /api/api/admin given the ingress
]

# This just makes the URL pattern:
# - /api/api/auth/
# - /api/api/admin/
urlpatterns = [
    path('api/', include([
        path('auth/', include('authentication.urls'), name='auth'),
        path('admin/', admin.site.urls),
    ])),
]

Question

So not quite sure how to resolve this.

  • Is there a way to resolve this via nginx-ingress? Somehow strip off the /api after the request is submitted?
  • Is there a way to prevent the default behavior of Django that strips /api off of /api/admin?
-- eox.dev
django
docker
kubernetes
nginx-ingress

1 Answer

11/4/2019

Added the following to the Django settings.py:

 FORCE_SCRIPT_NAME = '/api/'

Update the STATIC_URL because it will no longer serve the assets for the admin portal:

 STATIC_URL = '/api/static/`
-- eox.dev
Source: StackOverflow