Skip to main content

Enabling Multi-Tenancy in Kubernetes with NGINX

Multi-tenancy is a software architecture where a single instance of software serves multiple tenants (clients).

Each tenant's data is isolated and remains invisible to other tenants. In the context of your URLs, you are identifying which tenant (client) is making a request based on the URL, and then you query the corresponding tenant's database.

This script provides a basic foundation to build upon. You can expand it based on your application's requirements.

First, install Flask and SQLAlchemy if you haven't already:

pip install Flask SQLAlchemy

Database Setup

Assume you have a simple SQLite database for demonstration purposes.

CREATE TABLE items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
tenant VARCHAR(255),
name VARCHAR(255)
);

INSERT INTO items (tenant, name) VALUES ('tenant1', 'Item1 for tenant1');
INSERT INTO items (tenant, name) VALUES ('tenant2', 'Item1 for tenant2');
INSERT INTO items (tenant, name) VALUES ('tenant2', 'Item2 for tenant2');

Flask Script

Save the following script as app.py:

from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///items.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

class Item(db.Model):
id = db.Column(db.Integer, primary_key=True)
tenant = db.Column(db.String(255), nullable=False)
name = db.Column(db.String(255), nullable=False)

@app.route('/')
def index():
# Get the host header from the request
host = request.headers.get('Host', '')
# Extract the tenant name from the host header
tenant_name = host.split('.')[0]

# Query the database for items related to the tenant
items = Item.query.filter_by(tenant=tenant_name).all()
results = [{'id': item.id, 'tenant': item.tenant, 'name': item.name} for item in items]

return jsonify(results)

if __name__ == '__main__':
app.run(debug=True)

Running the App

  1. Ensure your SQLite database file (items.db) is in the same directory as app.py.
  2. Run the Flask application:
python app.py

Build the Docker Image

docker build -t yourusername/yourapp:latest .
docker login
docker push yourusername/yourapp:latest

Deploy the Docker Image to Kubernetes

Implementing multi-tenancy using Ingress in Kubernetes allows you to route traffic for multiple domains (DNS) to a single service, often through the use of annotations and path-based routing. Here’s a step-by-step guide to achieve this:

  • Ensure you have a running Kubernetes cluster. You can use Minikube, kind, or a cloud provider's Kubernetes service.
  • Install an Ingress Controller.

Create a Service and Deployment

Create a deployment and service for your application.

Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: my-app
app.kubernetes.io/instance: my-app
template:
metadata:
labels:
app.kubernetes.io/name: my-app
app.kubernetes.io/instance: my-app
spec:
containers:
- name: my-app
image: yourusername/yourapp:latest
ports:
- name: http
containerPort: 3000

Service

apiVersion: v1
kind: Service
metadata:
name: my-app-service
labels:
app.kubernetes.io/name: my-app
app.kubernetes.io/instance: my-app
spec:
type: ClusterIP
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: my-app
app.kubernetes.io/instance: my-app

Configure Ingress for Multi-Tenancy

Create an Ingress resource that routes multiple domains to the same service.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
labels:
app.kubernetes.io/name: my-app
app.kubernetes.io/instance: my-app
spec:
rules:
- host: "tenant1.example.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80
- host: "tenant2.example.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80
- host: "tenant3.example.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80

In this example, tenant1.example.com, tenant2.example.com, and tenant3.example.com are the domains being routed to the same my-app-service.

Apply the Configurations

Apply your Deployment, Service, and Ingress configurations:

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml

Conclusion

By setting up an Ingress resource with multiple host rules, you can efficiently route traffic for multiple domains to a single service in a Kubernetes cluster, achieving multi-tenancy.