Backstage Kubernetes 插件排查指南:Service 实体不显示集群资源的原因与修复
2026/9/10 0:44:58 网站建设 项目流程

Backstage Kubernetes 插件排查指南:Service 实体不显示集群资源的原因与修复

【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage

本文面向 Backstage 中 Kubernetes 插件的使用与运维场景,讲解一个高频问题的完整排查链路:当你在软件目录(Software Catalog)的 Service 实体中打开 Kubernetes 标签页却发现一片空白时,如何用后端 API 直接验证集群连通性、如何定位标签选择器(label selector)与注解不匹配的根因,以及如何通过为 K8s 资源添加backstage.io/kubernetes-id标签或使用backstage.io/kubernetes-label-selector注解来彻底修复。读完本文,你将掌握一套可复现、可验证的排障流程,并能结合当前仓库源码理解 Backstage 背后的资源匹配原理。

问题现象:Kubernetes 未显示在 Service 实体上

在 Backstage 中接入 Kubernetes 插件后,最常见的"不工作"表现就是:某个 Service 实体页面上的 Kubernetes 标签页始终为空,既不报错也不展示任何 Pod、Service、Deployment 等资源。出现这种情况时,集群并不一定没有连接上,更常见的原因是实体注解与集群资源上的标签无法匹配——Backstage 正是依靠这套"注解 ↔ 标签"的对应关系来决定要为哪个实体拉取哪些资源。

下面按照"先验证后端、再检查标签、最后修复注解"的顺序展开。

第一步:用 curl 直接探测后端 API,确认集群侧数据

排查的第一步是绕过前端 UI,直接向 Backstage 后端的 Kubernetes 插件路由发起请求,验证后端能否从集群取回资源。官方推荐的探测方式如下(将占位符替换为你的实际值):

curl --location --request POST '{{backstage-backend-url}}:{{backstage-backend-port}}/api/kubernetes/services/:service-entity-name' \ --header 'Content-Type: application/json' \ --data-raw '{ "entity": { "metadata": { "name": <service-entity-name> } } } '

其中:

  • {{backstage-backend-url}}/{{backstage-backend-port}}:Backstage 后端服务的地址与端口,即app-config.yamlbackend.baseUrl对应的主机与端口;
  • :service-entity-name:你在软件目录中创建的那个 Service 实体的metadata.name
  • 请求体中的entity.metadata.name用于告知后端要查询哪个实体。

如果后端与集群连接正常,且标签匹配正确,响应中应包含来自 Kubernetes 的资源列表:

# curl response { "items": [ { "cluster": { "name": <cluster-name> }, "resources": [ { "type": "services", "resources": [ { "metadata": { "creationTimestamp": "2022-03-13T13:52:46.000Z", "labels": { "app": <k8s-app-name>, "backstage": <selector>, "backstage.io/kubernetes-id": <service-entity-name> }, "name": <k8s-app-name>, "namespace": <namespace> }, .... } ] }, .... { "type": "pods", "resources": [ ,,,, ] } ], "errors": [] } ] }

如何解读这份响应

  • items[]数组对应"为该实体匹配到的每一个集群";
  • 每个集群下的resources[]按资源类型(servicespodsdeployments等)分组返回,type字段标明类型;
  • 每个资源的metadata.labels中可以看到backstage.io/kubernetes-id标签——这正是 Backstage 用来把实体与资源关联起来的键;
  • errors字段如果非空,则说明该集群在某些资源类型的抓取上发生了错误(例如鉴权失败、RBAC 权限不足、Metrics API 不可用等),这本身也是下一步排查的重要线索。

如果items为空或resources为空,说明后端没有为这个实体找到任何匹配的集群资源——问题大概率出在"标签/注解不匹配",而不是集群断连。

该端点在前端是如何被调用的

从当前仓库源码看,这个探测端点由 KubernetesRouter.ts 注册:router.post('/services/:serviceId', ...)会先校验调用方权限(kubernetesResourcesReadPermission),再将请求体中的实体引用解析为真实的 Catalog 实体,最后调用objectsProvider.getKubernetesObjectsByEntity完成资源抓取。注意该端点已在源码中被标注为// @deprecated,仓库中新增了POST /resources/workloads/queryPOST /resources/custom/query等路由(见 resourcesRoutes.ts),但上述 curl 探测方式仍可用于快速验证后端返回结构与标签匹配情况。对应端点的行为验证可参考仓库测试 KubernetesRouter.test.ts 中describe('post /services/:serviceId')的用例。

第二步:理解根因——注解与标签的匹配逻辑

当 Catalog 实体的注解(annotation)与集群资源的标签(label)不一致时,Kubernetes 标签页就不会显示任何内容。要理解这一点,需要先看 Backstage 后端是如何决定"拉取哪些资源"的。

从源码看匹配流程

资源匹配的核心逻辑位于 KubernetesFanOutHandler.ts 的fanOutRequests方法中,关键代码可以概括为两步:

  1. 确定实体名(entityName):优先读取实体注解backstage.io/kubernetes-id;如果该注解不存在,则回退使用实体的metadata.name
const entityName = entity.metadata?.annotations?.['backstage.io/kubernetes-id'] || entity.metadata?.name;
  1. 构造标签选择器(labelSelector):优先读取实体注解backstage.io/kubernetes-label-selector;如果该注解不存在,则默认构造为backstage.io/kubernetes-id=<entityName>
const labelSelector: string = entity.metadata?.annotations?.[ KUBERNETES_LABEL_SELECTOR_QUERY_ANNOTATION ] || `${KUBERNETES_ANNOTATION}=${entityName}`;

最终,这个labelSelector会被传给 fetcher,以labelSelector为条件去对应集群拉取各类型资源(见 KubernetesFetcher.ts 中fetchObjectsForService的实现)。

注解常量定义

上述两个注解键在 catalog-entity-constants.ts 中被统一定义:

  • KUBERNETES_ANNOTATION = 'backstage.io/kubernetes-id'——用于把 Catalog 实体与对应的 Kubernetes 资源关联起来;
  • KUBERNETES_LABEL_SELECTOR_QUERY_ANNOTATION = 'backstage.io/kubernetes-label-selector'——用于指定一个完整的 Kubernetes 标签选择器查询串,例如app=my-app,environment=production

小结:Kubernetes 标签页为空,几乎都是因为"实体上的注解(决定 labelSelector)"与"集群资源上的标签"对不上,导致 K8s API 按选择器查询时返回了空列表。

第三步:修复方案一——为 K8s 资源打上backstage.io/kubernetes-id标签

推荐做法是:给所有需要关联到该实体的 Kubernetes 对象(Service、Deployment、Ingress 等)加上backstage.io/kubernetes-id标签,标签值等于 Catalog 实体的名称。示例:

# k8s related yaml (service.yaml, deployment.yaml, ingress.yaml) metadata: creationTimestamp: '2022-03-13T13:52:46.000Z' labels: app: <k8s-app-name> env: <environment> backstage.io/kubernetes-id: <service-entity-name> name: <k8s-app-name> namespace: <namespace>

字段说明:

  • appenv等是你自己的业务标签,与 Backstage 无关;
  • backstage.io/kubernetes-id是关键——它的值必须与 Catalog 实体名(<service-entity-name>)一致;
  • name<k8s-app-name>)与backstage.io/kubernetes-id的值可以不同;但如果你希望 Kubernetes 侧与 Backstage 侧的名称保持一致、方便运维排查,官方建议两者使用同一个名字。

仓库中的测试夹具也印证了这一约定:例如 deploy-healthy.json 中的 Deployment 同时在其metadata.labels和 Pod 模板标签中携带"backstage.io/kubernetes-id": "dice-roller",而对应的 Catalog 实体名正是dice-roller。这意味着打标签时不能只打在 Deployment 上,还要注意 Pod 模板(spec.template.metadata.labels)等资源同样需要携带该标签,否则即使 Deployment 被选中,由其派生的 Pod 也可能匹配不上,导致资源类型显示不全。

第四步:修复方案二——在 Catalog 实体上使用 label selector 注解

如果由于历史原因无法统一修改所有 K8s 资源的标签(例如资源归属其他团队、标签体系已经固定),可以使用backstage.io/kubernetes-label-selector注解,在 Catalog 实体一侧指定任意的标签选择器:

# catalog-info.yaml (backstage) annotations: backstage.io/kubernetes-label-selector: '<label-selector>'

其中<label-selector>是标准的 Kubernetes 标签选择器表达式,例如:

annotations: backstage.io/kubernetes-label-selector: 'app=dice-roller,environment=production'

该注解的值会被直接作为 K8s API 查询时的labelSelector参数使用,因此你可以利用 K8s 标签选择器完整的表达能力(等值匹配、集合匹配in/notin、存在性判断exists/!等)。一旦配置了此注解,后端就会优先采用它构造选择器,而不再使用默认的backstage.io/kubernetes-id=<entityName>

两者如何选择

场景推荐方案
集群资源由你方统一管理,可以修改 YAML方案一:为资源打backstage.io/kubernetes-id标签(最简单、最直观)
资源标签体系固定、无法改动,或一个实体需要匹配多种标签组合方案二:在catalog-info.yaml中使用backstage.io/kubernetes-label-selector
两者都配置label selector 注解优先生效(见上文源码逻辑)

进阶提示:命名空间注解与更多排查方向

除了上面两个核心注解,源码中还支持backstage.io/kubernetes-namespace注解(见 KubernetesFanOutHandler.ts),用于将资源抓取范围限定到指定命名空间,适合实体资源较多时缩小查询范围、提升性能。

如果完成了标签/注解修复后标签页依然为空,建议按以下顺序继续排查:

  1. 检查errors字段:重新执行文首的 curl,看响应中items[].errors是否出现鉴权失败(如401/403)、Metrics API 不可用或 RBAC 权限不足等错误;
  2. 检查集群连通性配置:确认app-config.yamlkubernetes.clusterLocatorMethods下的集群 URL、authProviderserviceAccountToken等是否正确,完整配置示例见 configuration.md;
  3. 检查命名空间:如果实体注解了backstage.io/kubernetes-namespace,确认资源确实位于该命名空间;
  4. 确认实体名称:牢记默认选择器是backstage.io/kubernetes-id=<entityName>,其中entityName优先取注解值、其次取metadata.name,不要混淆这两者。

结语

Kubernetes 标签页为空是 Backstage Kubernetes 插件接入中最常见的"假故障"——集群连接正常,只是 Catalog 实体与集群资源之间缺少匹配关系。通过本文的 curl 探测法你可以快速定位问题层级,而backstage.io/kubernetes-id标签与backstage.io/kubernetes-label-selector注解则提供了两套互补的修复路径。理解了 KubernetesFanOutHandler.ts 中的匹配逻辑,你就能在任何"资源不显示"的场景下快速判断:问题出在标签、注解还是命名空间。更多配置细节可进一步阅读 Kubernetes 配置文档 与 Kubernetes 功能总览。

【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询