Autoscaling
    Kubernetes

    Deploy KEDA on Kubernetes

    Install KEDA for event-driven autoscaling on a Kubernetes cluster running on RamNode VPS nodes — queue, Prometheus, and cron scalers with scale-to-zero.

    KEDA (Kubernetes Event-Driven Autoscaling) extends the standard Horizontal Pod Autoscaler with event-source-driven scaling — including scale-to-zero. This guide covers install and a few scaler patterns commonly useful on a VPS cluster (queue-driven jobs, metrics-driven web scaling, cron-based batch work).

    Assumption: same cluster as the Longhorn guide — kubeadm on RamNode KVM VPS nodes, kubectl/helm from the jump host.


    1. Prerequisites

    • Kubernetes 1.27+
    • metrics-server installed (KEDA works alongside standard HPA metrics)
    shell
    kubectl get deployment metrics-server -n kube-system

    If it's missing:

    shell
    helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/
    helm install metrics-server metrics-server/metrics-server -n kube-system

    2. Install KEDA (Helm)

    shell
    helm repo add kedacore https://kedacore.github.io/charts
    helm repo update
    
    kubectl create namespace keda
    
    helm install keda kedacore/keda \
      --namespace keda \
      --set resources.operator.requests.cpu=100m \
      --set resources.operator.requests.memory=100Mi

    Verify:

    shell
    kubectl -n keda get pods
    # expect: keda-operator, keda-operator-metrics-apiserver, keda-admission-webhooks

    3. Core concepts (quick reference)

    • ScaledObject — attaches a scaler to an existing Deployment/StatefulSet.
    • ScaledJob — creates Kubernetes Jobs per event, good for batch/queue work that isn't a long-running service (e.g., one-shot migration or export scripts).
    • TriggerAuthentication — holds credentials for a scaler (API keys, connection strings) as a Secret reference.

    4. Example: scale a queue-consumer deployment (RabbitMQ)

    If you run job queues through RabbitMQ:

    shell
    apiVersion: keda.sh/v1alpha1
    kind: TriggerAuthentication
    metadata:
      name: rabbitmq-auth
      namespace: default
    spec:
      secretTargetRef:
        - parameter: host
          name: rabbitmq-secret
          key: host
    ---
    apiVersion: keda.sh/v1alpha1
    kind: ScaledObject
    metadata:
      name: migration-worker-scaler
      namespace: default
    spec:
      scaleTargetRef:
        name: migration-worker        # your existing Deployment
      minReplicaCount: 0
      maxReplicaCount: 10
      cooldownPeriod: 60
      triggers:
        - type: rabbitmq
          metadata:
            queueName: migration-jobs
            mode: QueueLength
            value: "5"                # scale up 1 replica per 5 queued messages
          authenticationRef:
            name: rabbitmq-auth

    This scales the migration-worker Deployment from 0 up to 10 pods based on queue depth — useful if migration jobs are bursty rather than constant.


    5. Example: cron-based scaling for scheduled collectors

    For something like your capacity collector script that only needs to run on a schedule rather than continuously:

    shell
    apiVersion: keda.sh/v1alpha1
    kind: ScaledObject
    metadata:
      name: capacity-collector-cron
      namespace: default
    spec:
      scaleTargetRef:
        name: capacity-collector
      minReplicaCount: 0
      maxReplicaCount: 1
      triggers:
        - type: cron
          metadata:
            timezone: America/New_York
            start: 0 */6 * * *   # scale up at :00 every 6 hours
            end: 5 */6 * * *     # scale back down 5 min later
            desiredReplicas: "1"

    This is a cleaner alternative to a CronJob if the collector needs to stay a long-running Deployment for other reasons (e.g., shared connection pooling) but you don't want it running 24/7.


    6. Example: Prometheus-driven scaling

    If Nagios/NRPE metrics or app metrics are exported to Prometheus, you can scale directly off a PromQL query:

    shell
    apiVersion: keda.sh/v1alpha1
    kind: ScaledObject
    metadata:
      name: web-app-scaler
      namespace: default
    spec:
      scaleTargetRef:
        name: web-app
      minReplicaCount: 1
      maxReplicaCount: 6
      triggers:
        - type: prometheus
          metadata:
            serverAddress: http://prometheus.monitoring.svc:9090
            metricName: http_requests_per_second
            query: sum(rate(http_requests_total{app="web-app"}[2m]))
            threshold: "50"

    7. ScaledJob pattern (one-shot batch work)

    For work that's genuinely job-shaped (run once per event, then exit) rather than a long-lived service:

    shell
    apiVersion: keda.sh/v1alpha1
    kind: ScaledJob
    metadata:
      name: solusvm-export-job
    spec:
      jobTargetRef:
        template:
          spec:
            containers:
              - name: export
                image: registry.internal/solusvm-export:latest
            restartPolicy: Never
      pollingInterval: 30
      maxReplicaCount: 3
      triggers:
        - type: rabbitmq
          metadata:
            queueName: export-jobs
            mode: QueueLength
            value: "1"

    Each queued export request spins up its own isolated Job pod, which is useful if the Python 2.7-compatible export script needs isolation from other runs.


    8. Verification checklist

    shell
    kubectl -n keda get pods                      # operator + webhook running
    kubectl get scaledobjects -A                  # your ScaledObjects listed
    kubectl describe scaledobject <name>          # check "Active" and "Ready" conditions
    kubectl get hpa                               # KEDA creates a backing HPA per ScaledObject

    Send a test event (queue message, or wait for a cron window) and confirm pod count changes:

    shell
    kubectl get pods -w

    9. Notes

    • KEDA does not replace metrics-server/HPA — it creates and manages HPA objects on your behalf, so both need to be healthy.
    • Scale-to-zero only works for Deployments/StatefulSets fronted by something tolerant of a cold start (add a small activationCooldownPeriod if downstream services are latency-sensitive).
    • If regions run separate clusters (per the Longhorn guide's recommendation), install KEDA independently per-region cluster — it's not cluster-spanning.