frappe-operator

Getting Started

This guide will help you install the Frappe Operator and deploy your first Frappe site.

Prerequisites

Before you begin, ensure you have:

Required Dependencies (v1.0.0+)

Optional Dependencies

Installation

Step 1: Install Frappe Operator

Install the operator and its CRDs:

# Install CRDs and operator
kubectl apply -f https://raw.githubusercontent.com/vyogotech/frappe-operator/main/config/install.yaml

# Verify installation
kubectl get deployment -n frappe-operator-system
kubectl get crd | grep vyogo.tech

You should see the following CRDs:

Step 2: Install MariaDB (For Development)

For a quick development setup, install a simple MariaDB instance:

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mariadb
  namespace: default
spec:
  serviceName: mariadb
  replicas: 1
  selector:
    matchLabels:
      app: mariadb
  template:
    metadata:
      labels:
        app: mariadb
    spec:
      containers:
      - name: mariadb
        image: mariadb:10.6
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "admin"
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mariadb-data
          mountPath: /var/lib/mysql
  volumeClaimTemplates:
  - metadata:
      name: mariadb-data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
  name: mariadb
  namespace: default
spec:
  type: ClusterIP
  selector:
    app: mariadb
  ports:
  - port: 3306
    targetPort: 3306
EOF

For production, use MariaDB Operator instead.

Step 3: Install Ingress Controller (Optional)

If you want external access to your sites:

# Install NGINX Ingress Controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml

# Wait for it to be ready
kubectl wait --namespace ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=120s

Deploying Your First Site

Create a file named my-first-site.yaml:

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

---
# FrappeSite: Your site
apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: mysite
  namespace: default
spec:
  benchRef:
    name: dev-bench
  siteName: "mysite.local"
  dbConfig:
    mode: shared

Deploy it:

# Apply the manifest
kubectl apply -f my-first-site.yaml

# Watch the resources being created
kubectl get frappebench,frappesite -w

Method 2: Using Example Manifests

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

# Check status
kubectl get frappebench,frappesite

Understanding What Gets Created

When you deploy a bench and site, the operator creates:

For FrappeBench:

For FrappeSite:

Checking Deployment Status

Check Custom Resources

# Check bench status
kubectl get frappebench dev-bench -o yaml

# Check site status  
kubectl get frappesite mysite -o yaml

# View all Frappe resources
kubectl get frappebench,frappesite

Check Kubernetes Resources

# View all pods
kubectl get pods

# Check deployments
kubectl get deployments

# Check services
kubectl get services

# Check jobs
kubectl get jobs

Watch Logs

# Bench initialization
kubectl logs -l job-name=dev-bench-init -f

# Site initialization
kubectl logs -l job-name=mysite-init -f

# Application logs
kubectl logs -l app=mysite-gunicorn -f

Accessing Your Site

Method 1: Port Forwarding (Easiest for Testing)

# Forward nginx service to localhost
kubectl port-forward service/dev-bench-nginx 8080:8080

# Add to /etc/hosts (Linux/Mac)
echo "127.0.0.1 mysite.local" | sudo tee -a /etc/hosts

# Or on Windows (as Administrator)
# echo 127.0.0.1 mysite.local >> C:\Windows\System32\drivers\etc\hosts

# Access in browser
# http://mysite.local:8080

Method 2: Using Ingress (Production)

If you have an ingress controller and proper DNS:

apiVersion: vyogo.tech/v1alpha1
kind: FrappeSite
metadata:
  name: mysite
spec:
  benchRef:
    name: dev-bench
  siteName: "mysite.example.com"
  domain: "mysite.example.com"
  ingress:
    enabled: true
    className: "nginx"
    tls:
      enabled: true
      certManagerIssuer: "letsencrypt-prod"
  dbConfig:
    mode: shared

Access at: https://mysite.example.com

Method 3: NodePort (Development)

For local development without DNS:

# Expose nginx service as NodePort
kubectl patch service dev-bench-nginx -p '{"spec":{"type":"NodePort"}}'

# Get the NodePort
kubectl get service dev-bench-nginx

# Access via NodePort
# http://<node-ip>:<node-port>

Default Credentials

After site initialization, use these default credentials:

# Get admin password from secret (if configured)
kubectl get secret mysite-admin-password -o jsonpath='{.data.password}' | base64 -d

Verifying the Installation

1. Check Bench Status

kubectl get frappebench dev-bench -o jsonpath='{.status.ready}'
# Should return: true

2. Check Site Status

kubectl get frappesite mysite -o jsonpath='{.status.phase}'
# Should return: Ready

3. Test Site Access

# Get site URL
kubectl get frappesite mysite -o jsonpath='{.status.siteURL}'

# Test with curl
curl -H "Host: mysite.local" http://localhost:8080/api/method/ping
# Should return: {"message":"pong"}

4. Check Component Health

# All pods should be running
kubectl get pods -l bench=dev-bench
kubectl get pods -l site=mysite

# Check endpoints
kubectl get endpoints

Common Initial Setup Tasks

Change Admin Password

# Create a password secret
kubectl create secret generic mysite-admin-pwd \
  --from-literal=password='YourSecurePassword123!'

# Reference it in FrappeSite
kubectl patch frappesite mysite --type=merge -p '{
  "spec": {
    "adminPasswordSecretRef": {
      "name": "mysite-admin-pwd"
    }
  }
}'

Install Additional Apps

# Update bench with more apps
kubectl patch frappebench dev-bench --type=merge -p '{
  "spec": {
    "appsJSON": "[\"erpnext\", \"hrms\", \"custom_app\"]"
  }
}'

# The operator will handle the update

Scale Components

# Scale gunicorn replicas manually
kubectl patch frappebench dev-bench --type=merge -p '{
  "spec": {
    "componentReplicas": {
      "gunicorn": 3,
      "workerDefault": 2
    }
  }
}'

Enable Worker Autoscaling (NEW)

For production workloads, enable KEDA-based autoscaling to automatically scale workers based on queue length:

kubectl patch frappebench dev-bench --type=merge -p '{
  "spec": {
    "workerAutoscaling": {
      "short": {
        "enabled": true,
        "minReplicas": 0,
        "maxReplicas": 10,
        "queueLength": 2
      },
      "long": {
        "enabled": true,
        "minReplicas": 1,
        "maxReplicas": 5,
        "queueLength": 5
      },
      "default": {
        "enabled": false,
        "staticReplicas": 2
      }
    }
  }
}'

# Check autoscaling status
kubectl get scaledobjects
kubectl get frappebench dev-bench -o jsonpath='{.status.workerScaling}' | jq

Benefits:

For more details, see Worker Autoscaling.

Next Steps

Now that you have a working installation:

  1. Learn about concepts - Understanding benches, sites, and architecture
  2. Explore examples - Common deployment patterns
  3. Configure for production - Best practices
  4. Set up monitoring - Observability
  5. Configure backups - Data protection

Troubleshooting

If something goes wrong, check:

  1. Operator logs:
    kubectl logs -n frappe-operator-system deployment/frappe-operator-controller-manager
    
  2. Resource events:
    kubectl describe frappebench dev-bench
    kubectl describe frappesite mysite
    
  3. Pod logs:
    kubectl logs <pod-name>
    

For more detailed troubleshooting, see the Troubleshooting Guide.

Security Context Configuration

The operator provides flexible security context configuration for different environments.

Default Behavior (OpenShift Compatible)

Out of the box, the operator uses OpenShift-compatible defaults:

No configuration needed for OpenShift deployments!

Custom Security Contexts

Option 1: Per-Bench Override

Configure security context for a specific bench:

apiVersion: vyogo.tech/v1alpha1
kind: FrappeBench
metadata:
  name: custom-bench
spec:
  security:
    podSecurityContext:
      runAsUser: 2000      # Custom UID
      runAsGroup: 2000
      fsGroup: 2000
    securityContext:
      runAsUser: 2000
      runAsGroup: 2000
      allowPrivilegeEscalation: false
      capabilities:
        drop: ["ALL"]
  apps:
    - name: erpnext

Option 2: Cluster-Wide Defaults

Set environment variables in the operator deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frappe-operator-controller-manager
  namespace: frappe-operator-system
spec:
  template:
    spec:
      containers:
      - name: manager
        env:
        - name: FRAPPE_DEFAULT_UID
          value: "2000"        # All benches default to UID 2000
        - name: FRAPPE_DEFAULT_GID
          value: "2000"
        - name: FRAPPE_DEFAULT_FSGROUP
          value: "2000"

Priority: spec.security → Environment Variables → Hardcoded Defaults (1001/0/0)

For detailed examples and best practices, see:

Clean Up

To remove everything:

# Delete site
kubectl delete frappesite mysite

# Delete bench
kubectl delete frappebench dev-bench

# Delete MariaDB (if you created it)
kubectl delete statefulset mariadb
kubectl delete service mariadb

# Uninstall operator (optional)
kubectl delete -f https://raw.githubusercontent.com/vyogotech/frappe-operator/main/config/install.yaml