Networking & Monitoring¶
Services¶
Routable components expose a Kubernetes Service. The service spec supports
type, port, nodePort, labels, and annotations:
spec:
webServer:
service:
type: LoadBalancer
port: 443
annotations:
service.beta.kubernetes.io/aws-load-balancer-internal: "true"
The operator does not expose Kubernetes Service.spec.loadBalancerIP because
that field is deprecated. Prefer controller-specific annotations when your
provider documents them.
Gateway API (Recommended)¶
Requires Gateway API CRDs installed on the cluster. Gateway API is not included in Kubernetes and must be installed separately. If the CRDs are absent, the operator logs a message and skips HTTPRoute management.
spec:
networking:
gateway:
gatewayRef:
name: my-gateway
namespace: gateway-system
hostnames:
- superset.example.com
The operator creates an HTTPRoute with path-based routing:
| Priority | Path | Target | Condition |
|---|---|---|---|
| 1 (most specific) | /ws |
websocket-server Service | websocketServer enabled |
| 2 | /mcp |
mcp-server Service | mcpServer enabled |
| 3 | /flower |
celery-flower Service | celeryFlower enabled |
| 4 (catch-all) | / |
web-server Service | webServer enabled |
More specific paths are listed first to ensure correct routing priority.
Paths are configurable via service.gatewayPath on each component spec.
For example, to serve Celery Flower under /monitoring:
Ingress (Legacy)¶
Gateway API and Ingress are mutually exclusive — set one or the other, not both.
Ingress uses the same per-component path routing as Gateway API: a host with
no explicit paths is expanded by the operator into one rule per present
component (/ → web server, plus /flower, /mcp, /ws for the components
that are enabled), reusing each component's service.gatewayPath. Requests are
forwarded as-is (no path rewrite), so each component owns its subpath the same
way it does under Gateway API (e.g. Flower via its --url_prefix).
spec:
networking:
ingress:
className: nginx
host: superset.example.com # no explicit paths -> all components routed by path
A host with explicit paths is treated as a user-controlled override and
those paths route to the web server only — use this when you want full control
of the path rules for a host:
spec:
networking:
ingress:
className: nginx
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
hosts:
- host: superset.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: superset-tls
hosts:
- superset.example.com
Use className for controllers that support spec.ingressClassName. For
legacy controllers, put kubernetes.io/ingress.class under annotations
instead:
spec:
networking:
ingress:
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/target-type: ip
hosts:
- host: superset.example.com
paths:
- path: /
pathType: Prefix
Graceful CRD Handling¶
If Gateway API CRDs are not present, the controller skips HTTPRoute watch
registration and catches meta.IsNoMatchError at reconciliation time. The
operator runs with reduced functionality rather than failing.
Superset Instance Metrics¶
Requires prometheus-operator CRDs. The operator gracefully skips if they are not installed.
The controller creates a Prometheus ServiceMonitor targeting the web-server
component using unstructured objects (because the ServiceMonitor CRD is
external: monitoring.coreos.com/v1). Default scrape interval is 30s
(configurable). Targets pods with app.kubernetes.io/component: web-server.
Operator Metrics¶
The operator itself exposes controller-runtime default metrics — reconcile counts and durations, work-queue depth, leader election state. These are served over HTTPS on port 8443, guarded by Kubernetes bearer-token authentication and authorization. No custom lifecycle metrics are emitted today; condition and event streams cover the per-instance lifecycle state.
RBAC. Any scraper (typically Prometheus) needs the metrics-reader
ClusterRole bound to its own ServiceAccount. Both install paths ship this
role; bind it to your Prometheus ServiceAccount, for example:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: prometheus-superset-operator-metrics
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: superset-operator-metrics-reader # Kustomize. For Helm, check the installed role name.
subjects:
- kind: ServiceAccount
name: prometheus
namespace: monitoring
TLS by default. The operator generates a self-signed certificate at
startup, so scrapers connect over HTTPS with insecureSkipVerify: true. This
is the default in both the Kustomize ServiceMonitor (config/prometheus/monitor.yaml)
and the Helm chart. It's fine for a trusted cluster but not for
zero-trust environments. Authentication and authorization are always enforced
via bearer tokens (TokenReview/SubjectAccessReview) regardless of TLS
setup — see
Design Decisions in the security
reference for the trust-model context.
Enable via Helm¶
The chart ships a ServiceMonitor template, off by default. The minimal opt-in looks like:
metrics:
enabled: true
serviceMonitor:
enabled: true
interval: 30s
labels:
release: prometheus # selector your Prometheus picks up
That keeps the default self-signed + insecureSkipVerify: true behavior.
For real TLS via cert-manager, provision a metrics-server-cert Secret
(typically via a cert-manager.io/v1 Certificate keyed to a self-signed
Issuer) and point the chart at it:
metrics:
enabled: true
certSecretName: metrics-server-cert # mounts Secret into manager pod
serviceMonitor:
enabled: true
labels:
release: prometheus
tlsConfig: # free-form ServiceMonitor tlsConfig
insecureSkipVerify: false
serverName: <release>-superset-operator-metrics.<namespace>.svc
ca:
secret:
name: metrics-server-cert
key: ca.crt
The operator authenticates scrapers via bearer token (TokenReview), not
mTLS, so ca + serverName are sufficient for the scraper to verify the
server. Add cert/keySecret only if you've separately configured the
metrics server to require client certs.
Setting metrics.certSecretName mounts the Secret into the manager pod
and adds --metrics-cert-path args so the metrics server presents that
certificate. The full set of knobs is documented in
charts/superset-operator/values.yaml.
The chart does not ship the cert-manager Certificate or Issuer
resources themselves; you create them (for example via
cert-manager.io/v1 manifests alongside your values). See the Kustomize
section below for a working example of those manifests.
Enable via Kustomize¶
Uncomment - ../prometheus in config/default/kustomization.yaml and
re-apply. This adds the shipped ServiceMonitor in
config/prometheus/monitor.yaml, which scrapes the operator's self-signed
metrics endpoint with insecureSkipVerify: true.
For a cert-manager-managed certificate (real TLS, no insecureSkipVerify),
install cert-manager on the cluster, then
uncomment three more sections in config/default/kustomization.yaml:
[CERTMANAGER]— pulls inconfig/certmanager(aselfsigned-issuerIssuer plus ametrics-certsCertificate that issues themetrics-server-certSecret).[METRICS-WITH-CERTS]— mounts that Secret into the manager pod and adds the--metrics-cert-pathargs.[PROMETHEUS-WITH-CERTS]— areplacementsblock that substitutes the real Service name and namespace into the Certificate's dnsNames and the ServiceMonitor'stlsConfig.serverName.
Also uncomment the patch reference in config/prometheus/kustomization.yaml
so the ServiceMonitor picks up the real-TLS tlsConfig from
monitor_tls_patch.yaml.
Network Policies¶
Creates per-component NetworkPolicies that:
- Allow ingress from other pods of the same Superset instance on any port (matched by
app.kubernetes.io/name: superset+superset.apache.org/parentlabels — multiple Superset instances in the same namespace are isolated from each other). The same-instance rule is intentionally port-unrestricted so internal traffic between components (sidecar metrics scraping, the websocket server fanning out to web pods, etc.) is not silently blocked. - Allow ingress on the service port from any source for externally-facing components (web server, Celery Flower, websocket server, MCP server) — this is necessary because ingress controllers and load balancers typically reside outside the namespace and cannot be matched with a pod selector.
- Allow all egress (for database/cache access)
- Support custom
extraIngressandextraEgressrules
Per-component rules:
| Component | Ingress from same-instance Superset pods | Ingress from external | Egress |
|---|---|---|---|
| WebServer | any port | port 8088 | all |
| CeleryWorker | any port | — | all |
| CeleryBeat | any port | — | all |
| CeleryFlower | any port | port 5555 | all |
| WebsocketServer | any port | port 8080 | all |
| McpServer | any port | port 8088 | all |
If you need to restrict external ingress to specific sources, disable the built-in
network policy and create your own NetworkPolicy resources with the desired from
selectors.
The built-in policy is ingress segmentation only — egress is intentionally unrestricted so workloads can reach the metastore database, Valkey, SMTP servers, and other user-configured dependencies. For the rationale and hardening path, see Design Decisions in the security reference.