This is a follow-up to:
This post enables the Backstage Kubernetes view without changing any Backstage source code and without installing any extra plugin. We only add Kubernetes-side configuration:
- Add Backstage Kubernetes plugin config (in
app-config.k8s.yaml) - Create a read-only ServiceAccount + RBAC for Backstage to read cluster objects, events, logs, and metrics
- Map the Component to Kubernetes objects using
backstage.io/kubernetes-id - Label the Kubernetes objects with the same
backstage.io/kubernetes-idso they show up under the Component
What you get in the UI
Inside the homelab-backstage Component page → Kubernetes tab:
- Deployments / Pods
- Services / Ingress
- Events
- Pod logs
- Pod + node metrics (if Metrics Server is available)
- Map the Backstage Component to Kubernetes objects (Catalog annotations)
Update your Component entity so Backstage knows which cluster, which namespace, and which kubernetes-id to query.
catalog-info.yaml
diff --git a/catalog-info.yaml b/catalog-info.yaml
index a8abe33..164d342 100644
--- a/catalog-info.yaml
+++ b/catalog-info.yaml
@@ -8,7 +8,9 @@ metadata:
jenkins.io/job-full-name: backstage/homelab-backstage-main-ci
backstage.io/techdocs-ref: dir:.
harbor.maksonlee.com/repository: backstage/homelab-backstage
-
+ backstage.io/kubernetes-id: homelab-backstage
+ backstage.io/kubernetes-namespace: backstage
+ backstage.io/kubernetes-cluster: in-cluster
spec:
type: website
owner: user:default/maksonlee
- Add Kubernetes plugin config (in-cluster)
Backstage needs to know how to locate clusters and how to authenticate. Here we use:
serviceLocatorMethod: multiTenantclusterLocatorMethods: configwith a single clusterin-clusterauthProvider: serviceAccountso it uses the Pod’s ServiceAccount token automatically
kubernetes/app-config.k8s.yaml
diff --git a/kubernetes/app-config.k8s.yaml b/kubernetes/app-config.k8s.yaml
index 3feca55..04d5aa4 100644
--- a/kubernetes/app-config.k8s.yaml
+++ b/kubernetes/app-config.k8s.yaml
@@ -7,3 +7,16 @@ backend:
cors:
origin: https://backstage-k8s.maksonlee.com
credentials: true
+
+kubernetes:
+ serviceLocatorMethod:
+ type: multiTenant
+
+ clusterLocatorMethods:
+ - type: config
+ clusters:
+ - name: in-cluster
+ url: https://kubernetes.default.svc
+ authProvider: serviceAccount
+ skipTLSVerify: false
+ skipMetricsLookup: false
- Grant Backstage read-only access to Kubernetes (RBAC)
The Kubernetes tab can show more than just Deployments/Pods; common “extra info” includes:
- Events
- Pod logs
- Pod + node metrics (from
metrics.k8s.io)
So we add a read-only ServiceAccount and RBAC.
kubernetes/backstage-k8s-rbac.yaml (new file)
diff --git a/kubernetes/backstage-k8s-rbac.yaml b/kubernetes/backstage-k8s-rbac.yaml
new file mode 100644
index 0000000..05c4034
--- /dev/null
+++ b/kubernetes/backstage-k8s-rbac.yaml
@@ -0,0 +1,47 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: backstage-k8s-reader
+ namespace: backstage
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: backstage-k8s-readonly
+rules:
+ - apiGroups: ['', 'apps', 'batch', 'autoscaling', 'networking.k8s.io']
+ resources:
+ - namespaces
+ - pods
+ - pods/log
+ - services
+ - endpoints
+ - configmaps
+ - limitranges
+ - resourcequotas
+ - deployments
+ - replicasets
+ - daemonsets
+ - statefulsets
+ - jobs
+ - cronjobs
+ - horizontalpodautoscalers
+ - ingresses
+ - events
+ verbs: ['get', 'list', 'watch']
+ - apiGroups: ['metrics.k8s.io']
+ resources: ['pods', 'nodes']
+ verbs: ['get', 'list']
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: backstage-k8s-readonly
+subjects:
+ - kind: ServiceAccount
+ name: backstage-k8s-reader
+ namespace: backstage
+roleRef:
+ kind: ClusterRole
+ name: backstage-k8s-readonly
+ apiGroup: rbac.authorization.k8s.io
- Label Kubernetes resources with
backstage.io/kubernetes-id
Backstage links Kubernetes objects to a Component by matching the annotation:
- backstage.io/kubernetes-id: homelab-backstage
…to Kubernetes resources that contain the label:
- backstage.io/kubernetes-id: homelab-backstage
So the fix is: add this label to all workloads/services you want to appear under that Component.
kubernetes/homelab-backstage.yaml
diff --git a/kubernetes/homelab-backstage.yaml b/kubernetes/homelab-backstage.yaml
index 02ab74c..38beb02 100644
--- a/kubernetes/homelab-backstage.yaml
+++ b/kubernetes/homelab-backstage.yaml
@@ -3,6 +3,9 @@ kind: Deployment
metadata:
name: homelab-backstage
namespace: backstage
+ labels:
+ app: homelab-backstage
+ backstage.io/kubernetes-id: homelab-backstage
spec:
replicas: 1
selector:
@@ -12,7 +15,9 @@ spec:
metadata:
labels:
app: homelab-backstage
+ backstage.io/kubernetes-id: homelab-backstage
spec:
+ serviceAccountName: backstage-k8s-reader
initContainers:
- name: wait-for-postgres
image: postgres:16
@@ -30,8 +35,6 @@ spec:
ports:
- name: http
containerPort: 7007
-
- # Load env vars (OIDC client for k8s, plus your existing secrets)
envFrom:
- secretRef:
name: backstage-env
@@ -64,6 +67,9 @@ kind: Service
metadata:
name: homelab-backstage
namespace: backstage
+ labels:
+ app: homelab-backstage
+ backstage.io/kubernetes-id: homelab-backstage
spec:
type: ClusterIP
selector:
@@ -79,6 +85,9 @@ kind: Ingress
metadata:
name: homelab-backstage
namespace: backstage
+ labels:
+ app: homelab-backstage
+ backstage.io/kubernetes-id: homelab-backstage
spec:
ingressClassName: traefik
rules:
- Label Postgres resources so they also appear under the same Component
Same idea: if Postgres is part of this Backstage “system”, label it with the same kubernetes-id.
kubernetes/postgres.yaml
diff --git a/kubernetes/postgres.yaml b/kubernetes/postgres.yaml
index 58300c6..630621a 100644
--- a/kubernetes/postgres.yaml
+++ b/kubernetes/postgres.yaml
@@ -3,6 +3,9 @@ kind: Service
metadata:
name: backstage-postgres
namespace: backstage
+ labels:
+ app: backstage-postgres
+ backstage.io/kubernetes-id: homelab-backstage
spec:
type: ClusterIP
selector:
@@ -18,6 +21,9 @@ kind: StatefulSet
metadata:
name: backstage-postgres
namespace: backstage
+ labels:
+ app: backstage-postgres
+ backstage.io/kubernetes-id: homelab-backstage
spec:
serviceName: backstage-postgres
replicas: 1
@@ -28,6 +34,7 @@ spec:
metadata:
labels:
app: backstage-postgres
+ backstage.io/kubernetes-id: homelab-backstage
spec:
securityContext:
fsGroup: 999
- Include the new RBAC manifest in Kustomize
kubernetes/kustomization.yaml
diff --git a/kubernetes/kustomization.yaml b/kubernetes/kustomization.yaml
index 1057fcd..28ba11a 100644
--- a/kubernetes/kustomization.yaml
+++ b/kubernetes/kustomization.yaml
@@ -6,6 +6,7 @@ namespace: backstage
resources:
- postgres.yaml
- homelab-backstage.yaml
+ - backstage-k8s-rbac.yaml
generatorOptions:
disableNameSuffixHash: false
- Apply and verify
Apply:
kubectl apply -k kubernetes/
kubectl -n backstage rollout status deploy/homelab-backstage
Verify Backstage can read objects (quick sanity checks):
kubectl -n backstage get sa backstage-k8s-reader
kubectl get clusterrole backstage-k8s-readonly
kubectl get clusterrolebinding backstage-k8s-readonly
Then open Backstage:
- Catalog → homelab-backstage → Kubernetes tab

Did this guide save you time?
Support this site