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
- Ensure your SQLite database file (
items.db
) is in the same directory asapp.py
. - 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.