My goal is the following: I have two Flask apps in two separate Docker containers and I want to access them via different paths on the same IP address, like this: 127.0.0.1/app1, 127.0.0.1/app2 (but with a real IP address).
I want to do this with Kubernetes.
I have a Kubernetes cluster running (Azure Kubernetes Service), with a Deployment and Service for each of the two Docker containers. The pod for each app is running fine. I also installed an ingress controller (Nginx) in my cluster and now I am trying to make it work with a single Ingress resource.
If I do it as follows, it works perfectly for 1 single app (either one of them works on IP-address/):
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-name
namespace: my-namespace
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: service1 (or service2)
servicePort: 5000
But when I try the following it doesn't work:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-name
namespace: my-namespace
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /app1
backend:
serviceName: service1
servicePort: 5000
- path: /app2
backend:
serviceName: service2
servicePort: 5000
I am able to see the html page that gets rendered by the Flask app, for both applications on their respective paths, but none of the functionalities work.
Other than the fact that the paths don't always seem to work (I sometimes get redirected to IP-address/ when I try to connect to IP-address/app1 or IP-address/app1/), the problem is the following (I think):
Each of the Flask applications have a "/predict" route, that only accepts POST requests, where the respective calls for the apps are made (Each application is an AI application that makes a prediction for a given input).
The calls for both apps are made to IP-address/predict, instead of IP-address/app1/predict or IP-address/app2/predict. Also the static files cannot be accessed because of this path problem.
I don't know if this is the right way to do it? I tried playing around with the 'rewrite-target' as well, but haven't figured out a solution.
I hope someone can explain me what I'm doing wrong.
Check your rewrite annotation in the ingress resource. Any request that you make will be rewritten to /
. This means that if you call IP:80/app1 your container will receive IP:80/
nginx.ingress.kubernetes.io/rewrite-target: /
If you don't want that to happen, then remove that rewrite annotation. Your ingress would end up like this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-name
namespace: my-namespace
spec:
rules:
- http:
paths:
- path: /app1
backend:
serviceName: service1
servicePort: 5000
- path: /app2
backend:
serviceName: service2
servicePort: 5000
Your containers will receive the full path based on /app1 and /app2.
UPDATE Check this example. I have two backends that listen on /
and respond an html with a number that you configure via an environment variable.
---
apiVersion: v1
kind: Service
metadata:
name: backend1
namespace: default
labels:
mojix.service: backend1
spec:
ports:
- name: "8000"
port: 8000
targetPort: 8000
selector:
mojix.service: backend1
status:
loadBalancer: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: default
labels:
mojix.service: backend1
name: backend1
spec:
replicas: 1
selector:
matchLabels:
mojix.service: backend1
template:
metadata:
creationTimestamp: null
labels:
mojix.service: backend1
spec:
containers:
- name: backend1
image: lozuwa/number_backend:latest
env:
- name: BACKEND_NUMBER
value: "1"
hostname: backend1
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: backend2
namespace: default
labels:
mojix.service: backend2
spec:
ports:
- name: "8000"
port: 8000
targetPort: 8000
selector:
mojix.service: backend2
status:
loadBalancer: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: default
labels:
mojix.service: backend2
name: backend2
spec:
replicas: 1
selector:
matchLabels:
mojix.service: backend2
template:
metadata:
creationTimestamp: null
labels:
mojix.service: backend2
spec:
containers:
- name: backend2
image: lozuwa/number_backend:latest
env:
- name: BACKEND_NUMBER
value: "2"
hostname: backend2
restartPolicy: Always
I have the following ingress.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: vizix-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /app1
backend:
serviceName: backend1
servicePort: 8000
- path: /app2
backend:
serviceName: backend2
servicePort: 8000
If you hit IP/app1
you get Response from 1
and if you hit IP/app2
you get Response from 2
. My containers listen on /
that is why I need the rewrite. What path does your application expect?
You may consider to supply capture groups entirely within Ingress manifest and specify particular regular expression that will define the source Nginx rewrite rule.
I would expect to get it working as desired, after some adjustments in the genuine Ingress
manifest:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-name
namespace: my-namespace
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- http:
paths:
- path: /app1(/|$)(.*)
backend:
serviceName: service1
servicePort: 5000
- path: /app2(/|$)(.*)
backend:
serviceName: service2
servicePort: 5000
Probably, you would also need to add Trailing slash in the target URL, instructing Nginx engine to properly serve some static content.