Cloud
Blog
Cloud13 min

Architecture SaaS multi-tenant sur Kubernetes : par où commencer

Matthieu Robin15 septembre 2022

Vous avez construit un produit SaaS. Maintenant vous devez gérer 50 clients différents sur la même infrastructure sans qu'ils puissent voir les données des autres.

Votre équipe d'engineering a trois options :

  • Une instance d'application par client (cher, ne scale pas)
  • Une base de données par client (cauchemar opérationnel)
  • Une vrai multi-tenancy (complexe, mais puissant)

La plupart des SaaS qui scale finissent par adopter la multi-tenancy authentique : une application qui sert plusieurs clients avec isolation complète à chaque couche. Bien implémentée, elle réduit les coûts opérationnels de 70-80%. Mal implémentée, elle devient un cauchemar de sécurité.

Kubernetes rend la multi-tenancy plus facile que jamais. Mais "plus facile" ne veut pas dire "simple". Vous avez besoin de patterns clairs pour isolation, gestion des tenants, séparation des données, et sécurité. Cet article explique comment architecturer une SaaS multi-tenant sur Kubernetes et Hikube.

Pourquoi multi-tenancy sur Kubernetes ?

Avant de plonger dans l'architecture, clarifions pourquoi Kubernetes est la bonne plateforme pour une SaaS multi-tenant.

Avantages Kubernetes :

  • Isolation par namespaces : Un namespace Kubernetes par tenant (ou par tier de client) fournit séparation logique
  • Scaling horizontal : Ajouter plus de replicas instantanément quand la charge d'un client augmente
  • Resource quotas : Imposer des limites de mémoire/CPU par tenant, empêcher un client de noyer les autres
  • Multi-région : Déployer la même application dans plusieurs régions avec la même architecture
  • Coût efficace : Un cluster sert 100 clients au lieu de 100 déploiements séparés

Avantages Hikube pour SaaS :

  • Control plane managé : Vous ne gérez pas l'infrastructure Kubernetes
  • Infrastructure basée en Suisse : Respecter les exigences de résidence des données pour clients européens
  • Support multi-tenancy intégré : Isolation par namespaces, RBAC, network policies
  • Auto-scaling : Les clients peuvent faire des pics sans capacity planning
  • Ready pour compliance : Audit logging, encryption de données, security scanning inclus

Décision d'architecture : cluster partagé vs. clusters séparés

Votre première décision : cluster partagé ou clusters séparés par tier de client.

Modèle Cluster Partagé (Le Plus Commun)

Tous les clients tournent sur le même cluster Kubernetes. Chacun a un namespace dédié.

Avantages :

  • Complexité opérationnelle minimale
  • Meilleure efficacité de coûts (un seul cluster overhead)
  • Meilleur utilisation des ressources (capacité inutilisée partagée entre tenants)
  • Disaster recovery plus simple (un seul cluster à backuper)

Désavantages :

  • Doit implémenter isolation stricte (bug isolation = fuite de données)
  • L'application mal configurée d'un tenant peut impacter les autres (noisy neighbor problem)
  • Decisions de scaling affectent tous les tenants

Quand utiliser : La plupart des SaaS (surtout au stage initial). Coût et simplicité gagnent généralement.

Cluster Séparé Par Tier

Les clients premium ont des clusters dédiés. Les clients standard partagent un cluster.

Avantages :

  • Clients premium ne souffrent pas du noisy neighbor problem
  • Peut isoler workloads sensibles compliance
  • Meilleures garanties de performance pour clients high-value
  • Deploiement multi-région plus facile par tier

Désavantages :

  • Complexité opérationnelle augmente (gérer 3-5 clusters au lieu de 1)
  • Coûts augmentent (chaque cluster a overhead)
  • Upgrades et maintenance sont plus complexes

Quand utiliser : Produits SaaS matures avec structure de tiers claire (clients $100K+ ARR justifient des clusters dédiés).

Isolation par Namespace : La Fondation

Les namespaces Kubernetes fournissent isolation logique. Ce ne sont pas des limites de sécurité par eux-mêmes, vous devez ajouter des couches.

Structure Namespace Basique

production
├── tenant-acme-corp
├── tenant-globex
├── tenant-initech
└── shared-services (monitoring, logging)

staging
├── tenant-acme-corp
├── tenant-globex
└── ...

Chaque tenant reçoit :

  • Un namespace dédié en production
  • Un namespace dédié en staging
  • Deployments isolés, services, secrets, et persistent volumes

RBAC pour Isolation des Tenants

Role-Based Access Control (RBAC) empêche le service account d'un tenant d'accéder aux ressources d'un autre tenant.

Exemple règle RBAC pour tenant-acme-corp :

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: tenant-acme-corp
  name: tenant-acme-reader
rules:
- apiGroups: [""]
  resources: ["pods", "services", "configmaps", "secrets"]
  verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: tenant-acme-corp
  name: tenant-acme-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: tenant-acme-reader
subjects:
- kind: ServiceAccount
  name: tenant-acme-app
  namespace: tenant-acme-corp

Cela assure que le service account tenant-acme-app ne peut accéder qu'aux ressources dans son propre namespace.

Network Policies : Bloquer Traffic Cross-Tenant

Les Kubernetes Network Policies sont des firewalls entre namespaces.

Exemple : Bloquer tout ingress excepté dans le namespace

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  namespace: tenant-acme-corp
  name: deny-cross-namespace
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector: {}
      namespaceSelector:
        matchLabels:
          name: tenant-acme-corp

Cela empêche les pods d'autres namespaces de joindre les pods du tenant-acme-corp.

Vous devez aussi explicitement autoriser traffic ingress depuis votre ingress controller. La plupart des équipes utilisent un ingress controller partagé qui route le traffic selon hostname ou path.

Stratégies Tenant Data

Où vivent les données des tenants ? Votre stratégie de database décide de tout.

Stratégie 1 : Base de Données Partagée, Schemas Séparés

Tous les tenants utilisent la même base (ex. PostgreSQL), mais chaque tenant a son propre schema.

Exemple :

postgres
├── schema: acme_corp (toutes les tables acme_corp)
├── schema: globex (toutes les tables globex)
├── schema: initech (toutes les tables initech)
└── schema: shared (données de référence)

Avantages :

  • Opérationnellement simple : Une seule base à gérer
  • Facile de scaler compute séparément des données
  • Isolation des données imposée par la database
  • Row-level security (RLS) ajoute isolation additionnelle au niveau application

Désavantages :

  • Une panne database affecte tous les tenants
  • Cher pour clients très gros
  • Difficile de scaler un tenant individuel (tous les tenants partagent compute database)
  • Backup/restore est all-or-nothing

Quand utiliser : La plupart des SaaS au stage early-to-mid.

Stratégie 2 : Base Partagée, Filtering Par Ligne

Tous les tenants dans un schema. L'application filtre les lignes par tenant ID.

SELECT * FROM orders WHERE tenant_id = 'acme-corp'

Avantages :

  • Complexité opérationnelle minimale
  • Facile à debug (toutes les données dans un schema)
  • Meilleure efficacité de coûts
  • Queries efficaces (query planner de la base voit toutes les données)

Désavantages :

  • Risque de sécurité énorme si le filtering bugue (un bug = fuite data entre tous les clients)
  • Exige code application discipliné (chaque query doit filtrer par tenant)
  • Difficile d'implémenter row-level security (RLS) consistent
  • Migrations de données complexes

Quand utiliser : Seulement si votre équipe engineering est très disciplinée et security-conscious. Non recommandé pour la plupart des équipes.

Stratégie 3 : Base de Données Séparée Par Tenant

Chaque client reçoit sa propre instance de base de données.

Avantages :

  • Isolation de données ultime (séparation au niveau base)
  • Scale clients individuels indépendamment
  • Facile compliance (data client est littéralement séparé)
  • Simple disaster recovery (backuper une base par client)

Désavantages :

  • Cauchemar opérationnel : Gérer 1,000 bases pour 1,000 clients
  • Multiplicateur de coûts : Chaque base a overhead (mémoire, storage, backups)
  • Migrations de schema exigent coordonner sur toutes les bases
  • Complexe de scaler : Ajouter une base par nouveau client est inefficace

Quand utiliser : Seulement pour clients high-value (instances dédiées) ou workloads compliance-sensitive. Jamais pour tous les clients.

Approche Hybride Recommandée

Utilisez Stratégie 1 (schemas séparés dans base partagée) pour la plupart des clients. Utilisez Stratégie 3 (bases séparées) pour votre top 5-10 clients highest-value.

Cela vous donne :

  • Efficacité de coûts pour la plupart des clients (base partagée)
  • Expérience premium pour clients high-value (base dédiée)
  • Chemin clair d'upgrade (customer success peut migrer clients vers base dédiée)

Pattern Gestion des Tenants : Le Tenant Controller

Les systèmes multi-tenant production ajoutent habituellement un "tenant controller", un processus automatisé qui gère le lifecycle des tenants.

Le tenant controller gère :

  • Créer un namespace Kubernetes quand un client s'inscrit
  • Provisionner schema database pour le client
  • Créer service accounts et règles RBAC
  • Configurer network policies
  • Définir resource quotas
  • Générer certificats TLS pour le domaine custom du tenant
  • Updater DNS quand le client ajoute un domaine custom

Exemple workflow :

Client S'Inscrit
    ↓
POST /api/tenants (internal API)
    ↓
Tenant Controller Reçoit Event
    ↓
Créer Namespace (tenant-acme-corp)
Créer ServiceAccount (tenant-acme-app)
Créer RBAC Role + RoleBinding
Créer NetworkPolicy
Créer ResourceQuota (CPU, Memory limits)
Provisionner Schema Database
Créer Secret avec connection string DB
Créer Ingress Rule pour domaine custom
    ↓
Tenant Ready

La plupart des équipes implémentent ceci comme un Kubernetes Operator (utilisant frameworks comme kubebuilder). Cependant, une approche plus simple (webhook + script automation) marche bien pour les plus petites SaaS.

Resource Quotas : Prévenir le Noisy Neighbor Problem

Sans quotas, l'application runaway d'un tenant peut consommer toutes les ressources du cluster, causant les applications d'autres tenants de fail.

Exemple ResourceQuota pour un tenant standard :

apiVersion: v1
kind: ResourceQuota
metadata:
  namespace: tenant-acme-corp
  name: tenant-quota
spec:
  hard:
    requests.cpu: "10"
    requests.memory: "20Gi"
    limits.cpu: "20"
    limits.memory: "40Gi"
    pods: "100"
    services.loadbalancers: "2"
    persistentvolumeclaims: "10"
  scopeSelector:
    matchExpressions:
    - operator: In
      scopeName: PriorityClass
      values: ["default"]

Cela empêche un tenant de requester plus que 10 CPU cores ou 20GB RAM en opération normal. Burst est permis jusqu'à 20 cores/40GB via limits.

Stratégie resource quota par tier :

  • Tier Starter : 2 cores / 4GB memory
  • Tier Standard : 5 cores / 10GB memory
  • Tier Premium : 20 cores / 50GB memory (ou cluster dédié)

Liez ces limites à votre modèle de pricing. Si un client a besoin de plus de ressources, il upgrade son plan.

Scaling Horizontal pour Workloads Multi-Tenant

Kubernetes horizontal pod autoscaling (HPA) marche bien pour systèmes multi-tenant, mais exige configuration soignée.

Challenge : Si vous avez 100 tenants et un tenant expérimente un spike, l'HPA scalera up replicas. Mais maintenant vous tournez extra capacity pour ce seul tenant tandis que les autres tenants sont idle.

Solution: Scaling tenant-aware

Certaines équipes utilisent custom metrics pour scaler selon charge per-tenant :

apiVersion: autoscaling.k8s.io/v2
kind: HorizontalPodAutoscaler
metadata:
  namespace: tenant-acme-corp
  name: app-autoscaler
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: tenant-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Pods
    pods:
      metric:
        name: http_requests_per_second
      target:
        type: AverageValue
        averageValue: "1k"

Cela scale le deployment du tenant quand ils dépassent 1,000 requests par seconde.

Pour systèmes vraiment multi-tenant : Considérez tourner un shared application pool avec multiples tenants par pod, utilisant application-level routing pour distribuer requests. Cela maximise resource utilization et minimise overhead.

Ingress Routing : Acheminer Traffic au Bon Tenant

Avec multiples tenants, vous avez besoin d'un Ingress controller qui route traffic par hostname ou path.

Pattern 1 : Hostname-based routing (Le Plus Commun)

Chaque tenant a un subdomain ou domaine custom :

  • acme-corp.app.example.com → routes vers tenant-acme-corp namespace
  • globex.example.com → routes vers tenant-globex namespace
  • customer.example.com (custom domain) → routes vers namespace approprié

Configuration Ingress :

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: tenant-acme-corp
  name: tenant-acme-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: acme-corp.app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-service
            port:
              number: 80
  - host: custom.acmecorp.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-service
            port:
              number: 80

Pattern 2 : Path-based routing

Tous les tenants derrière un domaine, séparés par path :

  • app.example.com/acme-corp/ → tenant-acme-corp
  • app.example.com/globex/ → tenant-globex

C'est plus simple mais exige changements d'application pour gérer prefixes de path.

Considérations Sécurité

Les systèmes multi-tenant sont des cibles attractives pour attackers. Les breaches sont chers. Ajoutez ces couches de sécurité :

1. Network Policies (Déjà Couverte)

Bloquer cross-namespace traffic par défaut.

2. Pod Security Policies / Pod Security Standards

Prévenir tenants de tourner containers privileged qui pourraient échapper isolation.

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: restricted
spec:
  privileged: false
  allowPrivilegeEscalation: false
  requiredDropCapabilities:
    - ALL
  volumes:
    - 'configMap'
    - 'emptyDir'
    - 'projected'
    - 'secret'
    - 'downwardAPI'
    - 'persistentVolumeClaim'
  hostNetwork: false
  hostIPC: false
  hostPID: false
  runAsUser:
    rule: 'MustRunAsNonRoot'
  seLinux:
    rule: 'MustRunAs'

3. Secret Management

Ne jamais stocker credentials database dans ConfigMaps. Utilisez Kubernetes Secrets ou external secret managers (HashiCorp Vault, AWS Secrets Manager).

apiVersion: v1
kind: Secret
metadata:
  namespace: tenant-acme-corp
  name: db-credentials
type: Opaque
stringData:
  connection-string: "postgresql://user:password@db.internal:5432/acme_corp"

Référencez-le dans votre application :

env:
- name: DATABASE_URL
  valueFrom:
    secretKeyRef:
      name: db-credentials
      key: connection-string

4. Audit Logging

Loguer tout accès aux ressources sensibles. Kubernetes audit logging est intégré.

5. Security Scanning Régulier

Utilisez container image scanning (Trivy, Snyk) pour détecter vulnerabilities dans vos images d'application avant qu'elles n'atteignent production.

Monitoring et Observabilité pour Systèmes Multi-Tenant

Avec multiples tenants, vous devez tracker métriques par-tenant pour comprendre coûts et performance.

Métriques clés à tracker :

  • CPU/memory usage par tenant
  • Request count par tenant
  • Database query count par tenant
  • Storage usage par tenant
  • Error rate par tenant
  • API latency (p50, p95, p99) par tenant

Exemple requête Prometheus (CPU usage per-tenant) :

sum(rate(container_cpu_usage_seconds_total{namespace=~"tenant-.*"}[5m])) by (namespace)

Cela vous donne breakdown de CPU usage par tenant namespace.

La plupart des équipes utilisent Prometheus + Grafana pour métriques, et optionnellement ajoutent observabilité application-level (Datadog, New Relic) pour insights plus profonds.

Deploiement Multi-Région

Au fur et à mesure que votre SaaS grandit, vous aurez besoin de multiples régions pour latency et disaster recovery.

Pattern multi-région pour multi-tenant :

Region: US-East
├── Kubernetes Cluster (Hikube)
│   ├── Namespace: tenant-acme-corp (primary)
│   ├── Namespace: tenant-globex
│   └── Database: Primary (PostgreSQL)

Region: EU-West
├── Kubernetes Cluster (Hikube)
│   ├── Namespace: tenant-acme-corp (replica)
│   ├── Namespace: tenant-globex (replica)
│   └── Database: Replica (Read-only)

Region: APAC
├── Kubernetes Cluster (Hikube)
│   └── [Same pattern]

Routez traffic selon géographie (utilisant DNS geolocation ou un global load balancer). Cela assure :

  • Low latency : Clients connectent la région la plus proche
  • Data residency : Les données du client restent dans leur région (compliance)
  • Disaster recovery : Si une région échoue, le traffic se déplace aux autres

Patterns de Deployment sur Hikube

Pattern 1 : GitOps avec Flux

Utilisez Flux pour automatiquement deployer changements à Hikube au fur et à mesure que vous commitez à Git.

apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
  namespace: flux-system
  name: multi-tenant-repo
spec:
  interval: 1m
  url: https://github.com/your-company/saas-infra
  ref:
    branch: main

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  namespace: flux-system
  name: multi-tenant-app
spec:
  interval: 10m
  sourceRef:
    kind: GitRepository
    name: multi-tenant-repo
  path: ./deployments/multi-tenant
  prune: true
  wait: true

Bénéfices : Infrastructure déclarative, audit facile, rollbacks automatisés.

Pattern 2 : Helm pour Tenant Provisioning

Utilisez Helm pour templater les namespaces des tenants et les deployer de manière consistent.

helm install tenant-acme-corp ./tenant-chart \
  --namespace tenant-acme-corp \
  --create-namespace \
  --set tenantName=acme-corp \
  --set tenantId=cust-12345 \
  --set tier=premium

Cela automatise creation de namespace, RBAC, quotas, et deployment d'application.

Optimisation de Coûts pour SaaS Multi-Tenant

La multi-tenancy est coût-efficace, mais vous pouvez optimiser davantage :

1. Right-size requests/limits des ressources N'allouez pas plus de ressources que les tenants n'utilisent réellement. Monitorez et adjustez.

2. Utilisez cluster autoscaling Laissez Hikube scaler le cluster up/down selon demande réelle.

3. Utilisez spot/preemptible instances pour workloads non-critiques Les environnements dev/staging peuvent tourner sur instances spot moins chers.

4. Implémentez chargeback tenant-based Trackez coût par tenant (CPU, storage, networking) et charchez en conséquence. Cela incite clients à optimiser leur usage.

5. Utilisez reserved instances pour baseline capacity Engagez une baseline et utilisez on-demand pour burst.

Getting Started : Votre Premier Deployment Multi-Tenant sur Hikube

  1. Designez votre tenant model : Décidez sur cluster partagé vs. clusters séparés, et stratégie de database (schemas partagés dans la plupart des cas).

  2. Créez namespace templates : Construisez manifests Kubernetes pour namespace, RBAC, quotas, network policies.

  3. Configurez ingress routing : Deployez un Ingress controller (Nginx ou Traefik) configuré pour hostname-based routing.

  4. Implémentez tenant provisioning : Construisez automation pour créer namespaces, schemas, et secrets quand clients s'inscrivent.

  5. Ajoutez monitoring : Configurez métriques per-tenant dans Prometheus/Grafana.

  6. Testez isolation : Essayez délibérément d'accéder aux données d'autres tenants. Assurez-vous que votre isolation fonctionne.

  7. Planifiez pour upgrades : Définissez comment vous upgraderez applications par-tenant sans disrupter les autres.

Conclusion

La SaaS multi-tenant sur Kubernetes est puissante mais exige une architecture soignée. La bonne nouvelle : Kubernetes fournit tous les outils dont vous avez besoin (namespaces, RBAC, network policies, resource quotas, auto-scaling).

Quick recap :

  • Utilisez un cluster Kubernetes partagé pour la plupart des clients
  • Isolez tenants via namespaces, RBAC, et network policies
  • Stockez données dans base partagée avec schemas séparés (pour la plupart des clients)
  • Implémentez resource quotas pour prévenir noisy neighbor issues
  • Monitorez métriques per-tenant pour comprendre les coûts
  • Ajoutez couches de sécurité : pod security policies, audit logging, secrets management

La complexité n'est pas dans Kubernetes lui-même. C'est dans construire l'automation (tenant controller) qui gère le lifecycle multi-tenant. Investissez dans ceci tôt, et votre SaaS scale smoothement.


Prêt à deployer une SaaS multi-tenant sur Kubernetes ? L'équipe de conseil d'Hidora peut vous aider à architecting, sécuriser, et optimiser votre système multi-tenant sur Hikube. Nous travaillons avec des SaaS à tous les niveaux d'échelle. Hikube Consulting Services · Managed Kubernetes · Managed Services

Cet article vous parle ?

Hidora peut vous accompagner sur ce sujet.

Besoin d'un accompagnement ?

Parlons de votre projet. 30 minutes, sans engagement.