diff --git a/contrib/k8s/helm/prowler-app/templates/worker/scaled-object.yaml b/contrib/k8s/helm/prowler-app/templates/worker/scaled-object.yaml index 98ae3ae9d5..32408cb0ec 100644 --- a/contrib/k8s/helm/prowler-app/templates/worker/scaled-object.yaml +++ b/contrib/k8s/helm/prowler-app/templates/worker/scaled-object.yaml @@ -18,15 +18,12 @@ spec: triggers: - type: {{ .Values.worker.keda.triggerType }} metadata: - userName: "postgres" - passwordFromEnv: POSTGRES_ADMIN_PASSWORD - host: {{ .Release.Name }}-postgresql - port: {{ .Values.postgresql.port | quote }} - dbName: {{ .Values.postgresql.auth.database | quote }} - sslmode: disable - # Query for KEDA to count the number of scans that are in executing, available, or scheduled states, - # where the scheduled time is within the last 2 hours and is before NOW(). Used for scaling workers. - query: >- - SELECT COUNT(*) FROM scans WHERE ((state='executing' OR state='available' OR state='scheduled') and scheduled_at < NOW() and scheduled_at > NOW() - INTERVAL '2 hours') - targetQueryValue: "1" + userName: {{ .Values.worker.keda.postgresql.userName | quote }} + passwordFromEnv: {{ .Values.worker.keda.postgresql.passwordFromEnv | quote }} + host: {{ .Values.worker.keda.postgresql.host | default (printf "%s-postgresql.%s.svc.cluster.local" .Release.Name .Release.Namespace) | quote }} + port: {{ .Values.worker.keda.postgresql.port | quote }} + dbName: {{ .Values.worker.keda.postgresql.database | default .Values.postgresql.auth.database | quote }} + sslmode: {{ .Values.worker.keda.postgresql.sslmode | quote }} + query: {{ .Values.worker.keda.query | quote }} + targetQueryValue: {{ .Values.worker.keda.targetQueryValue | quote }} {{- end }} diff --git a/contrib/k8s/helm/prowler-app/values.yaml b/contrib/k8s/helm/prowler-app/values.yaml index 1bc6fe8422..a5607575bc 100644 --- a/contrib/k8s/helm/prowler-app/values.yaml +++ b/contrib/k8s/helm/prowler-app/values.yaml @@ -427,10 +427,61 @@ worker: pollingInterval: 30 # -- The cooldown period in seconds for scaling cooldownPeriod: 120 - # -- The trigger type for scaling (cpu or memory) + # -- The KEDA scaler type. Only `postgresql` is supported by the default query below. triggerType: "postgresql" - # -- The target utilization percentage for the worker pods - value: "50" + # PostgreSQL connection used by the scaler query. The KEDA operator opens this + # connection from its own namespace, so `host` must resolve from there. The + # defaults target the bundled postgresql subchart; set them explicitly when + # using an external database (postgresql.enabled: false). + postgresql: + # -- Scaler database host. Defaults to the bundled "-postgresql..svc.cluster.local" service. + host: "" + # -- Scaler database port. + port: "5432" + # -- Scaler database name. Defaults to `postgresql.auth.database`. + database: "" + # -- User the scaler authenticates as. + userName: "postgres" + # -- Name of an env var on the worker container holding the password. + passwordFromEnv: "POSTGRES_ADMIN_PASSWORD" + # -- sslmode for the scaler connection. + sslmode: "disable" + # -- The scaler divides the query result by this value to get the desired replica count. + targetQueryValue: "1" + # -- Query the scaler runs to measure pending work. It replaces the previous + # 2-hour scheduled-only window, which missed manual scans, older backlogs and + # in-progress scans. Override to tune scaling for your workload. + # + # The default sums three signals: + # 1. Scans executing or available, bounded to rows updated in the last 24h so + # orphaned rows do not pin the worker up, plus scheduled scans that are due + # (no lower bound, so an overdue backlog still scales up). + # 2. Scan tasks published in the last 48h that no worker has finished. A PENDING + # TaskResult is written at publish time (before_task_publish in api/signals.py), + # so Beat's daily publishes are visible even with zero workers. Signal 1 alone + # deadlocks with minReplicas 0: every scan row after the first is created by + # the worker, so once the initial row ages out of the 24h bound there is + # nothing to count and nothing to create more. + # 3. Non-scan tasks pending in the last hour. Provider connection checks, + # deletions, reports and backfills never touch the scans table, so without + # this they are never picked up while the worker is scaled to zero. + # This includes reconcile-orphan-tasks, a Beat watchdog that runs every two + # minutes, so with minReplicas 0 the worker is woken about that often. Add + # it to the excluded task names below, or raise cooldownPeriod, if you would + # rather trade watchdog latency for longer idle periods. + query: >- + SELECT + (SELECT COUNT(*) FROM scans + WHERE (state IN ('executing', 'available') AND updated_at > NOW() - INTERVAL '24 hours') + OR (state = 'scheduled' AND scheduled_at < NOW())) + + (SELECT COUNT(*) FROM django_celery_results_taskresult + WHERE task_name IN ('scan-perform', 'scan-perform-scheduled') + AND status IN ('PENDING', 'RECEIVED', 'STARTED') + AND date_created > NOW() - INTERVAL '48 hours') + + (SELECT COUNT(*) FROM django_celery_results_taskresult + WHERE task_name NOT IN ('scan-perform', 'scan-perform-scheduled') + AND status IN ('PENDING', 'RECEIVED', 'STARTED') + AND date_created > NOW() - INTERVAL '1 hour') worker_beat: # This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/