frappe-operator

Examples

Real-world deployment patterns and configuration examples for Frappe Operator.

Note: All example YAML files are available in the examples/ directory of the repository.

Table of Contents


Quick Start

The fastest way to get started is using the minimal example:

kubectl apply -f https://raw.githubusercontent.com/vyogotech/frappe-operator/main/examples/minimal-bench-and-site.yaml

Or clone the repository:

git clone https://github.com/vyogotech/frappe-operator.git
cd frappe-operator/examples
kubectl apply -f minimal-bench-and-site.yaml

Development Environment

Minimal Local Setup

Perfect for local development and testing.

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeBench
metadata:
  name: dev-bench
  namespace: default
spec:
  frappeVersion: "version-15"
  appsJSON: '["erpnext"]'
  domainConfig:
    suffix: ".local"
    autoDetect: false

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: mysite
  namespace: default
spec:
  benchRef:
    name: dev-bench
  siteName: "mysite"
  dbConfig:
    mode: shared
  ingress:
    enabled: true
    className: "nginx"

Access:

kubectl port-forward service/dev-bench-nginx 8080:8080
# Add to /etc/hosts: 127.0.0.1 mysite.local
# Access: http://mysite.local:8080

Production Deployment

Single-Site Production Setup

Production-ready configuration with proper resources and TLS.

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeBench
metadata:
  name: prod-bench
  namespace: production
spec:
  frappeVersion: "version-15"
  appsJSON: '["erpnext", "hrms"]'

  imageConfig:
    repository: frappe/erpnext
    tag: v15.0.0
    pullPolicy: IfNotPresent

  componentReplicas:
    gunicorn: 3
    socketio: 2
    workerDefault: 2
    workerLong: 2
    workerShort: 1

  componentResources:
    gunicorn:
      requests:
        cpu: "1"
        memory: "2Gi"
      limits:
        cpu: "2"
        memory: "4Gi"
    socketio:
      requests:
        cpu: "500m"
        memory: "512Mi"
      limits:
        cpu: "1"
        memory: "1Gi"
    scheduler:
      requests:
        cpu: "250m"
        memory: "512Mi"
      limits:
        cpu: "500m"
        memory: "1Gi"
    workerDefault:
      requests:
        cpu: "500m"
        memory: "1Gi"
      limits:
        cpu: "1"
        memory: "2Gi"
    workerLong:
      requests:
        cpu: "500m"
        memory: "1Gi"
      limits:
        cpu: "1"
        memory: "2Gi"
    workerShort:
      requests:
        cpu: "250m"
        memory: "512Mi"
      limits:
        cpu: "500m"
        memory: "1Gi"

  redisConfig:
    type: dragonfly
    maxMemory: "4gb"
    resources:
      requests:
        cpu: "500m"
        memory: "4Gi"
      limits:
        cpu: "1"
        memory: "6Gi"

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: erp-site
  namespace: production
spec:
  benchRef:
    name: prod-bench

  siteName: "erp.example.com"
  domain: "erp.example.com"

  adminPasswordSecretRef:
    name: erp-admin-password

  dbConfig:
    mode: dedicated
    storageSize: "100Gi"
    resources:
      requests:
        cpu: "1"
        memory: "4Gi"
      limits:
        cpu: "2"
        memory: "8Gi"

  ingress:
    enabled: true
    className: "nginx"
    annotations:
      cert-manager.io/cluster-issuer: "letsencrypt-prod"
      nginx.ingress.kubernetes.io/proxy-body-size: "100m"
      nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
    tls:
      enabled: true
      certManagerIssuer: "letsencrypt-prod"

---
# Admin password secret
apiVersion: v1
kind: Secret
metadata:
  name: erp-admin-password
  namespace: production
type: Opaque
stringData:
  password: "YourSecurePassword123!"

Multi-Tenant SaaS

Shared Bench with Multiple Customer Sites

One bench serving multiple customer sites - cost-effective SaaS model.

---
# Shared bench for all customers
apiVersion: vyogo.tech/v1alpha1
kind: FrappeBench
metadata:
  name: saas-bench
  namespace: saas-platform
spec:
  frappeVersion: "version-15"
  appsJSON: '["erpnext", "hrms"]'

  # Automatic domain assignment
  domainConfig:
    suffix: ".myplatform.com"

  componentReplicas:
    gunicorn: 5
    socketio: 3
    workerDefault: 5
    workerLong: 3
    workerShort: 2

  componentResources:
    gunicorn:
      requests: { cpu: "1", memory: "2Gi" }
      limits: { cpu: "2", memory: "4Gi" }
    workerDefault:
      requests: { cpu: "500m", memory: "1Gi" }
      limits: { cpu: "1", memory: "2Gi" }

  redisConfig:
    type: dragonfly
    maxMemory: "8gb"

---
# Customer 1 - Shared database
apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: customer1
  namespace: saas-platform
spec:
  benchRef:
    name: saas-bench
  siteName: "customer1" # Results in: customer1.myplatform.com
  dbConfig:
    mode: shared
    mariadbRef:
      name: shared-mariadb
  ingress:
    enabled: true
    className: "nginx"
    tls:
      enabled: true
      certManagerIssuer: "letsencrypt-prod"

---
# Customer 2 - Shared database
apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: customer2
  namespace: saas-platform
spec:
  benchRef:
    name: saas-bench
  siteName: "customer2" # Results in: customer2.myplatform.com
  dbConfig:
    mode: shared
    mariadbRef:
      name: shared-mariadb
  ingress:
    enabled: true
    className: "nginx"
    tls:
      enabled: true
      certManagerIssuer: "letsencrypt-prod"

---
# Customer 3 - Dedicated database (enterprise tier)
apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: enterprise-customer
  namespace: saas-platform
spec:
  benchRef:
    name: saas-bench
  siteName: "enterprise-customer"
  dbConfig:
    mode: dedicated
    storageSize: "200Gi"
    resources:
      requests: { cpu: "2", memory: "8Gi" }
      limits: { cpu: "4", memory: "16Gi" }
  ingress:
    enabled: true
    className: "nginx"
    tls:
      enabled: true
      certManagerIssuer: "letsencrypt-prod"

Enterprise Setup

Dedicated Bench for Enterprise Customer

Complete isolation with dedicated resources.

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeBench
metadata:
  name: acme-corp-bench
  namespace: acme-corp
spec:
  frappeVersion: "version-15"
  appsJSON: '["erpnext", "hrms", "custom_app"]'

  imageConfig:
    repository: acmecorp.azurecr.io/frappe-custom
    tag: v15-acme-1.0.0
    pullPolicy: Always
    pullSecrets:
      - name: acr-credentials

  componentReplicas:
    gunicorn: 10
    socketio: 5
    workerDefault: 10
    workerLong: 5
    workerShort: 3

  componentResources:
    gunicorn:
      requests: { cpu: "2", memory: "4Gi" }
      limits: { cpu: "4", memory: "8Gi" }
    workerDefault:
      requests: { cpu: "1", memory: "2Gi" }
      limits: { cpu: "2", memory: "4Gi" }

  redisConfig:
    type: dragonfly
    maxMemory: "16gb"
    storageSize: "50Gi"

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: acme-erp
  namespace: acme-corp
spec:
  benchRef:
    name: acme-corp-bench

  siteName: "erp.acme.com"
  domain: "erp.acme.com"

  dbConfig:
    mode: external # Using Azure Database for MySQL
    connectionSecretRef:
      name: azure-mysql-credentials

  ingress:
    enabled: true
    className: "nginx"
    annotations:
      cert-manager.io/cluster-issuer: "letsencrypt-prod"
      nginx.ingress.kubernetes.io/proxy-body-size: "500m"
      nginx.ingress.kubernetes.io/proxy-read-timeout: "1800"
      nginx.ingress.kubernetes.io/rate-limit: "100"
    tls:
      enabled: true
      certManagerIssuer: "letsencrypt-prod"

---
# External database credentials
apiVersion: v1
kind: Secret
metadata:
  name: azure-mysql-credentials
  namespace: acme-corp
type: Opaque
stringData:
  host: "acme-mysql.mysql.database.azure.com"
  port: "3306"
  database: "acme_erp"
  username: "acme_admin@acme-mysql"
  password: "YourAzureMySQLPassword"

Custom Domains

Custom Domain per Site

Each site with its own custom domain.

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeBench
metadata:
  name: multi-domain-bench
  namespace: default
spec:
  frappeVersion: "version-15"
  appsJSON: '["erpnext"]'

---
# Site 1: Custom domain
apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: site-company-a
  namespace: default
spec:
  benchRef:
    name: multi-domain-bench
  siteName: "erp.company-a.com"
  domain: "erp.company-a.com"
  dbConfig:
    mode: dedicated
    storageSize: "50Gi"
  ingress:
    enabled: true
    className: "nginx"
    tls:
      enabled: true
      certManagerIssuer: "letsencrypt-prod"

---
# Site 2: Different custom domain
apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: site-company-b
  namespace: default
spec:
  benchRef:
    name: multi-domain-bench
  siteName: "system.company-b.net"
  domain: "system.company-b.net"
  dbConfig:
    mode: dedicated
    storageSize: "50Gi"
  ingress:
    enabled: true
    className: "nginx"
    tls:
      enabled: true
      certManagerIssuer: "letsencrypt-prod"

High Availability

HA Setup with Auto-Scaling

High-availability configuration with horizontal pod autoscaling.

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeBench
metadata:
  name: ha-bench
  namespace: production
spec:
  frappeVersion: "version-15"
  appsJSON: '["erpnext", "hrms"]'

  # Start with moderate replicas
  componentReplicas:
    gunicorn: 5
    socketio: 3
    workerDefault: 3
    workerLong: 2
    workerShort: 2

  componentResources:
    gunicorn:
      requests: { cpu: "1", memory: "2Gi" }
      limits: { cpu: "2", memory: "4Gi" }
    socketio:
      requests: { cpu: "500m", memory: "1Gi" }
      limits: { cpu: "1", memory: "2Gi" }
    workerDefault:
      requests: { cpu: "500m", memory: "1Gi" }
      limits: { cpu: "1", memory: "2Gi" }

  redisConfig:
    type: dragonfly
    maxMemory: "8gb"

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: ha-site
  namespace: production
spec:
  benchRef:
    name: ha-bench
  siteName: "erp.example.com"

  dbConfig:
    mode: external
    connectionSecretRef:
      name: rds-mariadb-galera # AWS RDS with multi-AZ

  ingress:
    enabled: true
    className: "nginx"
    tls:
      enabled: true

---
# HPA for gunicorn
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: ha-bench-gunicorn-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: ha-bench-gunicorn
  minReplicas: 5
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80

---
# HPA for workers
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: ha-bench-worker-default-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: ha-bench-worker-default
  minReplicas: 3
  maxReplicas: 15
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 75

Component Autoscaling

Provider-Agnostic Autoscaling for All Components

⚡ NEW in v3.0.0: Unified autoscaling for web components (HPA) and workers (KEDA) with provider abstraction.

Prerequisites

HPA: Built-in to Kubernetes ✅
KEDA: Automatically installed by install.sh, or manual installation:

kubectl apply -f https://github.com/kedacore/keda/releases/download/v2.16.1/keda-2.16.1.yaml

Production Setup with Full Autoscaling

This example shows autoscaling for all components - web (HPA) and workers (KEDA):

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeBench
metadata:
  name: autoscaling-bench
  namespace: production
spec:
  frappeVersion: "version-15"
  apps:
    - name: erpnext
      source: image
    - name: hrms
      source: image

  redisConfig:
    type: redis

  # Component autoscaling - unified configuration for all components
  componentAutoscaling:
    # NGINX - HPA based on CPU utilization
    nginx:
      enabled: true
      provider: hpa # Kubernetes built-in HPA
      minReplicas: 2
      maxReplicas: 10
      hpa:
        metric: cpu # cpu or memory
        targetUtilization: 70 # Scale when CPU > 70%
        scaleUpStabilization: 0 # Scale up immediately
        scaleDownStabilization: 300 # Wait 5min before scaling down

    # Gunicorn - HPA based on memory utilization
    gunicorn:
      enabled: true
      provider: hpa
      minReplicas: 3
      maxReplicas: 15
      hpa:
        metric: memory
        targetUtilization: 80
        scaleUpStabilization: 0
        scaleDownStabilization: 300

    # Socket.IO - static replicas (no autoscaling)
    socketio:
      enabled: false
      staticReplicas: 2

    # Short workers - KEDA with scale-to-zero
    worker-short:
      enabled: true
      provider: keda # KEDA for queue-based scaling
      minReplicas: 0 # Scale to zero to save costs
      maxReplicas: 10
      pollingInterval: 10 # Check queue every 10s
      cooldownPeriod: 30 # Wait 30s before scaling down
      keda:
        trigger: redis # Monitor Redis queue
        targetValue: "2" # 2 jobs per worker

    # Long workers - KEDA with minimum replicas
    worker-long:
      enabled: true
      provider: keda
      minReplicas: 1 # Always have 1 worker
      maxReplicas: 5
      pollingInterval: 30
      cooldownPeriod: 60
      keda:
        trigger: redis
        targetValue: "5" # 5 jobs per worker

    # Default workers - static replicas
    worker-default:
      enabled: false
      staticReplicas: 2

  # Resources for components
  componentResources:
    nginx:
      requests: { cpu: "200m", memory: "256Mi" }
      limits: { cpu: "500m", memory: "512Mi" }
    gunicorn:
      requests: { cpu: "500m", memory: "1Gi" }
      limits: { cpu: "2", memory: "2Gi" }
    socketio:
      requests: { cpu: "200m", memory: "512Mi" }
      limits: { cpu: "1", memory: "1Gi" }
    workerShort:
      requests: { cpu: "500m", memory: "1Gi" }
      limits: { cpu: "1", memory: "2Gi" }
    workerLong:
      requests: { cpu: "1", memory: "2Gi" }
      limits: { cpu: "2", memory: "4Gi" }
    workerDefault:
      requests: { cpu: "500m", memory: "1Gi" }
      limits: { cpu: "1", memory: "2Gi" }

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: autoscaling-site
  namespace: production
spec:
  benchRef:
    name: autoscaling-bench
  siteName: "app.example.com"
  dbConfig:
    provider: mariadb
    mode: shared
  domain: "app.example.com"

Cost-Optimized Development Setup

Aggressive scale-to-zero for development environments to minimize costs:

apiVersion: vyogo.tech/v1alpha1
kind: FrappeBench
metadata:
  name: dev-autoscaling
  namespace: development
spec:
  frappeVersion: "version-15"
  apps:
    - name: erpnext
      source: image

  # All workers scale to zero when idle
  componentAutoscaling:
    worker-short:
      enabled: true
      provider: keda
      minReplicas: 0
      maxReplicas: 3
      pollingInterval: 5 # Check frequently
      cooldownPeriod: 10 # Scale down fast
      keda:
        trigger: redis
        targetValue: "1" # Scale up quickly
    worker-long:
      enabled: true
      provider: keda
      minReplicas: 0 # Also scale to zero
      maxReplicas: 2
      pollingInterval: 10
      cooldownPeriod: 20
      keda:
        trigger: redis
        targetValue: "1"
    worker-default:
      enabled: true
      provider: keda
      minReplicas: 0
      maxReplicas: 2
      pollingInterval: 5
      cooldownPeriod: 10
      keda:
        trigger: redis
        targetValue: "1"

Monitoring Autoscaling

# Check ScaledObjects created by KEDA
kubectl get scaledobjects -n production

# Check component scaling status
kubectl get frappebench autoscaling-bench -o jsonpath='{.status.componentScaling}' | jq

# View current HPA status
kubectl get hpa -n production

# Check queue lengths
kubectl exec -n production deployment/autoscaling-bench-redis -- \
  redis-cli LLEN "rq:queue:short"

kubectl exec -n production deployment/autoscaling-bench-redis -- \
  redis-cli LLEN "rq:queue:long"

# Watch worker pods scaling
kubectl get pods -n production -l component=worker-short -w

Benefits

Configuration Parameters

Parameter Description Default Recommended
enabled Enable autoscaling false true for production
provider Scaling provider (keda or hpa) hpa keda for workers, hpa for web
minReplicas Minimum replicas (0 for scale-to-zero) 1 0 for dev, 1+ for prod
maxReplicas Maximum replicas 10 Based on load
staticReplicas Fixed replicas when disabled 1 Based on component
pollingInterval Metric check frequency (seconds) 30 10-30
cooldownPeriod Wait before scale down (seconds) 60 30-60 for workers
keda.trigger KEDA trigger type (cpu/memory/redis) cpu redis for workers
keda.targetValue Jobs per worker threshold "5" "2-5" for short, "5-10" for long
hpa.metric HPA metric type (cpu/memory) cpu cpu for web
hpa.targetUtilization Target percentage (1-100) 70 70-80

Note: The new componentAutoscaling API replaces the deprecated workerAutoscaling API from v1.x.


Site Backup Management

⚡ NEW: Automated site backups using the bench backup command with full control over backup options and scheduling.

One-Time Backup

Create an immediate backup of a site:

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeBench
metadata:
  name: backup-demo-bench
spec:
  frappeVersion: "version-15"
  apps:
    - name: erpnext
      source: image

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: backup-demo-site
spec:
  benchRef:
    name: backup-demo-bench
  siteName: "demo.example.com"
  dbConfig:
    mode: shared

---
# One-time backup with files and compression
apiVersion: vyogo.tech/v1alpha1
kind: SiteBackup
metadata:
  name: demo-site-backup
spec:
  site: "demo.example.com" # Must match FrappeSite
  withFiles: true # Include private/public files
  compress: true # Compress backup files
  verbose: true # Enable verbose output

Scheduled Daily Backup

Automatic daily backups at 2 AM:

---
apiVersion: vyogo.tech/v1alpha1
kind: SiteBackup
metadata:
  name: demo-site-daily-backup
spec:
  site: "demo.example.com"
  schedule: "0 2 * * *" # Daily at 2 AM
  withFiles: true
  compress: true

Selective Backup with Filtering

Backup only specific DocTypes while excluding sensitive data:

---
apiVersion: vyogo.tech/v1alpha1
kind: SiteBackup
metadata:
  name: demo-site-selective-backup
spec:
  site: "demo.example.com"
  withFiles: true
  compress: true

  # Include only these DocTypes
  include:
    - "DocType"
    - "Module Def"
    - "Custom Field"
    - "Print Format"

  # Exclude sensitive data
  exclude:
    - "User"
    - "Role"
    - "Communication"
    - "Email Queue"

  verbose: true

Custom Backup Paths

Specify custom paths for different backup components:

---
apiVersion: vyogo.tech/v1alpha1
kind: SiteBackup
metadata:
  name: demo-site-custom-paths
spec:
  site: "demo.example.com"
  withFiles: true
  compress: true

  # Custom backup paths
  backupPath: "/backups/daily" # Main backup directory
  backupPathDB: "/backups/db" # Database files
  backupPathConf: "/backups/config" # Configuration files
  backupPathFiles: "/backups/public" # Public files
  backupPathPrivateFiles: "/backups/private" # Private files

Monitoring Backup Status

# Check backup status
kubectl get sitebackup

# Get detailed status
kubectl describe sitebackup demo-site-backup

# Check backup jobs
kubectl get jobs -l backup=true

# View backup logs
kubectl logs job/demo-site-backup-backup

# Check scheduled backups
kubectl get cronjob demo-site-daily-backup-backup

Backup Configuration Options

Option Description Default
site Target site name Required
schedule Cron expression for recurring backups One-time
withFiles Include private/public files false
compress Compress backup files false
backupPath Main backup directory Default
backupPathDB Database files path Default
backupPathConf Config files path Default
backupPathFiles Public files path Default
backupPathPrivateFiles Private files path Default
include DocTypes to include All
exclude DocTypes to exclude None
ignoreBackupConf Ignore backup config false
verbose Verbose output false

Backup Status Fields

status:
  phase: "Succeeded" # Pending, Running, Succeeded, Failed
  lastBackup: "2024-01-15T02:00:00Z" # Last successful backup
  lastBackupJob: "demo-site-backup-backup-abc123" # Job/CronJob name
  message: "Backup completed successfully"

Production Backup Strategy

---
# Daily full backup (2 AM)
apiVersion: vyogo.tech/v1alpha1
kind: SiteBackup
metadata:
  name: prod-daily-full-backup
spec:
  site: "erp.example.com"
  schedule: "0 2 * * *"
  withFiles: true
  compress: true

---
# Hourly selective backup (business data only)
apiVersion: vyogo.tech/v1alpha1
kind: SiteBackup
metadata:
  name: prod-hourly-business-backup
spec:
  site: "erp.example.com"
  schedule: "0 * * * *"
  include:
    - "Sales Order"
    - "Purchase Order"
    - "Item"
    - "Customer"
    - "Supplier"
  compress: true

Benefits



External Database Support

⚡ NEW in v2.4.0: Connect to databases managed outside of Kubernetes (e.g., AWS RDS, Managed MariaDB).

Shared External Database (RDS/Cloud SQL)

Connect multiple sites to a shared external database server with default bench configurations.

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeBench
metadata:
  name: external-db-bench
spec:
  frappeVersion: "version-15"
  apps:
    - name: erpnext
      source: image
  # Default DB config for all sites in this bench
  dbConfig:
    provider: external
    host: "mariadb.production.svc.cluster.local"
    port: "3306"
    connectionSecretRef:
      name: shared-db-creds

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: site1-external
spec:
  benchRef:
    name: external-db-bench
  siteName: "site1.example.com"
  # site1_db will be used by default (from siteName)
  # Credentials will be pulled from 'shared-db-creds'

Dedicated External Database per Site

Each site with its own specific external host and credentials.

---
apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: enterprise-site
spec:
  benchRef:
    name: dev-bench
  siteName: "enterprise.example.com"
  dbConfig:
    provider: external
    host: "dedicated-rds-instance.aws.com"
    port: "3306"
    connectionSecretRef:
      name: enterprise-db-creds

Credentials Secret Format

The referenced Secret should contain at least username and password. database is optional (defaults to site name).

apiVersion: v1
kind: Secret
metadata:
  name: enterprise-db-creds
type: Opaque
stringData:
  username: "admin_user"
  password: "secure_password"
  database: "enterprise_prod" # Optional

Resource Scaling

Three-Tier Resource Configuration

Small, medium, and large resource tiers.

Small Tier (Development/Testing)

apiVersion: vyogo.tech/v1alpha1
kind: FrappeBench
metadata:
  name: small-bench
spec:
  frappeVersion: "version-15"
  appsJSON: '["erpnext"]'

  componentReplicas:
    gunicorn: 1
    socketio: 1
    workerDefault: 1
    workerLong: 1
    workerShort: 1

  componentResources:
    gunicorn:
      requests: { cpu: "200m", memory: "256Mi" }
      limits: { cpu: "500m", memory: "512Mi" }
    socketio:
      requests: { cpu: "100m", memory: "128Mi" }
      limits: { cpu: "200m", memory: "256Mi" }
    scheduler:
      requests: { cpu: "100m", memory: "128Mi" }
      limits: { cpu: "200m", memory: "256Mi" }
    workerDefault:
      requests: { cpu: "200m", memory: "256Mi" }
      limits: { cpu: "400m", memory: "512Mi" }

Medium Tier (Small Production)

apiVersion: vyogo.tech/v1alpha1
kind: FrappeBench
metadata:
  name: medium-bench
spec:
  frappeVersion: "version-15"
  appsJSON: '["erpnext", "hrms"]'

  componentReplicas:
    gunicorn: 3
    socketio: 2
    workerDefault: 2
    workerLong: 1
    workerShort: 1

  componentResources:
    gunicorn:
      requests: { cpu: "500m", memory: "512Mi" }
      limits: { cpu: "1", memory: "1Gi" }
    socketio:
      requests: { cpu: "250m", memory: "256Mi" }
      limits: { cpu: "500m", memory: "512Mi" }
    scheduler:
      requests: { cpu: "250m", memory: "256Mi" }
      limits: { cpu: "500m", memory: "512Mi" }
    workerDefault:
      requests: { cpu: "500m", memory: "512Mi" }
      limits: { cpu: "1", memory: "1Gi" }

Large Tier (Production)

apiVersion: vyogo.tech/v1alpha1
kind: FrappeBench
metadata:
  name: large-bench
spec:
  frappeVersion: "version-15"
  appsJSON: '["erpnext", "hrms"]'

  componentReplicas:
    gunicorn: 5
    socketio: 3
    workerDefault: 5
    workerLong: 3
    workerShort: 2

  componentResources:
    gunicorn:
      requests: { cpu: "1", memory: "2Gi" }
      limits: { cpu: "2", memory: "4Gi" }
    socketio:
      requests: { cpu: "500m", memory: "1Gi" }
      limits: { cpu: "1", memory: "2Gi" }
    scheduler:
      requests: { cpu: "500m", memory: "1Gi" }
      limits: { cpu: "1", memory: "2Gi" }
    workerDefault:
      requests: { cpu: "1", memory: "2Gi" }
      limits: { cpu: "2", memory: "4Gi" }

Using Example Files

All examples are available in the repository under examples/:

File Description
minimal-bench-and-site.yaml Minimal setup for quick testing
autoscaling-bench.yaml ⚡ NEW: KEDA-based worker autoscaling with scale-to-zero
production-bench.yaml Production-ready bench configuration
production-site.yaml Production site with TLS
multi-tenant-bench.yaml Bench for multiple customer sites
multi-tenant-sites.yaml Multiple sites on shared bench
enterprise-setup.yaml Complete enterprise configuration
high-availability-bench.yaml HA setup with multiple replicas
dedicated-db-site.yaml Site with dedicated database
custom-domain-site.yaml Custom domain configuration
custom-image-bench.yaml Using custom container images
resource-tiers.yaml Small/Medium/Large resource tiers
basic-sitebackup.yaml ⚡ NEW: One-time site backup
scheduled-sitebackup.yaml ⚡ NEW: Scheduled daily backup
sitebackup-with-options.yaml ⚡ NEW: Backup with files and compression
sitebackup-selective.yaml ⚡ NEW: Selective DocType backup

Applying Examples

# Clone the repository
git clone https://github.com/vyogotech/frappe-operator.git
cd frappe-operator

# Apply a specific example
kubectl apply -f examples/minimal-bench-and-site.yaml

# Or apply all examples (not recommended)
kubectl apply -f examples/

# Apply from remote URL
kubectl apply -f https://raw.githubusercontent.com/vyogotech/frappe-operator/main/examples/production-bench.yaml

Quick Reference

Command Cheat Sheet

# Create resources
kubectl apply -f examples/minimal-bench-and-site.yaml

# Check status
kubectl get frappebench,frappesite

# Watch for changes
kubectl get frappebench,frappesite -w

# Get details
kubectl describe frappebench <name>
kubectl describe frappesite <name>

# Check pods
kubectl get pods -l bench=<bench-name>
kubectl get pods -l site=<site-name>

# View logs
kubectl logs -l app=<component> -f

# Scale replicas
kubectl patch frappebench <name> --type=merge -p '{
  "spec": {"componentReplicas": {"gunicorn": 5}}
}'

# Delete resources
kubectl delete frappesite <name>
kubectl delete frappebench <name>

Next Steps