Documentation Index Fetch the complete documentation index at: https://mintlify.com/makeplane/plane/llms.txt
Use this file to discover all available pages before exploring further.
Deploy Plane on Kubernetes for production environments that require high availability, scalability, and advanced orchestration capabilities.
Overview
The Kubernetes deployment of Plane provides:
High Availability : Multiple replicas of critical services
Auto-scaling : Horizontal pod autoscaling based on load
Rolling Updates : Zero-downtime deployments
Resource Management : CPU and memory limits/requests
Health Checks : Liveness and readiness probes
Persistent Storage : StatefulSets for databases
Prerequisites
Kubernetes Cluster
You need a running Kubernetes cluster (v1.21+). Options include:
Cloud Providers : AWS EKS, Google GKE, Azure AKS, DigitalOcean DOKS
Self-Managed : kubeadm, kops, Rancher
Local Development : minikube, kind, k3s
Verify cluster access: kubectl cluster-info
kubectl get nodes
Helm 3
Install Helm, the Kubernetes package manager: curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Verify installation:
kubectl
Ensure kubectl is installed and configured:
Persistent Storage
Your cluster needs a StorageClass for persistent volumes: Most cloud providers offer default storage classes (gp2, standard, etc.).
Installation via Helm
Plane provides an official Helm chart for Kubernetes deployments.
Add Helm Repository
helm repo add makeplane https://helm.plane.so
helm repo update
Verify the chart is available:
helm search repo makeplane/plane-ce
Install Plane
Create Namespace
kubectl create namespace plane
Create Configuration File
Create a values.yaml file with your custom configuration: # Basic configuration
ingress :
enabled : true
host : plane.example.com
tls :
enabled : true
secretName : plane-tls
# Application settings
env :
web_url : "https://plane.example.com"
cors_allowed_origins : "https://plane.example.com"
# Database (use external for production)
postgresql :
enabled : true # Set to false if using external DB
auth :
username : plane
password : "change-me-in-production"
database : plane
primary :
persistence :
size : 10Gi
# Redis cache
redis :
enabled : true # Set to false if using external Redis
auth :
enabled : false
master :
persistence :
size : 2Gi
# RabbitMQ
rabbitmq :
enabled : true
auth :
username : plane
password : "change-me-in-production"
persistence :
size : 2Gi
# MinIO (object storage)
minio :
enabled : true # Set to false if using S3
auth :
rootUser : access-key
rootPassword : "change-me-in-production"
persistence :
size : 20Gi
# Service replicas (adjust based on load)
api :
replicaCount : 2
resources :
requests :
cpu : 500m
memory : 1Gi
limits :
cpu : 2000m
memory : 2Gi
worker :
replicaCount : 2
resources :
requests :
cpu : 250m
memory : 512Mi
limits :
cpu : 1000m
memory : 1Gi
beatWorker :
replicaCount : 1
resources :
requests :
cpu : 100m
memory : 256Mi
limits :
cpu : 500m
memory : 512Mi
web :
replicaCount : 2
resources :
requests :
cpu : 100m
memory : 256Mi
limits :
cpu : 500m
memory : 512Mi
space :
replicaCount : 1
resources :
requests :
cpu : 100m
memory : 256Mi
limits :
cpu : 500m
memory : 512Mi
admin :
replicaCount : 1
resources :
requests :
cpu : 100m
memory : 256Mi
limits :
cpu : 500m
memory : 512Mi
live :
replicaCount : 1
resources :
requests :
cpu : 100m
memory : 256Mi
limits :
cpu : 500m
memory : 512Mi
Install Chart
helm install plane makeplane/plane-ce \
--namespace plane \
--values values.yaml \
--timeout 10m
Monitor the installation: kubectl get pods -n plane -w
Wait for all pods to reach Running status.
Verify Installation
Check all resources: View logs if needed: kubectl logs -n plane -l app=plane-api
kubectl logs -n plane -l app=plane-worker
Access Plane
Depending on your ingress configuration:
With Ingress
Port Forward (Testing)
LoadBalancer
# Access via configured domain
open https://plane.example.com
Architecture on Kubernetes
Namespace : plane
├── Deployments
│ ├── plane-web (2 replicas)
│ ├── plane-space (1 replica)
│ ├── plane-admin (1 replica)
│ ├── plane-api (2 replicas)
│ ├── plane-worker (2 replicas)
│ ├── plane-beat-worker (1 replica)
│ └── plane-live (1 replica)
├── StatefulSets
│ ├── plane-postgresql (1 replica)
│ ├── plane-redis (1 replica)
│ ├── plane-rabbitmq (1 replica)
│ └── plane-minio (1 replica)
├── Services
│ ├── plane-proxy (LoadBalancer/ClusterIP)
│ ├── plane-api (ClusterIP)
│ ├── plane-postgresql (ClusterIP)
│ ├── plane-redis (ClusterIP)
│ ├── plane-rabbitmq (ClusterIP)
│ └── plane-minio (ClusterIP)
├── Jobs
│ └── plane-migrator (one-time)
├── PersistentVolumeClaims
│ ├── postgresql-data
│ ├── redis-data
│ ├── rabbitmq-data
│ └── minio-data
└── ConfigMaps & Secrets
├── plane-config
└── plane-secrets
Configuration
Using External PostgreSQL
For production, use a managed database service:
postgresql :
enabled : false # Disable bundled PostgreSQL
env :
database_url : "postgresql://user:password@your-db-host:5432/plane"
postgres_host : "your-db-host"
postgres_port : "5432"
postgres_user : "plane"
postgres_password : "your-password"
postgres_db : "plane"
Using External Redis
redis :
enabled : false # Disable bundled Redis
env :
redis_host : "your-redis-host"
redis_port : "6379"
redis_url : "redis://your-redis-host:6379/"
Using AWS S3 for Storage
minio :
enabled : false # Disable MinIO
env :
use_minio : "0"
aws_region : "us-east-1"
aws_access_key_id : "your-access-key"
aws_secret_access_key : "your-secret-key"
aws_s3_endpoint_url : "https://s3.amazonaws.com"
aws_s3_bucket_name : "plane-uploads"
Ingress Configuration
NGINX Ingress
ingress :
enabled : true
className : nginx
host : plane.example.com
annotations :
cert-manager.io/cluster-issuer : "letsencrypt-prod"
nginx.ingress.kubernetes.io/proxy-body-size : "10m"
tls :
enabled : true
secretName : plane-tls
Traefik Ingress
ingress :
enabled : true
className : traefik
host : plane.example.com
annotations :
traefik.ingress.kubernetes.io/router.entrypoints : websecure
traefik.ingress.kubernetes.io/router.tls : "true"
tls :
enabled : true
secretName : plane-tls
SSL/TLS with cert-manager
Install cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
Create ClusterIssuer
apiVersion : cert-manager.io/v1
kind : ClusterIssuer
metadata :
name : letsencrypt-prod
spec :
acme :
server : https://acme-v02.api.letsencrypt.org/directory
email : admin@example.com
privateKeySecretRef :
name : letsencrypt-prod
solvers :
- http01 :
ingress :
class : nginx
Apply: kubectl apply -f letsencrypt-prod.yaml
Update Ingress
Update your values.yaml: ingress :
annotations :
cert-manager.io/cluster-issuer : "letsencrypt-prod"
Upgrade release: helm upgrade plane makeplane/plane-ce -n plane -f values.yaml
Scaling
Manual Scaling
Scale deployments directly:
# Scale API servers
kubectl scale deployment -n plane plane-api --replicas=4
# Scale workers
kubectl scale deployment -n plane plane-worker --replicas=3
Or update values.yaml and upgrade:
api :
replicaCount : 4
worker :
replicaCount : 3
helm upgrade plane makeplane/plane-ce -n plane -f values.yaml
Horizontal Pod Autoscaling (HPA)
Create HPA for API pods:
apiVersion : autoscaling/v2
kind : HorizontalPodAutoscaler
metadata :
name : plane-api-hpa
namespace : plane
spec :
scaleTargetRef :
apiVersion : apps/v1
kind : Deployment
name : plane-api
minReplicas : 2
maxReplicas : 10
metrics :
- type : Resource
resource :
name : cpu
target :
type : Utilization
averageUtilization : 70
- type : Resource
resource :
name : memory
target :
type : Utilization
averageUtilization : 80
Apply:
kubectl apply -f api-hpa.yaml
Upgrading
Always backup your data before upgrading.
Backup Data
Backup PVCs: # Create snapshots or backup using your storage provider
kubectl get pvc -n plane
Update Helm Repository
helm repo update makeplane
Check New Version
helm search repo makeplane/plane-ce --versions
Upgrade Release
helm upgrade plane makeplane/plane-ce \
--namespace plane \
--values values.yaml \
--timeout 10m
Monitor rollout: kubectl rollout status deployment/plane-api -n plane
kubectl rollout status deployment/plane-worker -n plane
Monitoring
Resource Usage
# Pod resource usage
kubectl top pods -n plane
# Node resource usage
kubectl top nodes
Logs
# Stream logs from all API pods
kubectl logs -n plane -l app=plane-api -f
# View logs from specific pod
kubectl logs -n plane plane-api-7d8f9c5b6-xyz12
# Previous container logs (if crashed)
kubectl logs -n plane plane-api-7d8f9c5b6-xyz12 --previous
Events
# Recent events in namespace
kubectl get events -n plane --sort-by= '.lastTimestamp'
# Events for specific pod
kubectl describe pod -n plane plane-api-7d8f9c5b6-xyz12
Troubleshooting
Pods Not Starting
# Check pod status
kubectl get pods -n plane
# Describe pod for events
kubectl describe pod -n plane < pod-nam e >
# Check logs
kubectl logs -n plane < pod-nam e >
Common issues:
ImagePullBackOff : Check image name and registry access
CrashLoopBackOff : Check logs for application errors
Pending : Check resource availability and PVC binding
Database Connection Issues
# Test database connectivity
kubectl run -it --rm debug --image=postgres:15 --restart=Never -n plane -- \
psql -h plane-postgresql -U plane -d plane
# Check PostgreSQL logs
kubectl logs -n plane -l app=postgresql
PVC Not Binding
# Check PVC status
kubectl get pvc -n plane
# Describe PVC for events
kubectl describe pvc -n plane < pvc-nam e >
# Check available storage classes
kubectl get storageclass
Ingress Not Working
# Check ingress status
kubectl get ingress -n plane
# Describe ingress
kubectl describe ingress -n plane plane-ingress
# Check ingress controller logs
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx
Backup and Disaster Recovery
Using Velero
Install Velero for cluster backups:
# Install Velero
helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts
helm install velero vmware-tanzu/velero --namespace velero --create-namespace
# Backup Plane namespace
velero backup create plane-backup --include-namespaces plane
# Schedule daily backups
velero schedule create plane-daily --schedule= "0 2 * * *" --include-namespaces plane
Manual PVC Backup
# Create a backup job for PostgreSQL
kubectl apply -f - << EOF
apiVersion: batch/v1
kind: Job
metadata:
name: postgres-backup
namespace: plane
spec:
template:
spec:
containers:
- name: backup
image: postgres:15
command: ["/bin/sh", "-c"]
args:
- pg_dump -h plane-postgresql -U plane -d plane > /backup/plane-$( date +%Y%m%d).sql
volumeMounts:
- name: backup-volume
mountPath: /backup
restartPolicy: Never
volumes:
- name: backup-volume
persistentVolumeClaim:
claimName: postgres-backup-pvc
EOF
Next Steps
Configuration Configure environment variables and integrations
Instance Admin Set up instance administration
Additional Resources