Kubernetes Deployment
Deploy FireBackup Enterprise on Kubernetes using Helm charts. This guide covers production-grade deployments with high availability, autoscaling, and monitoring.
Prerequisites
- Kubernetes 1.27+
- Helm 3.12+
- kubectl configured for your cluster
- PostgreSQL 14+ (managed or self-hosted)
- Redis 7.0+ (managed or self-hosted)
- Valid FireBackup license key
Quick Start
1. Add Helm Repository
helm repo add firebackup https://charts.firebackup.io
helm repo update
2. Create Namespace
kubectl create namespace firebackup
3. Create Secrets
# Database credentials
kubectl create secret generic firebackup-db \
--namespace firebackup \
--from-literal=url='postgresql://user:password@postgres:5432/firebackup'
# Application secrets
kubectl create secret generic firebackup-secrets \
--namespace firebackup \
--from-literal=jwt-secret=$(openssl rand -hex 32) \
--from-literal=encryption-key=$(openssl rand -hex 32)
# Google OAuth
kubectl create secret generic firebackup-oauth \
--namespace firebackup \
--from-literal=client-id='YOUR_CLIENT_ID' \
--from-literal=client-secret='YOUR_CLIENT_SECRET'
# License
kubectl create secret generic firebackup-license \
--namespace firebackup \
--from-literal=key='fb_lic_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
4. Install Chart
helm install firebackup firebackup/firebackup \
--namespace firebackup \
--values values.yaml
5. Verify Installation
kubectl get pods -n firebackup
kubectl get services -n firebackup
Helm Chart Configuration
Basic values.yaml
# ===========================================
# FireBackup Enterprise Helm Values
# ===========================================
global:
# Your domain
domain: firebackup.example.com
# Image settings
image:
repository: firebackup
pullPolicy: IfNotPresent
tag: "latest"
# Use existing secrets
existingSecrets:
database: firebackup-db
application: firebackup-secrets
oauth: firebackup-oauth
license: firebackup-license
# API Server
api:
replicaCount: 2
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
service:
type: ClusterIP
port: 4000
# Web Dashboard
web:
replicaCount: 2
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
service:
type: ClusterIP
port: 80
# Backup Worker
backupWorker:
replicaCount: 3
resources:
requests:
cpu: 1000m
memory: 1Gi
limits:
cpu: 4000m
memory: 4Gi
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 20
targetCPUUtilizationPercentage: 60
# PITR Worker
pitrWorker:
replicaCount: 1
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
# Ingress
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: "300"
hosts:
- host: firebackup.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: firebackup-tls
hosts:
- firebackup.example.com
# PostgreSQL (if using bundled)
postgresql:
enabled: false # Use external database
# Redis (if using bundled)
redis:
enabled: true
architecture: standalone
auth:
enabled: true
existingSecret: firebackup-redis
existingSecretPasswordKey: password
master:
persistence:
size: 10Gi
# Monitoring
metrics:
enabled: true
serviceMonitor:
enabled: true
namespace: monitoring
Production values.yaml
# ===========================================
# FireBackup Enterprise Production Values
# ===========================================
global:
domain: firebackup.example.com
image:
repository: firebackup
pullPolicy: Always
tag: "v1.5.0" # Pin to specific version
existingSecrets:
database: firebackup-db
application: firebackup-secrets
oauth: firebackup-oauth
license: firebackup-license
# API Server - High Availability
api:
replicaCount: 3
resources:
requests:
cpu: 1000m
memory: 1Gi
limits:
cpu: 4000m
memory: 4Gi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 15
targetCPUUtilizationPercentage: 65
targetMemoryUtilizationPercentage: 80
podDisruptionBudget:
enabled: true
minAvailable: 2
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/component
operator: In
values:
- api
topologyKey: kubernetes.io/hostname
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/component: api
# Web Dashboard
web:
replicaCount: 2
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
podDisruptionBudget:
enabled: true
minAvailable: 1
# Backup Worker - Scale based on queue
backupWorker:
replicaCount: 5
resources:
requests:
cpu: 2000m
memory: 2Gi
limits:
cpu: 8000m
memory: 8Gi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 50
targetCPUUtilizationPercentage: 50
# Scale based on Redis queue length
customMetrics:
- type: External
external:
metric:
name: redis_queue_length
selector:
matchLabels:
queue: backups
target:
type: AverageValue
averageValue: 5
persistence:
enabled: true
size: 100Gi
storageClass: fast-ssd
# PITR Worker
pitrWorker:
replicaCount: 2
resources:
requests:
cpu: 1000m
memory: 1Gi
limits:
cpu: 4000m
memory: 4Gi
persistence:
enabled: true
size: 100Gi
storageClass: fast-ssd
# Ingress with advanced configuration
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-body-size: "1g"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
nginx.ingress.kubernetes.io/limit-rps: "50"
nginx.ingress.kubernetes.io/limit-connections: "100"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "X-Frame-Options: SAMEORIGIN";
more_set_headers "X-Content-Type-Options: nosniff";
more_set_headers "Strict-Transport-Security: max-age=31536000; includeSubDomains";
hosts:
- host: firebackup.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: firebackup-tls
hosts:
- firebackup.example.com
# Redis HA
redis:
enabled: true
architecture: replication
auth:
enabled: true
existingSecret: firebackup-redis
master:
persistence:
size: 20Gi
storageClass: fast-ssd
replica:
replicaCount: 2
persistence:
size: 20Gi
storageClass: fast-ssd
sentinel:
enabled: true
# Monitoring
metrics:
enabled: true
serviceMonitor:
enabled: true
namespace: monitoring
interval: 30s
scrapeTimeout: 10s
# Pod Security
podSecurityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
# Node selection
nodeSelector:
kubernetes.io/os: linux
tolerations: []
Kubernetes Resources
API Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: firebackup-api
namespace: firebackup
labels:
app.kubernetes.io/name: firebackup
app.kubernetes.io/component: api
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: firebackup
app.kubernetes.io/component: api
template:
metadata:
labels:
app.kubernetes.io/name: firebackup
app.kubernetes.io/component: api
spec:
serviceAccountName: firebackup
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: api
image: firebackup/api:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 4000
protocol: TCP
env:
- name: NODE_ENV
value: production
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: firebackup-db
key: url
- name: REDIS_URL
valueFrom:
secretKeyRef:
name: firebackup-redis
key: url
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: firebackup-secrets
key: jwt-secret
- name: ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: firebackup-secrets
key: encryption-key
- name: GOOGLE_CLIENT_ID
valueFrom:
secretKeyRef:
name: firebackup-oauth
key: client-id
- name: GOOGLE_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: firebackup-oauth
key: client-secret
- name: LICENSE_KEY
valueFrom:
secretKeyRef:
name: firebackup-license
key: key
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
volumeMounts:
- name: data
mountPath: /app/data
- name: tmp
mountPath: /tmp
volumes:
- name: data
emptyDir: {}
- name: tmp
emptyDir: {}
Backup Worker Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: firebackup-worker
namespace: firebackup
labels:
app.kubernetes.io/name: firebackup
app.kubernetes.io/component: backup-worker
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: firebackup
app.kubernetes.io/component: backup-worker
template:
metadata:
labels:
app.kubernetes.io/name: firebackup
app.kubernetes.io/component: backup-worker
spec:
serviceAccountName: firebackup
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: worker
image: firebackup/api:latest
imagePullPolicy: Always
command: ["node", "dist/worker.js"]
env:
- name: NODE_ENV
value: production
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: firebackup-db
key: url
- name: REDIS_URL
valueFrom:
secretKeyRef:
name: firebackup-redis
key: url
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: firebackup-secrets
key: jwt-secret
- name: ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: firebackup-secrets
key: encryption-key
- name: LICENSE_KEY
valueFrom:
secretKeyRef:
name: firebackup-license
key: key
resources:
requests:
cpu: 1000m
memory: 1Gi
limits:
cpu: 4000m
memory: 4Gi
volumeMounts:
- name: data
mountPath: /app/data
- name: tmp
mountPath: /tmp
volumes:
- name: data
persistentVolumeClaim:
claimName: firebackup-worker-data
- name: tmp
emptyDir:
sizeLimit: 10Gi
HorizontalPodAutoscaler
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: firebackup-api
namespace: firebackup
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: firebackup-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
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
PodDisruptionBudget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: firebackup-api
namespace: firebackup
spec:
minAvailable: 2
selector:
matchLabels:
app.kubernetes.io/name: firebackup
app.kubernetes.io/component: api
Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: firebackup
namespace: firebackup
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-body-size: "500m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
spec:
ingressClassName: nginx
tls:
- hosts:
- firebackup.example.com
secretName: firebackup-tls
rules:
- host: firebackup.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: firebackup-api
port:
number: 4000
- path: /socket.io
pathType: Prefix
backend:
service:
name: firebackup-api
port:
number: 4000
- path: /
pathType: Prefix
backend:
service:
name: firebackup-web
port:
number: 80
Database Setup
External PostgreSQL (Recommended)
AWS RDS
# values.yaml
postgresql:
enabled: false
api:
extraEnv:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: firebackup-db
key: url
Create the secret:
kubectl create secret generic firebackup-db \
--namespace firebackup \
--from-literal=url='postgresql://admin:password@firebackup.xxxxx.us-east-1.rds.amazonaws.com:5432/firebackup?sslmode=require'
Google Cloud SQL
# Use Cloud SQL Proxy sidecar
api:
extraContainers:
- name: cloud-sql-proxy
image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.6.1
args:
- "--structured-logs"
- "--port=5432"
- "project:region:instance"
securityContext:
runAsNonRoot: true
resources:
requests:
memory: "256Mi"
cpu: "100m"
Bundled PostgreSQL
For testing or small deployments:
postgresql:
enabled: true
auth:
database: firebackup
existingSecret: firebackup-db-credentials
primary:
persistence:
size: 50Gi
storageClass: standard
SSL/TLS Configuration
cert-manager with Let's Encrypt
# 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
Custom Certificates
kubectl create secret tls firebackup-tls \
--namespace firebackup \
--cert=fullchain.pem \
--key=privkey.pem
Monitoring & Observability
Prometheus ServiceMonitor
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: firebackup
namespace: monitoring
labels:
app.kubernetes.io/name: firebackup
spec:
selector:
matchLabels:
app.kubernetes.io/name: firebackup
namespaceSelector:
matchNames:
- firebackup
endpoints:
- port: metrics
path: /metrics
interval: 30s
scrapeTimeout: 10s
Grafana Dashboard
Import dashboard ID 12345 from Grafana.com or use the provided JSON:
kubectl create configmap firebackup-dashboard \
--namespace monitoring \
--from-file=dashboard.json
Logging with Fluentd
apiVersion: v1
kind: ConfigMap
metadata:
name: fluentd-config
namespace: logging
data:
firebackup.conf: |
<match kubernetes.var.log.containers.firebackup-**>
@type elasticsearch
host elasticsearch.logging.svc
port 9200
logstash_format true
logstash_prefix firebackup
</match>
Backup & Disaster Recovery
Velero Backup
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: firebackup-daily
namespace: velero
spec:
schedule: "0 2 * * *"
template:
includedNamespaces:
- firebackup
storageLocation: default
ttl: 720h # 30 days
Database Backup CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: firebackup-db-backup
namespace: firebackup
spec:
schedule: "0 */6 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: postgres:16-alpine
command:
- /bin/sh
- -c
- |
pg_dump $DATABASE_URL | gzip > /backup/db-$(date +%Y%m%d-%H%M%S).sql.gz
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: firebackup-db
key: url
volumeMounts:
- name: backup
mountPath: /backup
volumes:
- name: backup
persistentVolumeClaim:
claimName: firebackup-backups
restartPolicy: OnFailure
Troubleshooting
Check Pod Status
kubectl get pods -n firebackup
kubectl describe pod firebackup-api-xxx -n firebackup
View Logs
# API logs
kubectl logs -f deployment/firebackup-api -n firebackup
# Worker logs
kubectl logs -f deployment/firebackup-worker -n firebackup
# All pods
kubectl logs -f -l app.kubernetes.io/name=firebackup -n firebackup
Debug Pod
kubectl run debug --rm -it --image=alpine/curl -n firebackup -- sh
# Test API
curl http://firebackup-api:4000/health
# Test database
apk add postgresql-client
psql $DATABASE_URL -c "SELECT 1"
Common Issues
Pods in CrashLoopBackOff
# Check logs
kubectl logs firebackup-api-xxx -n firebackup --previous
# Common causes:
# - Database not accessible
# - Invalid secrets
# - Resource limits too low
Database Connection Timeout
# Verify network policy allows connection
kubectl get networkpolicy -n firebackup
# Check if database is reachable
kubectl run test-db --rm -it --image=postgres:16-alpine -n firebackup -- \
psql postgresql://user:pass@db-host:5432/firebackup -c "SELECT 1"
Worker Not Processing Jobs
# Check Redis connection
kubectl exec -it deployment/firebackup-worker -n firebackup -- \
redis-cli -u $REDIS_URL PING
# Check queue length
kubectl exec -it deployment/firebackup-worker -n firebackup -- \
redis-cli -u $REDIS_URL LLEN bull:backups:waiting
Upgrades
Upgrade Helm Release
# Update repo
helm repo update
# Check available versions
helm search repo firebackup --versions
# Upgrade
helm upgrade firebackup firebackup/firebackup \
--namespace firebackup \
--values values.yaml \
--version 1.6.0
# Verify
kubectl rollout status deployment/firebackup-api -n firebackup
Rollback
# Check history
helm history firebackup -n firebackup
# Rollback to previous
helm rollback firebackup -n firebackup
# Rollback to specific revision
helm rollback firebackup 3 -n firebackup
Security Checklist
- Network policies configured
- Pod security policies/standards applied
- Secrets encrypted at rest (EncryptionConfiguration)
- RBAC configured with least privilege
- TLS enabled for all endpoints
- Resource limits set
- Pod disruption budgets configured
- Regular security updates applied
- Audit logging enabled
Related
- System Requirements - Hardware requirements
- Docker Deployment - Docker installation
- Environment Variables - Configuration reference
- High Availability - HA configuration
Next: Environment Variables - Complete configuration reference.