Use event-driven scaling with a MongoDB event source

更新时间:
复制 MD 格式

For event-driven workloads such as offline jobs and streaming data, horizontal pod autoscaling based on CPU and memory may respond too slowly. ack-keda monitors event backlogs from sources such as message queues and databases, creates Jobs or Deployment replicas within seconds, and scales down to zero after tasks complete for efficient, real-time scheduling and cost optimization.

How it works

ack-keda is an enhanced version of KEDA (Kubernetes-based Event-driven Autoscaling) integrated with ACK. It introduces a Scaler that bridges event sources and applications.

image
  1. Monitor the event source: The Scaler connects to an external event source—such as MongoDB—and periodically queries a metric, for example, the count of documents matching certain conditions.

  2. Drive application scaling:

    • When the Scaler detects event backlog—for example, unprocessed data—ack-keda scales the workload tied to a ScaledJob or ScaledObject by creating a Job or adding Deployment replicas.

    • When the Scaler detects no backlog, ack-keda scales down the workload. For Jobs, it removes completed resources to prevent capacity waste and metadata buildup.

Key capabilities:

  • Broad event source support: Supports data sources such as Apache Kafka, MySQL, PostgreSQL, RabbitMQ, and MongoDB. See RabbitMQ Queue.

  • Flexible concurrency control: Use maxReplicaCount to cap concurrent tasks and protect downstream systems from traffic bursts.

  • Automatic metadata cleanup: After a task finishes, ScaledJob removes completed Jobs and pods, reducing API server pressure from metadata accumulation.

ScaledJob vs. ScaledObject

Use ScaledJob when each event maps to a discrete, long-running task that runs to completion in its own pod. ack-keda schedules one Job per event: it initializes, processes the event, and terminates. This isolation prevents slow tasks from blocking others and enables precise concurrency control with maxReplicaCount.

Use ScaledObject when events drive continuous throughput and your workload is best handled by a pool of long-running Deployment replicas.

The tutorial below uses ScaledJob for video transcoding. When a record with "state":"waiting" is inserted into MongoDB, ack-keda creates a Job to process the task and sets the record to "state":"finished" on completion. Finished Jobs are cleaned up automatically.

How it works

Prerequisites

Ensure the following:

  • An ACK cluster up and running

  • kubectl configured to connect to the cluster

  • Sufficient permissions to create namespaces and deploy Helm charts

Step 1: Deploy ack-keda

  1. On the ACK Clusters page, click your cluster name. In the left navigation pane, choose Applications > Helm.

  2. Click Create. Find and select ack-keda, choose the latest chart version, and complete the installation.

  3. Verify that ack-keda is running:

    kubectl get pods -n keda

    All pods should be in Running status before you proceed.

Step 2: Deploy the MongoDB event-driven autoscaling example

Create example namespaces

This example uses the mongodb namespace for the database and mongodb-test for autoscaling configurations.

kubectl create ns mongodb
kubectl create ns mongodb-test

Deploy MongoDB

If you already have a MongoDB service, skip this step.

  1. Create mongoDB.yaml.

    Important

    This MongoDB service is for demonstration only without high availability. Do not use it in production.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mongodb
      namespace: mongodb
    spec:
      replicas: 1
      selector:
        matchLabels:
          name: mongodb
      template:
        metadata:
          labels:
            name: mongodb
        spec:
          containers:
          - name: mongodb
            image: registry-cn-shanghai.ack.aliyuncs.com/acs/mongo:v5.0.0
            imagePullPolicy: IfNotPresent
            ports:
            - containerPort: 27017
              name: mongodb
              protocol: TCP
    ---
    kind: Service
    apiVersion: v1
    metadata:
      name: mongodb-svc
      namespace: mongodb
    spec:
      type: ClusterIP
      ports:
      - name: mongodb
        port: 27017
        targetPort: 27017
        protocol: TCP
      selector:
        name: mongodb
  2. Deploy MongoDB.

    kubectl apply -f mongoDB.yaml

Initialize the MongoDB database

  1. Get the MongoDB pod name.

    MONGO_POD_NAME=$(kubectl get pods -n mongodb -l name=mongodb -o jsonpath='{.items[0].metadata.name}')
    echo "MongoDB pod name: $MONGO_POD_NAME"
  2. In the test database, create user test_user and collection test_collection.

    # Create user
    kubectl exec -n mongodb ${MONGO_POD_NAME} -- mongo --eval 'db.createUser({ user:"test_user",pwd:"test_password",roles:[{ role:"readWrite", db: "test"}]})'
    
    # Authenticate user
    kubectl exec -n mongodb ${MONGO_POD_NAME} -- mongo --eval 'db.auth("test_user","test_password")'
    
    # Create collection
    kubectl exec -n mongodb ${MONGO_POD_NAME} -- mongo test --eval 'db.createCollection("test_collection")'

Configure TriggerAuthentication and ScaledJob

ack-keda uses TriggerAuthentication to securely manage event source credentials. ScaledJob defines scaling rules, polling intervals, and the Job template.

The following file combines all three resources—Secret, TriggerAuthentication, and ScaledJob.

  1. Create keda-mongodb.yaml. The secretTargetRef in TriggerAuthentication reads the connection string from the Secret for MongoDB authentication. The query in ScaledJob triggers Job creation when documents in test_collection match {"type":"mp4","state":"waiting"}.

    apiVersion: v1
    kind: Secret
    metadata:
      name: mongodb-secret
      namespace: mongodb-test
    type: Opaque
    data:
      # Base64-encoded value of:
      # mongodb://test_user:test_password@mongodb-svc.mongodb.svc.cluster.local:27017/test
      connect: bW9uZ29kYjovL3Rlc3RfdXNlcjp0ZXN0X3Bhc3N3b3JkQG1vbmdvZGItc3ZjLm1vbmdvZGIuc3ZjLmNsdXN0ZXIubG9jYWw6MjcwMTcvdGVzdA==
    ---
    apiVersion: keda.sh/v1alpha1
    kind: TriggerAuthentication
    metadata:
      name: mongodb-trigger
      namespace: mongodb-test
    spec:
      secretTargetRef:
        - parameter: connectionString
          name: mongodb-secret
          key: connect
    ---
    apiVersion: keda.sh/v1alpha1
    kind: ScaledJob
    metadata:
      name: mongodb-job
      namespace: mongodb-test
    spec:
      jobTargetRef:
        template:
          spec:
            containers:
              - name: mongo-update
                image: registry-cn-shanghai.ack.aliyuncs.com/acs/mongo-update:v6
                args:
                  - --dataBase=test
                  - --collection=test_collection
                  - --operation=updateMany
                  - --update={"$set":{"state":"finished"}}
                env:
                  - name: MONGODB_CONNECTION_STRING
                    value: mongodb://test_user:test_password@mongodb-svc.mongodb.svc.cluster.local:27017/test
                imagePullPolicy: IfNotPresent
            restartPolicy: Never
        backoffLimit: 1
      pollingInterval: 15         # Check MongoDB every 15 seconds
      maxReplicaCount: 5          # Run at most 5 concurrent Jobs
      successfulJobsHistoryLimit: 0  # Delete completed Jobs immediately
      failedJobsHistoryLimit: 10     # Keep the last 10 failed Jobs for debugging
      triggers:
        - type: mongodb
          metadata:
            dbName: test
            collection: test_collection
            query: '{"type":"mp4","state":"waiting"}'  # Launch a Job for each matching document
            queryValue: "1"
          authenticationRef:
            name: mongodb-trigger
  2. Deploy the configuration.

    kubectl apply -f keda-mongodb.yaml

Step 3: Simulate events and verify autoscaling

  1. Insert five pending transcoding records into MongoDB.

    MONGO_POD_NAME=$(kubectl get pods -n mongodb -l name=mongodb -o jsonpath='{.items[0].metadata.name}')
    
    # Insert 5 pending transcoding records
    kubectl exec -n mongodb ${MONGO_POD_NAME} -- mongo test --eval 'db.test_collection.insert([
      {"type":"mp4","state":"waiting","createTimeStamp":"1610352740","fileName":"My Love"},
      {"type":"mp4","state":"waiting","createTimeStamp":"1610350740","fileName":"Harker"},
      {"type":"mp4","state":"waiting","createTimeStamp":"1610152940","fileName":"The World"},
      {"type":"mp4","state":"waiting","createTimeStamp":"1610390740","fileName":"Mother"},
      {"type":"mp4","state":"waiting","createTimeStamp":"1610344740","fileName":"Jagger"}
    ])'
  2. Watch the Job resources in the mongodb-test namespace.

    watch kubectl get job -n mongodb-test

    Within one polling interval (15 seconds), five Jobs are created and cleaned up after completion:

    NAME                STATUS     COMPLETIONS   DURATION   AGE
    mongodb-job-4wxgx   Complete   1/1           3s         10s
    mongodb-job-9bs8r   Complete   1/1           3s         10s
    mongodb-job-p6pnb   Complete   1/1           3s         10s
    mongodb-job-pshkv   Complete   1/1           4s         10s
    mongodb-job-t6fs8   Complete   1/1           4s         10s
  3. Confirm all records are marked as finished.

    MONGO_POD_NAME=$(kubectl get pods -n mongodb -l name=mongodb -o jsonpath='{.items[0].metadata.name}')
    kubectl exec -n mongodb ${MONGO_POD_NAME} -- mongo test --eval 'db.test_collection.find({"type":"mp4"}).pretty()'

    All records change from waiting to finished, confirming each Job processed its task.

References