Skip to main content

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

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

Next: Environment Variables - Complete configuration reference.