keda icon indicating copy to clipboard operation
keda copied to clipboard

Support Namespace label selector for WatchNamespace

Open Ladicle opened this issue 8 months ago • 7 comments

Proposal

Currently, KEDA allows restricting managed resources with the "WatchNamespace" option. However, when you want to restrict only specific namespaces, managing a comma-separated list of all namespaces can be difficult to maintain when there are many target namespaces.

It would be easier if KEDA offered a "namespace label selector" option that could be used to identify the namespaces to be set in WatchNamespace during startup. This feature could also be used for filtering target requests in ValidatingWebhookConfiguration.

Use-Case

We deploy multiple KEDAs in a single cluster for security reasons. Each organization has many sub-namespaces. We set all sub-namespaces belonging to the organization into WatchNamespace.

Is this a feature you are interested in implementing yourself?

Yes

Anything else?

No response

Ladicle avatar Aug 19 '25 03:08 Ladicle

We deploy multiple KEDAs in a single cluster for security reasons. Each organization has many sub-namespaces. We set all sub-namespaces belonging to the organization into WatchNamespace.

I am curious to hear, how do you manage KEDA metrics adapter in this case?

zroubalik avatar Aug 19 '25 09:08 zroubalik

It's not an official component, but we put the metrics adapter router between the apiserver and adapters

Ladicle avatar Aug 20 '25 06:08 Ladicle

@Ladicle do you have a link to a source code handy?

zroubalik avatar Aug 20 '25 09:08 zroubalik

Sorry, it's not open-source because the routing logic is closely tied to internal resource allocation. The design is straightforward. It simply forwards requests received from the apiserver to the adapter based on the routing logic.

Ladicle avatar Aug 21 '25 08:08 Ladicle

@zroubalik

here is the nginx.conf using for routing metrics request from apiserver to each adapter:

nginx.conf
events {
    worker_connections 1024;
}

http {
    access_log /dev/stdout;
    error_log /dev/stderr;

    # Add Kubernetes DNS resolver
    resolver kube-dns.kube-system.svc.cluster.local valid=5s;

    server {
        listen 6443 ssl;

        proxy_headers_hash_bucket_size 128;

        # SSL configuration
        ssl_certificate /certs/tls.crt;
        ssl_certificate_key /certs/tls.key;

        ignore_invalid_headers off;

        # Health check endpoint
        location /healthz {
            access_log off;
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }

        # Readiness check endpoint
        location /readyz {
            access_log off;
            return 200 "ready\n";
            add_header Content-Type text/plain;
        }

        # API discovery endpoints
        location = /apis {
            return 200 '{
  "kind": "APIGroupList",
  "apiVersion": "v1",
  "groups": [
    {
      "name": "external.metrics.k8s.io",
      "versions": [
        {
          "groupVersion": "external.metrics.k8s.io/v1beta1",
          "version": "v1beta1"
        }
      ],
      "preferredVersion": {
        "groupVersion": "external.metrics.k8s.io/v1beta1",
        "version": "v1beta1"
      }
    }
  ]
}';
            add_header Content-Type application/json;
        }


        location = /openapi/v2 {
            return 200 '{
  "swagger": "2.0",
  "info": {
    "title": "KEDA Adapter Router API",
    "version": "1.0.0"
  },
  "paths": {}
}';
            add_header Content-Type application/json;
        }

        location = /apis/external.metrics.k8s.io/v1beta1 {
            return 200 '{
  "kind": "APIResourceList",
  "apiVersion": "v1",
  "groupVersion": "external.metrics.k8s.io/v1beta1",
  "resources": [
    {
      "name": "namespaces/metrics",
      "singularName": "",
      "namespaced": false,
      "kind": "ExternalMetricValueList",
      "verbs": ["get"]
    }
  ]
}';
            add_header Content-Type application/json;
        }

        location ~ ^/apis/external\.metrics\.k8s\.io/v1beta1/namespaces/org-(?<org_id>[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)-- {
            set $upstream_service "keda-operator-metrics-apiserver.$org_id.svc.cluster.local";
            proxy_pass https://$upstream_service$request_uri;

            proxy_ssl_verify on;
            proxy_ssl_trusted_certificate /certs/ca.crt;
            proxy_ssl_certificate /certs/tls.crt;
            proxy_ssl_certificate_key /certs/tls.key;
        }

        location / {
            return 404 "Metrics Not Found";
        }
    }
}

Ladicle avatar Sep 29 '25 04:09 Ladicle

@zroubalik Compared to the watchNamespace option, the NamespaceSelector option allows for filtering by namespace labels, making it more flexible and seeming useful even on its own. What do you think?

superbrothers avatar Oct 03 '25 08:10 superbrothers

Implementing Namespace Selectors requires caching namespaces in the controller, so if this functionality isn't currently in place, it may result in slightly higher memory usage and marginally more configuration changes.

For the current requirements, simply adding object label selectors—where multiple controllers manage objects with different labels—might be sufficient. In this case, we would need to assign labels to our KEDA CRs. However, with the MutatingAdmissionPolicy feature available now, this can be implemented easily without requiring an admission webhook.

superbrothers avatar Oct 20 '25 12:10 superbrothers

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Dec 19 '25 12:12 stale[bot]