Documentation Index
Fetch the complete documentation index at: https://sure-917046f5-docs-backup-restore-clarity.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
This guide shows you how to deploy Sure on Kubernetes using the official Helm chart. The chart supports web (Rails) and worker (Sidekiq) workloads, optional in-cluster PostgreSQL and Redis, and production-grade features like pre-upgrade migrations, pod security contexts, and horizontal pod autoscaling.
Prerequisites
- Kubernetes >= 1.25
- Helm >= 3.10
- Basic familiarity with Kubernetes and Helm
Features
- Web (Rails) deployment with service and optional ingress
- Worker (Sidekiq) deployment
- Optional database migrations via Helm hook job or initContainer
- Optional subcharts for PostgreSQL (CloudNativePG) and Redis (OT-CONTAINER-KIT redis-operator)
- Security best practices: runAsNonRoot, readOnlyRootFilesystem, no hardcoded secrets
- Scalability: replicas, resources, topology spread constraints, optional HPAs
- Optional CronJobs for custom tasks
Installation
Add Helm repositories
Add the Sure Helm repository:
helm repo add sure https://we-promise.github.io/sure
helm repo update
If you plan to use the bundled PostgreSQL or Redis subcharts, add their repositories as well:
helm repo add cloudnative-pg https://cloudnative-pg.github.io/charts
helm repo add ot-helm https://ot-container-kit.github.io/helm-charts
helm repo update
Quickstart (turnkey self-hosting)
This installs CloudNativePG operator with a Postgres cluster and Redis managed by the OT redis-operator.
For production stability, use immutable image tags (for example, image.tag=v1.2.3) instead of latest.
Do not pass production secrets with --set on the command line. Use a values file with restricted permissions or a Kubernetes Secret as described in Secrets management.
# Create namespace
kubectl create ns sure || true
# Create a values file for the initial secret
SECRET_KEY_BASE=$(openssl rand -hex 32)
cat > values-quickstart.yaml <<EOF
image:
tag: v1.2.3
rails:
secret:
enabled: true
values:
SECRET_KEY_BASE: "$SECRET_KEY_BASE"
EOF
chmod 600 values-quickstart.yaml
# Install chart with a pinned image tag
helm upgrade --install sure sure/sure \
-n sure \
-f values-quickstart.yaml
Expose the app via an ingress (see configuration below) or port-forward:
kubectl port-forward svc/sure 8080:80 -n sure
Navigate to http://localhost:8080 to access Sure.
Configuration
Using external Postgres and Redis
To use external managed databases instead of the bundled subcharts, store connection strings in a Kubernetes Secret and reference them from your values file. See Secrets management for the general pattern.
cnpg:
enabled: false
redisOperator:
managed:
enabled: false
redisSimple:
enabled: false
rails:
extraEnv:
DATABASE_URL:
valueFrom:
secretKeyRef:
name: external-db-credentials
key: database-url
REDIS_URL:
valueFrom:
secretKeyRef:
name: external-db-credentials
key: redis-url
Deployment profiles
Simple single-node
Minimal setup for development or small deployments:
encryptionEnv.enabled: true tells the chart to wire the Active Record encryption keys from your secret into the app container.
SELF_HOSTED: "true" enables self-hosted behavior inside Sure.
- Replace
longhorn with a storage class that exists in your cluster.
image:
repository: ghcr.io/we-promise/sure
tag: "v1.0.0"
pullPolicy: IfNotPresent
rails:
existingSecret: sure-secrets
encryptionEnv:
enabled: true
settings:
SELF_HOSTED: "true"
cnpg:
enabled: true
cluster:
enabled: true
name: sure-db
instances: 1
storage:
size: 8Gi
storageClassName: longhorn
redisOperator:
enabled: true
managed:
enabled: true
mode: standalone
replicas: 1
persistence:
enabled: true
className: longhorn
size: 8Gi
migrations:
strategy: job
HA k3s profile
High availability setup with multiple replicas and synchronous replication:
cnpg:
enabled: true
cluster:
enabled: true
name: sure-db
instances: 3
storage:
size: 20Gi
storageClassName: longhorn
minSyncReplicas: 1
maxSyncReplicas: 2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
cnpg.io/cluster: sure-db
redisOperator:
enabled: true
managed:
enabled: true
mode: replication
replicas: 3
persistence:
enabled: true
className: longhorn
size: 8Gi
migrations:
strategy: job
initContainer:
enabled: true
hpa:
web:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
Secrets management
Generate strong secrets before creating the Kubernetes Secret:
openssl rand -hex 32 # SECRET_KEY_BASE
openssl rand -hex 32 # ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
openssl rand -hex 32 # ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY
openssl rand -hex 32 # redis-password
openssl rand -hex 64 # ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT
Create a Kubernetes secret with the required credentials:
apiVersion: v1
kind: Secret
metadata:
name: sure-secrets
type: Opaque
stringData:
# Rails secrets
SECRET_KEY_BASE: "__SET_SECRET__"
# Active Record Encryption keys (required for self-hosted mode)
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: "__SET_SECRET__"
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: "__SET_SECRET__"
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: "__SET_SECRET__"
# Redis password
redis-password: "__SET_SECRET__"
# Optional external service URLs
database-url: "postgresql://user:pass@db.example.com:5432/sure"
redis-url: "redis://:pass@redis.example.com:6379/0"
Apply the secret:
kubectl apply -f sure-secrets.yaml -n sure
Reference the secret in your values:
rails:
existingSecret: sure-secrets
redisOperator:
managed:
enabled: true
auth:
existingSecret: sure-secrets
passwordKey: redis-password
Ingress configuration
Enable ingress to expose Sure externally:
ingress:
enabled: true
className: "nginx"
hosts:
- host: finance.example.com
paths:
- path: /
pathType: Prefix
tls:
- hosts: [finance.example.com]
secretName: finance-tls
Horizontal pod autoscaling
Enable HPAs for automatic scaling based on CPU utilization:
hpa:
web:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
worker:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
Updating
To update to a new version of Sure:
# Update the Helm repository
helm repo update sure
# Update the deployment with a new image tag
helm upgrade sure sure/sure -n sure \
--set image.tag=v1.2.4 \
-f your-values.yaml
The chart will automatically run database migrations before deploying the new version.
Backup and restore
These steps cover PostgreSQL backups and restore. They do not automatically back up or restore uploaded files if your deployment stores them outside PostgreSQL.
PostgreSQL backups with CloudNativePG
CloudNativePG supports volume snapshot backups:
cnpg:
cluster:
backup:
method: volumeSnapshot
volumeSnapshot:
className: longhorn
Manual backup
Create a manual backup of your PostgreSQL database:
# Get the primary pod name
PRIMARY_POD=$(kubectl get pod -n sure -l cnpg.io/cluster=sure-db,role=primary -o name)
# Create a backup
kubectl exec -n sure $PRIMARY_POD -- pg_dump -U sure sure_production > backup.sql
[!NOTE]
If you customized the PostgreSQL username or database name in your chart values, replace sure and sure_production in the backup and restore commands below.
Restore from backup
-
Make sure app traffic is stopped or the deployment is in maintenance mode.
-
Copy the SQL backup to the primary PostgreSQL pod:
kubectl cp backup.sql sure/$PRIMARY_POD:/tmp/backup.sql
- Restore the database:
kubectl exec -n sure $PRIMARY_POD -- psql -U sure sure_production -f /tmp/backup.sql
-
If your deployment uses uploaded files stored outside PostgreSQL, restore those separately using the matching volume snapshot or object-storage recovery process.
-
Verify that the app starts cleanly and your data appears as expected.
Troubleshooting
View logs
# Web logs
kubectl logs -n sure -l app.kubernetes.io/component=web
# Worker logs
kubectl logs -n sure -l app.kubernetes.io/component=worker
# Migration job logs
kubectl logs -n sure -l job-name=sure-migrate
Check pod status
Verify database connectivity
# Test connection from web pod
kubectl exec -n sure deploy/sure-web -- rails runner "puts ActiveRecord::Base.connection.execute('SELECT 1').first"
Run Helm tests
After installation, verify the deployment:
Uninstall
To remove Sure from your cluster:
helm uninstall sure -n sure
This will not delete PersistentVolumeClaims. Before deleting PVCs, make sure the namespace does not contain volumes for anything other than Sure.
kubectl get pvc -n sure
kubectl delete pvc -n sure <sure-pvc-name>
Getting help
If you find bugs or have feature requests: