Work in Progress: This page is under development. Use the feedback button on the bottom right to help us improve it.

Multi-tenancy

Deploy Laminar in a multi-tenant configuration with isolated environments.

Overview

Laminar supports multi-tenant deployments where each tenant has:

  • Isolated namespace - Dedicated Kubernetes namespace
  • Separate storage - Isolated RocksDB and object storage paths
  • Resource quotas - Configurable resource limits

Architecture

Shared Infrastructure
├── Ingress Controller (nginx/ALB)
├── Monitoring Stack (optional)
└── Cert Manager

Per-Tenant Namespace (tenant-{name})
├── API Server
├── Controller (with RocksDB)
├── Workers (dynamic)
└── ConfigMaps/Secrets

Namespace Per Tenant

Create Tenant Namespace

apiVersion: v1
kind: Namespace
metadata:
  name: tenant-acme
  labels:
    tenant: acme
    environment: production

Resource Quotas

apiVersion: v1
kind: ResourceQuota
metadata:
  name: tenant-quota
  namespace: tenant-acme
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi
    persistentvolumeclaims: "10"
    pods: "50"

Limit Ranges

apiVersion: v1
kind: LimitRange
metadata:
  name: tenant-limits
  namespace: tenant-acme
spec:
  limits:
    - default:
        cpu: 500m
        memory: 512Mi
      defaultRequest:
        cpu: 100m
        memory: 128Mi
      type: Container

Tenant Installation

Tenant Values File

Create tenant-acme-values.yaml:

nameOverride: acme
fullnameOverride: laminar-acme
 
api:
  replicas: 2
  resources:
    requests:
      cpu: 500m
      memory: 512Mi
    limits:
      cpu: 2000m
      memory: 2Gi
 
controller:
  replicas: 2
  persistence:
    size: 50Gi
 
# Storage paths - isolated per tenant
storage:
  artifacts:
    url: "s3://laminar-data/tenants/acme/artifacts"
  checkpoints:
    url: "s3://laminar-data/tenants/acme/checkpoints"
 
# Tenant-specific ingress
ingress:
  enabled: true
  hosts:
    - host: acme.laminar.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: acme-tls
      hosts:
        - acme.laminar.example.com

Install Tenant

helm install laminar-acme laminar/laminar \
  --namespace tenant-acme \
  --create-namespace \
  -f tenant-acme-values.yaml

Network Isolation

Network Policies

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: tenant-acme
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

RBAC Configuration

Tenant Service Account

apiVersion: v1
kind: ServiceAccount
metadata:
  name: laminar-acme
  namespace: tenant-acme
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: laminar-acme
  namespace: tenant-acme
rules:
  - apiGroups: [""]
    resources: ["pods", "services", "configmaps", "secrets"]
    verbs: ["get", "list", "watch", "create", "update", "delete"]
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "watch", "create", "update", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: laminar-acme
  namespace: tenant-acme
subjects:
  - kind: ServiceAccount
    name: laminar-acme
    namespace: tenant-acme
roleRef:
  kind: Role
  name: laminar-acme
  apiGroup: rbac.authorization.k8s.io

Shared vs Dedicated Components

ComponentSharedDedicatedRecommendation
Ingress ControllerYesOptionalShared with tenant-specific rules
RocksDB StorageNoYesAlways dedicated per tenant
Object StorageYesYesIsolated paths per tenant
MonitoringYesOptionalShared with tenant labels
Cert ManagerYesNoShared cluster-wide

Managing Multiple Tenants

With ArgoCD

Create an app-of-apps for tenants:

# tenants-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: laminar-tenants
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/your-org/laminar-config.git
    targetRevision: main
    path: tenants
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd

Tenant directory structure:

tenants/
├── acme/
│   ├── namespace.yaml
│   ├── values.yaml
│   └── application.yaml
├── beta/
│   ├── namespace.yaml
│   ├── values.yaml
│   └── application.yaml
└── gamma/
    ├── namespace.yaml
    ├── values.yaml
    └── application.yaml

With Helm

# Install multiple tenants
for tenant in acme beta gamma; do
  helm install laminar-$tenant laminar/laminar \
    --namespace tenant-$tenant \
    --create-namespace \
    -f tenants/$tenant/values.yaml
done

Tenant Onboarding Checklist

  1. Create namespace with appropriate labels
  2. Apply resource quotas and limit ranges
  3. Configure network policies
  4. Create service account and RBAC
  5. Provision storage paths (S3, GCS, etc.)
  6. Configure ingress with TLS
  7. Install Laminar with tenant values
  8. Verify installation and test connectivity

Tenant Removal

# Uninstall Helm release
helm uninstall laminar-acme -n tenant-acme
 
# Delete namespace (removes all resources)
kubectl delete namespace tenant-acme
 
# Clean up external storage
aws s3 rm s3://laminar-data/tenants/acme/ --recursive

Next Steps