〇、写在前面
如果你的公司有超过 3 个微服务,并且每次找个 API 文档都要翻遍 Confluence、SharePoint、钉钉群聊和某位离职同事的脑子,那么恭喜你——你可能需要 Backstage。
如果你的公司只有一个单体应用,那你可以现在就放弃了,省下来的时间去健身房撸个铁不香吗?
Backstage 是 Spotify 在 2020 年开源的内部开发者门户(Internal Developer Portal, IDP),后来捐给了 CNCF,目前是 Incubating 项目。它的核心愿景是:把所有开发者需要的东西,塞进一个统一的界面里。
听起来很美好对吧?就像"我要把所有支付系统统一到一个平台"一样美好。
一、Backstage 是什么?
1.1 一句话定义
Backstage 是一个构建开发者门户的开源框架(注意,是框架,不是开箱即用的产品)。
1.2 核心功能三板斧
软件目录"] ST["🚀 Software Templates
软件模板"] TD["📖 TechDocs
技术文档"] end SC --> |"统一管理"| Services["微服务 / API / 库 / 网站"] ST --> |"一键创建"| Scaffold["标准化项目脚手架"] TD --> |"Docs as Code"| Docs["Markdown → 在线文档站"] subgraph Plugins["🔌 插件生态"] P1["Kubernetes"] P2["CI/CD"] P3["Cloud Costs"] P4["PagerDuty"] P5["还有100+..."] end Backstage --> Plugins style Backstage fill:#1a1a2e,stroke:#16213e,color:#e0e0e0 style Plugins fill:#0f3460,stroke:#16213e,color:#e0e0e0 style SC fill:#533483,stroke:#16213e,color:#e0e0e0 style ST fill:#533483,stroke:#16213e,color:#e0e0e0 style TD fill:#533483,stroke:#16213e,color:#e0e0e0
| 核心功能 | 干什么用 | 对标产品 |
|---|---|---|
| Software Catalog | 统一注册和查看所有软件资产(服务、API、组件、资源) | 内部版 ServiceNow CMDB |
| Software Templates | 标准化创建新项目,自动化 scaffolding | 内部版 Yeoman / CookieCutter |
| TechDocs | Docs-as-Code,把 Markdown 渲染成文档站 | 内部版 GitBook / Read the Docs |
1.3 架构全景图
(GitHub/GitLab/Bitbucket)"] CICD["CI/CD
(Jenkins/GitHub Actions)"] K8S["Kubernetes"] CLOUD["Cloud Provider
(AWS/Azure/GCP)"] end UI --> API API --> BP1 & BP2 & BP3 & BP4 & BP5 BP1 --> DB BP1 --> SCM BP2 --> SCM BP4 --> SCM & CICD BP5 --> DB style Frontend fill:#2d3436,stroke:#636e72,color:#dfe6e9 style Backend fill:#2d3436,stroke:#636e72,color:#dfe6e9 style Infra fill:#2d3436,stroke:#636e72,color:#dfe6e9
划重点:Backstage 本质上是一个 React + Node.js 的全栈应用,前端是 SPA,后端是一堆插件化的 API 服务。数据存在 PostgreSQL 里,和你的 Git、CI/CD、Cloud 通过插件集成。
二、Software Catalog:你的服务大管家
2.1 核心概念
Catalog 是 Backstage 的灵魂。它用 YAML 文件(catalog-info.yaml)来描述你的软件资产,这些 YAML 文件通常放在各个 Repo 的根目录。
# catalog-info.yaml - 放在你的服务仓库根目录
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: deposit-service
description: AstraTech 存款服务 - 管理所有存款相关业务
annotations:
github.com/project-slug: astratech/deposit-service
backstage.io/techdocs-ref: dir:.
tags:
- java
- spring-boot
- payments
links:
- url: https://grafana.astratech.ae/d/deposit
title: Grafana Dashboard
icon: dashboard
spec:
type: service
lifecycle: production
owner: team-deposit
system: payment-platform
providesApis:
- deposit-api
consumesApis:
- npss-api
- vis-api
dependsOn:
- resource:deposit-db
- component:escrow-service2.2 实体关系模型
2.3 以 AstraTech 为例
假设要把 Deposit Team 的系统全部注册到 Catalog,大概长这样:
Aani Instant Payments"] VIS["VIS/VISII Service
Virtual Account Mgmt"] DEP["Deposit Service
Core Deposits"] TTS["TTS Service
Visa Installments"] ESC["Escrow Service"] CARDS["Cards Service"] EX["Exchange Service"] RTP["RTP Service"] end end subgraph Resources["🗄️ Resources"] DB1[("Deposit DB")] DB2[("NPSS DB")] MQ["Kafka / RabbitMQ"] end subgraph APIs["📡 APIs"] A1["Deposit API
OpenAPI 3.0"] A2["NPSS API
ISO 20022"] A3["VIS API"] end DEP --> DB1 NPSS --> DB2 DEP --> MQ DEP --> A1 NPSS --> A2 VIS --> A3 NPSS -.-> DEP TTS -.-> DEP style Domain_Payments fill:#1B1464,stroke:#0c2461,color:#dfe6e9 style System_PaymentPlatform fill:#0a3d62,stroke:#0c2461,color:#dfe6e9
现实检查:要让所有团队都老老实实写 catalog-info.yaml,难度约等于让所有开发者都写单元测试。所以 Backstage 也支持从 LDAP/AD、GitHub Org、Kubernetes 等地方自动发现和导入实体。三、Software Templates:一键生成标准项目
3.1 它解决什么问题?
每次新建一个微服务,你是不是要:
- 创建 Git 仓库
- 复制粘贴某个"模板项目"
- 改一堆
pom.xml/build.gradle里的名字 - 配 CI/CD Pipeline
- 注册到服务发现
- 创建 Jira Board
- 然后发现忘了改某个配置,线上出 Bug
Software Templates 就是把上面这些步骤全部自动化。
3.2 模板工作流
"New Spring Boot Service" BS->>Dev: 2. 填写表单
(服务名、团队、描述...) Dev->>BS: 3. 提交 BS->>SC: 4. 触发 Scaffolder SC->>SC: 5. 渲染模板
(Nunjucks/Cookiecutter) SC->>GIT: 6. 创建仓库 + 推送代码 SC->>GIT: 7. 注册 catalog-info.yaml SC->>CI: 8. 触发首次 CI 构建 SC->>K8S: 9. (可选) 创建 namespace SC->>BS: 10. 完成 ✅ BS->>Dev: 11. 跳转到新服务页面
3.3 模板定义示例
# template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: springboot-service
title: Spring Boot 微服务模板
description: 创建一个标准的 Spring Boot 微服务,包含 CI/CD 和监控
tags:
- java
- spring-boot
- recommended
spec:
owner: team-platform
type: service
# === 第一步:收集参数 ===
parameters:
- title: 基本信息
required:
- name
- owner
- description
properties:
name:
title: 服务名称
type: string
description: 例如 deposit-service
pattern: '^[a-z][a-z0-9-]*$'
owner:
title: 所属团队
type: string
ui:field: OwnerPicker
description:
title: 服务描述
type: string
- title: 技术选型
properties:
javaVersion:
title: Java 版本
type: string
enum: ['17', '21']
default: '21'
database:
title: 数据库
type: string
enum: ['postgresql', 'mysql', 'none']
default: 'postgresql'
# === 第二步:执行动作 ===
steps:
- id: fetch-template
name: 拉取模板
action: fetch:template
input:
url: ./skeleton # 模板文件目录
values:
name: ${{ parameters.name }}
owner: ${{ parameters.owner }}
javaVersion: ${{ parameters.javaVersion }}
- id: publish
name: 创建 Git 仓库
action: publish:github
input:
allowedHosts: ['github.com']
repoUrl: github.com?owner=astratech&repo=${{ parameters.name }}
description: ${{ parameters.description }}
- id: register
name: 注册到 Catalog
action: catalog:register
input:
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: /catalog-info.yaml
output:
links:
- title: 打开仓库
url: ${{ steps.publish.output.remoteUrl }}
- title: 查看服务
entityRef: ${{ steps.register.output.entityRef }}四、TechDocs:让文档不再躺在 Confluence 里吃灰
4.1 核心理念:Docs as Code
(存在代码仓库里)"] --> B["🔧 MkDocs 构建"] B --> C["📦 静态 HTML"] C --> D["☁️ 存储
(S3/GCS/本地)"] D --> E["🖥️ Backstage 渲染"] style A fill:#6c5ce7,stroke:#5f27cd,color:#fff style B fill:#00b894,stroke:#00cec9,color:#fff style C fill:#fdcb6e,stroke:#ffeaa7,color:#2d3436 style D fill:#e17055,stroke:#d63031,color:#fff style E fill:#0984e3,stroke:#74b9ff,color:#fff
4.2 文档结构
your-service-repo/
├── catalog-info.yaml # 注册到 Backstage
├── mkdocs.yml # MkDocs 配置
├── docs/
│ ├── index.md # 首页
│ ├── getting-started.md # 快速开始
│ ├── architecture.md # 架构说明
│ ├── api-reference.md # API 参考
│ └── runbook.md # 运维手册
└── src/
└── ... # 你的代码# mkdocs.yml
site_name: Deposit Service
nav:
- Home: index.md
- Getting Started: getting-started.md
- Architecture: architecture.md
- API Reference: api-reference.md
- Runbook: runbook.md
plugins:
- techdocs-core真话时间:TechDocs 体验说实话一般般。MkDocs 的渲染能力有限,不支持复杂布局。如果你们已经在用 Confluence 并且用得还行,TechDocs 可能不是迁移的充分理由。
五、插件生态:Backstage 的真正杀手锏
Backstage 本身只是个框架,真正的价值在于插件生态。
5.1 官方 & 热门插件
插件生态)) CI/CD GitHub Actions Jenkins GitLab CI ArgoCD Tekton 监控 & 可观测 Grafana Prometheus Datadog PagerDuty Opsgenie 云 & 基础设施 Kubernetes AWS GCP Azure Terraform 安全 Snyk SonarQube Vault 协作 Jira Confluence Slack API 管理 OpenAPI / Swagger AsyncAPI GraphQL 成本 Cloud Cost Kubecost
5.2 插件架构
@backstage/plugin-xxxReact 组件"] BE["Backend Plugin
@backstage/plugin-xxx-backendExpress Router"] Common["Common
@backstage/plugin-xxx-common共享类型/工具"] end FE --> |"HTTP API"| BE FE --> Common BE --> Common subgraph Integration["外部集成"] ExtAPI["外部 API
(GitHub/Jira/K8s...)"] ExtDB["插件自有表
(PostgreSQL)"] end BE --> ExtAPI BE --> ExtDB style Plugin fill:#2d3436,stroke:#636e72,color:#dfe6e9 style Integration fill:#2d3436,stroke:#636e72,color:#dfe6e9
5.3 写一个自定义插件(伪代码)
// packages/app/src/plugins.ts
// 前端:注册一个显示 NPSS 交易状态的插件
import { createPlugin, createRoutableExtension } from '@backstage/core-plugin-api';
export const npssPlugin = createPlugin({
id: 'npss-dashboard',
routes: {
root: rootRouteRef,
},
});
export const NpssDashboardPage = npssPlugin.provide(
createRoutableExtension({
name: 'NpssDashboardPage',
component: () =>
import('./components/NpssDashboard').then(m => m.NpssDashboard),
mountPoint: rootRouteRef,
}),
);六、部署方案
6.1 部署拓扑
(Nginx / ALB)"] subgraph AppLayer["Application"] FE["Frontend
(Static Files / CDN)"] BE1["Backend Instance 1"] BE2["Backend Instance 2"] end DB[("PostgreSQL
(RDS / CloudSQL)")] CACHE["Redis
(可选, 用于Search)"] OBJ["Object Storage
(S3/GCS, TechDocs用)"] end LB --> FE LB --> BE1 & BE2 BE1 & BE2 --> DB BE1 & BE2 --> CACHE BE1 & BE2 --> OBJ style Production fill:#1a1a2e,stroke:#16213e,color:#e0e0e0 style AppLayer fill:#0f3460,stroke:#16213e,color:#e0e0e0
6.2 部署选项对比
| 方式 | 复杂度 | 适合场景 | 备注 |
|---|---|---|---|
| Docker Compose | ⭐ | PoC / 小团队 | 最快上手 |
| Kubernetes (Helm) | ⭐⭐⭐ | 中大型企业 | 官方有 Helm Chart |
| Kubernetes (自定义) | ⭐⭐⭐⭐ | 深度定制 | 自己写 Deployment YAML |
| Roadie (SaaS) | ⭐ | 不想运维 | 托管版 Backstage,要钱💰 |
| Port / Cortex | ⭐ | 不想运维 | 竞品 SaaS,各有千秋 |
七、快速上手:10 分钟跑起来
7.1 环境要求
- Node.js 18+ (推荐 20 LTS)
- Yarn 1.x(是的,还是 Classic Yarn 🤦)
- Docker(用于 PostgreSQL)
- Git
7.2 创建项目
# 1. 用官方 CLI 创建
npx @backstage/create-app@latest
# 2. 按提示输入项目名
? Enter a name for the app [required] astratech-portal
# 3. 进入项目
cd astratech-portal
# 4. 启动开发环境
yarn dev7.3 项目结构
astratech-portal/
├── app-config.yaml # 主配置文件 ⚡
├── app-config.production.yaml # 生产配置
├── catalog-info.yaml # Backstage 自身的 catalog 注册
├── packages/
│ ├── app/ # 前端 React 应用
│ │ ├── src/
│ │ │ ├── App.tsx # 路由和插件注册
│ │ │ └── components/ # 自定义组件
│ │ └── package.json
│ └── backend/ # 后端 Node.js 应用
│ ├── src/
│ │ └── index.ts # 后端入口
│ └── package.json
├── plugins/ # 自定义插件放这里
└── package.json7.4 核心配置
# app-config.yaml
app:
title: AstraTech Developer Portal
baseUrl: http://localhost:3000
backend:
baseUrl: http://localhost:7007
database:
client: pg
connection:
host: localhost
port: 5432
user: backstage
password: backstage
auth:
providers:
microsoft: # Azure AD 集成
development:
clientId: ${AZURE_CLIENT_ID}
clientSecret: ${AZURE_CLIENT_SECRET}
tenantId: ${AZURE_TENANT_ID}
catalog:
locations:
# 本地示例
- type: file
target: ../../examples/entities.yaml
# 从 GitHub Org 自动发现
- type: github-org
target: https://github.com/astratech
# 从 GitHub 仓库读取
- type: url
target: https://github.com/astratech/deposit-service/blob/main/catalog-info.yaml八、适用性评估:什么时候该用,什么时候该放弃
8.1 决策流程图
微服务/组件?"} Q1 -->|"< 10"| NO1["❌ 可能不需要
一个 Confluence 页面就够了"] Q1 -->|"10 ~ 50"| Q2{"有没有专人
维护内部工具?"} Q1 -->|"> 50"| Q3{"能接受 3-6 个月
的建设周期吗?"} Q2 -->|"没有"| NO2["❌ 考虑 SaaS 方案
(Roadie/Port/Cortex)"] Q2 -->|"有"| Q3 Q3 -->|"不能"| NO3["❌ 考虑 SaaS 方案
或者先用 Wiki + 手动管理"] Q3 -->|"能"| Q4{"开发团队
熟悉 React + TypeScript?"} Q4 -->|"不熟"| MAYBE["⚠️ 需要额外学习成本
但仍然可行"] Q4 -->|"熟"| Q5{"管理层支持
投入资源?"} MAYBE --> Q5 Q5 -->|"不支持"| NO4["❌ 没有自上而下的推动
内部平台注定失败"] Q5 -->|"支持"| YES(["✅ 上 Backstage!"]) style START fill:#6c5ce7,stroke:#5f27cd,color:#fff style YES fill:#00b894,stroke:#00cec9,color:#fff style NO1 fill:#d63031,stroke:#e17055,color:#fff style NO2 fill:#d63031,stroke:#e17055,color:#fff style NO3 fill:#d63031,stroke:#e17055,color:#fff style NO4 fill:#d63031,stroke:#e17055,color:#fff style MAYBE fill:#fdcb6e,stroke:#f9ca24,color:#2d3436
8.2 适用场景 ✅
| 场景 | 为什么适合 |
|---|---|
| 微服务数量 50+ | 人脑已经记不住谁依赖谁了 |
| 多团队协作 | 需要统一的服务发现和所有权管理 |
| 频繁创建新服务 | Software Templates 能节省大量时间 |
| 文档散落各处 | TechDocs 把文档和代码绑定 |
| 需要统一的开发者体验 | 一站式门户比 N 个工具跳来跳去强 |
| 已有 Kubernetes 基础设施 | K8s 插件是 Backstage 最成熟的插件之一 |
8.3 不适用场景 ❌
| 场景 | 为什么不适合 |
|---|---|
| 团队 < 20 人 | 投入产出比不合算 |
| 单体架构 | Catalog 没啥可管的 |
| 没有 DevOps 文化 | Backstage 需要团队主动维护 catalog-info.yaml |
| 追求开箱即用 | Backstage 需要大量定制开发 |
| 技术栈不含 TypeScript/React | 二次开发和插件维护会很痛苦 |
8.4 ROI 估算模型
九、Backstage vs 竞品
⭐ 29k+ GitHub Stars"] end subgraph SaaS["💰 SaaS"] RD["Roadie
托管版 Backstage"] PT["Port"] CX["Cortex"] OI["OpsLevel"] end subgraph DIY["🔨 自建"] WIKI["Confluence/Wiki
+ 自定义脚本"] end style OpenSource fill:#00b894,stroke:#00cec9,color:#fff style SaaS fill:#6c5ce7,stroke:#5f27cd,color:#fff style DIY fill:#fdcb6e,stroke:#f9ca24,color:#2d3436
| 维度 | Backstage | Roadie | Port | Cortex |
|---|---|---|---|---|
| 价格 | 免费(但要人力) | $$$ | $$$ | $$$ |
| 定制性 | 🟢 极高 | 🟡 中等 | 🟡 中等 | 🟡 中等 |
| 上手速度 | 🔴 慢(3-6月) | 🟢 快(1-2周) | 🟢 快 | 🟢 快 |
| 维护成本 | 🔴 高 | 🟢 低 | 🟢 低 | 🟢 低 |
| 插件生态 | 🟢 最丰富 | 🟢 兼容 Backstage | 🟡 自有生态 | 🟡 自有生态 |
| 数据控制 | 🟢 完全自主 | 🟡 SaaS | 🟡 SaaS | 🟡 SaaS |
| 社区支持 | 🟢 CNCF + 活跃社区 | 🟡 商业支持 | 🟡 商业支持 | 🟡 商业支持 |
十、实施路线图建议
十一、踩坑指南(从放弃到入门?)
🕳️ 坑 1:版本升级是噩梦
Backstage 的发布节奏非常快(几乎每周都有新版本),而且不保证向后兼容。每次升级都可能需要修改大量代码。
# 官方升级工具,但不要太相信它
npx @backstage/cli versions:bump建议:不要追最新版本。选一个稳定版本,每季度评估一次是否升级。
🕳️ 坑 2:Yarn 1.x 的诅咒
是的,2025 年了,Backstage 官方仍然推荐 Yarn Classic。虽然有社区方案支持 Yarn Berry 和 pnpm,但官方文档和工具链都是基于 Yarn 1.x 的。
🕳️ 坑 3:插件质量参差不齐
官方 marketplace 列出了 200+ 插件,但很多是社区贡献的,质量和维护状态各不相同。使用前一定要检查:最后更新时间、GitHub stars、是否有活跃维护者。
🕳️ 坑 4:认证和权限系统复杂
Backstage 的权限系统(Permission Framework)是后来加的,配置复杂且文档不完善。如果你需要细粒度的 RBAC,准备花不少时间。
🕳️ 坑 5:搜索功能是半成品
内置的搜索引擎(Lunr)只适合小规模使用。大规模部署需要集成 Elasticsearch 或 OpenSearch,额外增加运维负担。
十二、总结:到底该入门还是放弃?
给 AstraTech 的建议
推荐策略:PoC 先行,小步快跑
- 先做一个 2 周的 PoC:用 Docker Compose 部署一个最小化的 Backstage,把 Deposit Team 的几个核心服务注册进去,让团队感受一下 Software Catalog 的价值。
- 聚焦 Catalog,暂缓其他:Software Catalog 是最核心也是最容易产生价值的功能。Templates 和 TechDocs 可以后续再加。
- 评估 Roadie 作为 Plan B:如果 PoC 效果好但没有足够的人力做自建运维,Roadie(托管版 Backstage)是一个合理的备选。
- 自上而下推动:内部开发者门户必须有管理层支持和强制要求,否则注定成为又一个没人维护的内部项目。
一句话总结
Backstage 就像是开发者世界的"超级 App"——理念超前、生态丰富、但组装难度约等于从零开始拼一台高达。适合有能力有耐心的团队,不适合想要银弹的管理者。