Skip to content

Helm Deployment

La Suite Meet provides an official Helm chart for Kubernetes deployments. This is the method used by DINUM in production.

Getting the Helm chart

The Helm chart is included in the Meet repository:

git clone https://github.com/suitenumerique/meet.git
cd meet/helm

Chart structure

The Meet Helm chart deploys:

  • Meet backend (Django) — Deployment + Service
  • Celery worker — Deployment
  • Static/frontend assets — served by the backend or a separate Nginx
  • Ingress resources for HTTPS
  • Optional: LiveKit webhook Ingress

External services (PostgreSQL, Redis, Garage) are configured via values and expected to be pre-provisioned.

Values file

Create a values.yaml file for your deployment. Key sections:

Image

image:
  repository: lasuite/meet-backend
  tag: "1.15.0"  # pin to a specific version
  pullPolicy: IfNotPresent

Backend environment

backend:
  django:
    secretKey: "your-secret-key"
    allowedHosts: "meet.example.com"
    csrfTrustedOrigins: "https://meet.example.com"

  database:
    host: "postgresql.example.com"
    port: 5432
    name: "meet"
    user: "meet"
    password: "db-password"

  redis:
    url: "redis://redis.example.com:6379/0"

  oidc:
    clientId: "meet"
    clientSecret: "oidc-secret"
    jwksEndpoint: "https://auth.example.com/realms/meet/protocol/openid-connect/certs"
    authorizationEndpoint: "https://auth.example.com/realms/meet/protocol/openid-connect/auth"
    tokenEndpoint: "https://auth.example.com/realms/meet/protocol/openid-connect/token"
    userEndpoint: "https://auth.example.com/realms/meet/protocol/openid-connect/userinfo"

  livekit:
    apiKey: "myapikey"
    apiSecret: "livekit-secret"
    url: "wss://meet.example.com:7880"
    apiUrl: "http://livekit-service:7880"

  storage:
    s3EndpointUrl: "https://s3.example.com"
    s3AccessKeyId: "access-key"
    s3SecretAccessKey: "secret-key"
    s3BucketName: "meet-media-storage"

Ingress

ingress:
  enabled: true
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: meet.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: meet-tls
      hosts:
        - meet.example.com

Dedicated Ingress for LiveKit webhook

livekitWebhook:
  ingress:
    enabled: true
    className: nginx
    annotations:
      cert-manager.io/cluster-issuer: letsencrypt-prod
    host: meet.example.com
    path: /api/v1.0/webhook/livekit/
    tls:
      secretName: meet-tls

This creates a separate Ingress for the LiveKit webhook, isolated from the main application for security.

Replicas and resources

replicaCount: 2

resources:
  requests:
    cpu: 250m
    memory: 512Mi
  limits:
    cpu: 1000m
    memory: 1Gi

celery:
  enabled: true
  replicaCount: 1
  resources:
    requests:
      cpu: 100m
      memory: 256Mi

Security context (added in v1.14.0)

podSecurityContext:
  runAsNonRoot: true
  runAsUser: 1000
  fsGroup: 1000

containerSecurityContext:
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop:
      - ALL

Custom background image ingress (v1.11.0+)

customBackground:
  ingress:
    enabled: true
    host: meet.example.com

Deploying

Install

helm install meet ./helm/meet \
  --namespace meet \
  --create-namespace \
  --values values.yaml

Upgrade

helm upgrade meet ./helm/meet \
  --namespace meet \
  --values values.yaml

Check deployment status

kubectl -n meet get pods
kubectl -n meet get ingress
kubectl -n meet logs deployment/meet-backend

Run migrations after install/upgrade

kubectl -n meet exec deployment/meet-backend -- python manage.py migrate
kubectl -n meet exec deployment/meet-backend -- python manage.py collectstatic --no-input

Helmfile (multi-environment)

For managing multiple environments (staging, production), use helmfile:

# helmfile.yaml
releases:
  - name: meet
    chart: ./helm/meet
    namespace: meet
    values:
      - values/common.yaml
      - values/{{ .Environment.Name }}.yaml

environments:
  staging:
  production:

Deploy:

helmfile -e production sync

Secrets management

Avoid storing secrets in values.yaml in version control. Options:

  • Kubernetes Secrets referenced via valueFrom.secretKeyRef
  • External Secrets Operator (Vault, AWS Secrets Manager, etc.)
  • SOPS encrypted values files (used by the DINUM team — see .sops.yaml in the repo)
# Encrypt a values file with SOPS
sops --encrypt values/production-secrets.yaml > values/production-secrets.enc.yaml

Local development with Tilt

For local Kubernetes development mirroring production:

# Build and start a local Kind cluster
make build-k8s-cluster

# Start the application stack
make start-tilt-keycloak

# Monitor at http://localhost:10350/
# App available at https://meet.127.0.0.1.nip.io/

Tilt provides hot reloading and live log streaming for all services.