Kubernetes Deployment
Deploy Fluxbase on Kubernetes using Helm for production-grade, highly available infrastructure.
Overview
Section titled “Overview”Fluxbase provides an official Helm chart that includes:
- High availability with multiple replicas
- Horizontal Pod Autoscaling (HPA)
- PostgreSQL database (or external database support)
- Ingress with TLS/SSL support
- Prometheus metrics and ServiceMonitor
- Configurable resource limits
- Security contexts and RBAC
Helm Chart: deploy/helm/fluxbase
Prerequisites
Section titled “Prerequisites”- Kubernetes 1.19+
- Helm 3.2.0+
- kubectl configured
- Persistent Volume provisioner
- (Optional) Ingress controller (nginx, Traefik)
- (Optional) cert-manager for TLS certificates
Quick Start
Section titled “Quick Start”1. Install Helm Chart
Section titled “1. Install Helm Chart”# Add Fluxbase Helm repository (if published)helm repo add fluxbase https://charts.fluxbase.iohelm repo update
# Or use local chartcd deploy/helm
# Install with default valueshelm install my-fluxbase ./fluxbase
# Install in custom namespacehelm install my-fluxbase ./fluxbase \ --namespace fluxbase \ --create-namespace2. Verify Installation
Section titled “2. Verify Installation”# Check pod statuskubectl get pods -n fluxbase
# Expected output:# NAME READY STATUS RESTARTS AGE# my-fluxbase-xxxxx-xxxxx 1/1 Running 0 2m# my-fluxbase-postgresql-0 1/1 Running 0 2m
# Check servicekubectl get svc -n fluxbase
# Port-forward to test locallykubectl port-forward -n fluxbase svc/my-fluxbase 8080:8080
# Test health endpointcurl http://localhost:8080/health3. Get Connection Info
Section titled “3. Get Connection Info”# Get connection detailshelm status my-fluxbase -n fluxbase
# Get JWT secret (if auto-generated)kubectl get secret my-fluxbase -n fluxbase -o jsonpath='{.data.jwt-secret}' | base64 -dProduction Installation
Section titled “Production Installation”Create Values File
Section titled “Create Values File”Create production-values.yaml:
# Replica count (minimum 3 for HA)replicaCount: 3
# Image configurationimage: registry: ghcr.io repository: fluxbase-eu/fluxbase tag: "0.1.0" pullPolicy: IfNotPresent
# Fluxbase configurationconfig: database: host: my-postgres.example.com port: 5432 name: fluxbase user: fluxbase # Don't set password here - use existingSecret sslMode: require
server: port: 8080 host: "0.0.0.0"
jwt: # Don't set secret here - use existingSecret expirationMinutes: 60
storage: provider: s3 s3: bucket: fluxbase-production region: us-east-1 endpoint: "" # Leave empty for AWS S3
# Use external database (disable embedded PostgreSQL)postgresql: enabled: false
externalDatabase: host: my-postgres.example.com port: 5432 user: fluxbase password: "" # Use existingSecret database: fluxbase existingSecret: fluxbase-db-secret existingSecretPasswordKey: password
# Secrets (create separately)existingSecret: fluxbase-secrets
# Service configurationservice: type: ClusterIP ports: http: 8080
# Ingress configurationingress: enabled: true ingressClassName: nginx hostname: api.yourdomain.com path: / pathType: Prefix tls: true annotations: cert-manager.io/cluster-issuer: letsencrypt-prod nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/proxy-body-size: "2048m" nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
# Autoscalingautoscaling: enabled: true minReplicas: 3 maxReplicas: 10 targetCPU: 70 targetMemory: 80
# Resource limitsresources: requests: cpu: 500m memory: 1Gi limits: cpu: 2000m memory: 4Gi
# Pod securitypodSecurityContext: enabled: true fsGroup: 1001 fsGroupChangePolicy: Always
containerSecurityContext: enabled: true runAsUser: 1001 runAsGroup: 1001 runAsNonRoot: true privileged: false readOnlyRootFilesystem: false allowPrivilegeEscalation: false capabilities: drop: - ALL seccompProfile: type: RuntimeDefault
# Pod anti-affinity for HApodAntiAffinityPreset: soft
# Metricsmetrics: enabled: true serviceMonitor: enabled: true namespace: monitoring interval: 30s additionalLabels: prometheus: kube-prometheus
# Persistence (for local storage)persistence: enabled: false # Using S3, so disabled
# ProbeslivenessProbe: enabled: true initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3
readinessProbe: enabled: true initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3
startupProbe: enabled: true initialDelaySeconds: 0 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 30Create Secrets
Section titled “Create Secrets”# Create database secretkubectl create secret generic fluxbase-db-secret \ --namespace fluxbase \ --from-literal=password='your-postgres-password'
# Create Fluxbase secretskubectl create secret generic fluxbase-secrets \ --namespace fluxbase \ --from-literal=jwt-secret='your-jwt-secret-at-least-32-chars' \ --from-literal=database-password='your-postgres-password' \ --from-literal=s3-access-key-id='AKIAXXXXXXXXXXXXXXXX' \ --from-literal=s3-secret-access-key='your-aws-secret-key'Install with Custom Values
Section titled “Install with Custom Values”helm install fluxbase ./fluxbase \ --namespace fluxbase \ --create-namespace \ --values production-values.yamlConfiguration Options
Section titled “Configuration Options”Full values.yaml Reference
Section titled “Full values.yaml Reference”See values.yaml for all available options.
Key sections:
| Section | Description | Default |
|---|---|---|
replicaCount | Number of Fluxbase pods | 3 |
image | Container image configuration | ghcr.io/fluxbase-eu/fluxbase:latest |
config.database | Database connection settings | PostgreSQL defaults |
config.server | HTTP server settings | Port 8080 |
config.jwt | JWT authentication settings | 60 min expiry |
config.storage | Storage backend (local/s3) | local |
postgresql.enabled | Deploy PostgreSQL in cluster | true |
externalDatabase | External database settings | - |
ingress.enabled | Enable Ingress | false |
autoscaling.enabled | Enable HPA | false |
metrics.enabled | Expose Prometheus metrics | true |
persistence.enabled | Enable persistent storage | true |
Database Configuration
Section titled “Database Configuration”Option 1: Embedded PostgreSQL (Development/Testing)
Section titled “Option 1: Embedded PostgreSQL (Development/Testing)”postgresql: enabled: true auth: username: fluxbase password: fluxbase-dev database: fluxbase primary: persistence: enabled: true size: 8GiOption 2: External Managed Database (Production)
Section titled “Option 2: External Managed Database (Production)”postgresql: enabled: false
externalDatabase: host: my-postgres.rds.amazonaws.com port: 5432 user: fluxbase database: fluxbase existingSecret: fluxbase-db-secret existingSecretPasswordKey: passwordCreate the secret:
kubectl create secret generic fluxbase-db-secret \ --namespace fluxbase \ --from-literal=password='production-db-password'Option 3: PostgreSQL Operator (CloudNativePG)
Section titled “Option 3: PostgreSQL Operator (CloudNativePG)”# Install CloudNativePG operator firsthelm repo add cnpg https://cloudnative-pg.github.io/chartshelm install cnpg cnpg/cloudnative-pg --namespace cnpg-system --create-namespace
# Create PostgreSQL clusterapiVersion: postgresql.cnpg.io/v1kind: Clustermetadata: name: fluxbase-postgres namespace: fluxbasespec: instances: 3 primaryUpdateStrategy: unsupervised
postgresql: parameters: shared_buffers: 256MB max_connections: "300" shared_preload_libraries: "pg_stat_statements"
bootstrap: initdb: database: fluxbase owner: fluxbase secret: name: fluxbase-db-secret
storage: size: 100Gi storageClass: fast-ssd
backup: barmanObjectStore: destinationPath: s3://backups/postgresql s3Credentials: accessKeyId: name: aws-creds key: ACCESS_KEY_ID secretAccessKey: name: aws-creds key: SECRET_ACCESS_KEY retentionPolicy: "30d"Ingress Configuration
Section titled “Ingress Configuration”Nginx Ingress with cert-manager
Section titled “Nginx Ingress with cert-manager”ingress: enabled: true ingressClassName: nginx hostname: api.example.com path: / tls: true annotations: # SSL/TLS cert-manager.io/cluster-issuer: letsencrypt-prod nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
# CORS (if needed) nginx.ingress.kubernetes.io/enable-cors: "true" nginx.ingress.kubernetes.io/cors-allow-origin: "https://app.example.com"
# Upload limits nginx.ingress.kubernetes.io/proxy-body-size: "2048m"
# Timeouts nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
# Rate limiting nginx.ingress.kubernetes.io/limit-rps: "100"
# WebSocket support nginx.ingress.kubernetes.io/proxy-http-version: "1.1" nginx.ingress.kubernetes.io/websocket-services: "my-fluxbase"Install cert-manager
Section titled “Install cert-manager”# Install cert-managerkubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
# Create ClusterIssuercat <<EOF | kubectl apply -f -apiVersion: cert-manager.io/v1kind: ClusterIssuermetadata: name: letsencrypt-prodspec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: admin@example.com privateKeySecretRef: name: letsencrypt-prod solvers: - http01: ingress: class: nginxEOFTraefik Ingress
Section titled “Traefik Ingress”ingress: enabled: true ingressClassName: traefik hostname: api.example.com annotations: traefik.ingress.kubernetes.io/router.tls: "true" traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt traefik.ingress.kubernetes.io/router.middlewares: default-compress@kubernetescrdAutoscaling
Section titled “Autoscaling”Horizontal Pod Autoscaler (HPA)
Section titled “Horizontal Pod Autoscaler (HPA)”autoscaling: enabled: true minReplicas: 3 maxReplicas: 20 targetCPU: 70 targetMemory: 80Verify HPA:
kubectl get hpa -n fluxbase# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS# my-fluxbase Deployment/my-fluxbase 45%/70%,50%/80% 3 20 3Custom Metrics (Advanced)
Section titled “Custom Metrics (Advanced)”autoscaling: enabled: true minReplicas: 3 maxReplicas: 20 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 - type: Pods pods: metric: name: http_requests_per_second target: type: AverageValue averageValue: "1000"Monitoring and Observability
Section titled “Monitoring and Observability”Prometheus Metrics
Section titled “Prometheus Metrics”metrics: enabled: true serviceMonitor: enabled: true namespace: monitoring interval: 30s scrapeTimeout: 10s additionalLabels: prometheus: kube-prometheusInstall Prometheus Stack
Section titled “Install Prometheus Stack”# Add Prometheus Helm repohelm repo add prometheus-community https://prometheus-community.github.io/helm-chartshelm repo update
# Install kube-prometheus-stackhelm install prometheus prometheus-community/kube-prometheus-stack \ --namespace monitoring \ --create-namespace \ --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=falseGrafana Dashboards
Section titled “Grafana Dashboards”Import pre-built Fluxbase dashboard (ID: TBD) or create custom:
apiVersion: v1kind: ConfigMapmetadata: name: fluxbase-dashboard namespace: monitoring labels: grafana_dashboard: "1"data: fluxbase.json: | { "dashboard": { "title": "Fluxbase Metrics", "panels": [ { "title": "Request Rate", "targets": [ { "expr": "rate(http_requests_total{job=\"fluxbase\"}[5m])" } ] } ] } }Logging with Loki
Section titled “Logging with Loki”# Install Loki stackhelm install loki grafana/loki-stack \ --namespace monitoring \ --set grafana.enabled=true \ --set promtail.enabled=trueAdd log annotation to pod:
podAnnotations: prometheus.io/scrape: "true" prometheus.io/port: "8080"Storage
Section titled “Storage”Local Storage (Development)
Section titled “Local Storage (Development)”persistence: enabled: true storageClass: "standard" accessModes: - ReadWriteOnce size: 8GiS3-Compatible Storage (Production)
Section titled “S3-Compatible Storage (Production)”config: storage: provider: s3 s3: bucket: fluxbase-production region: us-east-1 endpoint: "" # Empty for AWS S3
# Add S3 credentials to existingSecretexistingSecret: fluxbase-secrets# Secret should contain: s3-access-key-id, s3-secret-access-keyMinIO (Self-Hosted S3)
Section titled “MinIO (Self-Hosted S3)”# Install MinIOhelm install minio bitnami/minio \ --namespace fluxbase \ --set auth.rootUser=admin \ --set auth.rootPassword=minio-secret \ --set defaultBuckets=fluxbaseConfigure Fluxbase:
config: storage: provider: s3 s3: bucket: fluxbase region: us-east-1 endpoint: http://minio:9000High Availability Configuration
Section titled “High Availability Configuration”Multi-Zone Deployment
Section titled “Multi-Zone Deployment”# Pod anti-affinity to spread across zonespodAntiAffinityPreset: hard
affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app.kubernetes.io/name operator: In values: - fluxbase topologyKey: topology.kubernetes.io/zone
# Topology spread constraintstopologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app.kubernetes.io/name: fluxbasePod Disruption Budget
Section titled “Pod Disruption Budget”apiVersion: policy/v1kind: PodDisruptionBudgetmetadata: name: fluxbase-pdb namespace: fluxbasespec: minAvailable: 2 selector: matchLabels: app.kubernetes.io/name: fluxbaseDatabase High Availability
Section titled “Database High Availability”Use managed database with multi-AZ:
- AWS RDS Multi-AZ
- Google Cloud SQL HA
- Azure Database for PostgreSQL HA
Or PostgreSQL operator with replication:
# CloudNativePG cluster with 3 replicasspec: instances: 3 minSyncReplicas: 1 maxSyncReplicas: 2Security
Section titled “Security”Network Policies
Section titled “Network Policies”apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: fluxbase-network-policy namespace: fluxbasespec: podSelector: matchLabels: app.kubernetes.io/name: fluxbase policyTypes: - Ingress - Egress ingress: # Allow from ingress controller - from: - namespaceSelector: matchLabels: name: ingress-nginx ports: - protocol: TCP port: 8080 egress: # Allow to database - to: - podSelector: matchLabels: app.kubernetes.io/name: postgresql ports: - protocol: TCP port: 5432 # Allow DNS - to: - namespaceSelector: {} ports: - protocol: UDP port: 53 # Allow to internet (for external APIs) - to: - ipBlock: cidr: 0.0.0.0/0 except: - 169.254.169.254/32 # Block metadata servicePod Security Standards
Section titled “Pod Security Standards”apiVersion: v1kind: Namespacemetadata: name: fluxbase labels: pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/audit: restricted pod-security.kubernetes.io/warn: restrictedSecrets Management with External Secrets Operator
Section titled “Secrets Management with External Secrets Operator”# Install External Secrets Operatorhelm install external-secrets external-secrets/external-secrets \ --namespace external-secrets-system \ --create-namespaceConfigure AWS Secrets Manager integration:
apiVersion: external-secrets.io/v1beta1kind: SecretStoremetadata: name: aws-secrets-manager namespace: fluxbasespec: provider: aws: service: SecretsManager region: us-east-1 auth: jwt: serviceAccountRef: name: fluxbase
---apiVersion: external-secrets.io/v1beta1kind: ExternalSecretmetadata: name: fluxbase-secrets namespace: fluxbasespec: refreshInterval: 1h secretStoreRef: name: aws-secrets-manager kind: SecretStore target: name: fluxbase-secrets data: - secretKey: jwt-secret remoteRef: key: fluxbase/jwt-secret - secretKey: database-password remoteRef: key: fluxbase/database-passwordBackup and Disaster Recovery
Section titled “Backup and Disaster Recovery”Automated Backups with Velero
Section titled “Automated Backups with Velero”# Install Velerohelm install velero vmware-tanzu/velero \ --namespace velero \ --create-namespace \ --set configuration.provider=aws \ --set configuration.backupStorageLocation.bucket=backups \ --set configuration.backupStorageLocation.config.region=us-east-1
# Create backup schedulevelero schedule create fluxbase-daily \ --schedule="0 2 * * *" \ --include-namespaces fluxbase \ --ttl 720h0m0sDatabase Backups
Section titled “Database Backups”# Create CronJob for database backupsapiVersion: batch/v1kind: CronJobmetadata: name: postgres-backup namespace: fluxbasespec: schedule: "0 2 * * *" jobTemplate: spec: template: spec: containers: - name: backup image: postgres:18-alpine env: - name: PGHOST value: postgresql - name: PGUSER value: fluxbase - name: PGPASSWORD valueFrom: secretKeyRef: name: fluxbase-db-secret key: password command: - sh - -c - | pg_dump fluxbase | gzip > /backups/backup-$(date +%Y%m%d-%H%M%S).sql.gz volumeMounts: - name: backups mountPath: /backups volumes: - name: backups persistentVolumeClaim: claimName: postgres-backups restartPolicy: OnFailureUpgrading
Section titled “Upgrading”Rolling Update
Section titled “Rolling Update”# Update valueshelm upgrade fluxbase ./fluxbase \ --namespace fluxbase \ --values production-values.yaml
# Monitor rolloutkubectl rollout status deployment/fluxbase -n fluxbase
# Rollback if neededhelm rollback fluxbase -n fluxbaseBlue-Green Deployment
Section titled “Blue-Green Deployment”# Install new version alongside oldhelm install fluxbase-blue ./fluxbase \ --namespace fluxbase-blue \ --values production-values.yaml
# Test new versionkubectl port-forward -n fluxbase-blue svc/fluxbase-blue 8081:8080
# Switch traffic (update Ingress or Service)kubectl patch ingress fluxbase -n fluxbase \ --type json \ -p '[{"op": "replace", "path": "/spec/rules/0/http/paths/0/backend/service/name", "value": "fluxbase-blue"}]'
# Delete old version after verificationhelm uninstall fluxbase -n fluxbaseTroubleshooting
Section titled “Troubleshooting”Pod Not Starting
Section titled “Pod Not Starting”# Check pod statuskubectl describe pod <pod-name> -n fluxbase
# Check logskubectl logs <pod-name> -n fluxbase
# Check eventskubectl get events -n fluxbase --sort-by='.lastTimestamp'Database Connection Issues
Section titled “Database Connection Issues”# Test database connectivitykubectl run -it --rm debug --image=postgres:18-alpine --restart=Never -n fluxbase -- \ psql -h postgresql -U fluxbase -d fluxbase
# Check database servicekubectl get svc -n fluxbasekubectl describe svc postgresql -n fluxbaseIngress Not Working
Section titled “Ingress Not Working”# Check ingress statuskubectl describe ingress fluxbase -n fluxbase
# Check ingress controller logskubectl logs -n ingress-nginx deployment/ingress-nginx-controller
# Verify TLS certificatekubectl get certificate -n fluxbasekubectl describe certificate fluxbase-tls -n fluxbaseNext Steps
Section titled “Next Steps”- Production Checklist - Pre-deployment verification
- Scaling Guide - Performance optimization
- Docker Deployment - Alternative deployment method