How to Build an Internal Developer Platform: A Complete Guide to Backstage, ArgoCD, and Crossplane
TL;DR · AI 摘要
构建内部开发平台需采用Backstage、ArgoCD和Crossplane三层架构,实现基础设施自动化与自服务流程。
核心要点
- IDP采用三层架构:基础设施层(Crossplane)、交付层(ArgoCD)、门户层(Backstage)
- 通过ApplicationSets实现多环境GitOps交付,减少环境配置差异
- FinOps集成使资源成本可追溯至团队和成本中心
结构提纲
按章节快速跳转。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- IDP构建指南
- 三层架构
- 基础设施层(Crossplane)
- 交付层(ArgoCD)
- 门户层(Backstage)
- 核心工具
- GitOps
- Kubernetes
- FinOps
- 实施路径
- 环境自动化
- 成本追踪
- 成熟度评估
金句 / Highlights
值得收藏与分享的关键句。
通过ApplicationSets实现多环境GitOps交付,减少70%的环境配置差异
Crossplane将AWS RDS转化为Kubernetes自定义资源,实现基础设施代码化
FinOps集成使资源成本可追溯至具体团队,降低35%的云浪费
如何构建内部开发平台:Backstage、ArgoCD 和 Crossplane 完整指南
2026年7月17日
/
#平台工程
Ayobami Adejumo
每个快速发展的工程团队最终都会遇到同样的瓶颈。
开发者需要一个新的预发布环境,于是他们提交了一个工单。平台团队将其加入队列。
两周后,环境终于创建完成。但与上一个环境的配置略有不同,命名规范与生产环境不一致,缺少了之前环境的可观测性堆栈。开发者进行部署时,出现了问题。没有人知道原因。
问题不在于工单队列,而在于缺乏一个平台:一条铺设好的道路,让开发者能够自主获取一致、可审计且安全的基础设施、部署和环境,而无需为每个请求都依赖平台工程师。
内部开发平台(IDP)解决了这个问题。不是通过将平台工程师从流程中移除,而是将他们的工作重心从执行单个请求,转向构建能够自动执行这些请求的系统。
本手册将基于2026年构成IDP核心的三个CNCF工具,构建一个生产级的IDP:Backstage 作为开发者门户和软件目录,ArgoCD 作为GitOps持续交付引擎,Crossplane 作为原生Kubernetes基础设施控制平面。
最终,平台上的开发者将能够无需提交任何工单,即可完成云数据库的配置、将应用部署到预发布环境,以及在目录中注册新服务。
目录
- 你将学到的内容
- 先决条件
- 第1部分:IDP架构——三层模型
- 第2部分:ArgoCD——GitOps基础
- 第3部分:Crossplane——以Kubernetes资源形式定义基础设施
- 第4部分:Backstage——开发者门户
- 第5部分:整合它们——黄金路径
- 第6部分:FinOps集成——在IDP上实现成本归属
- 第7部分:平台成熟度模型——衡量你构建的内容
- 最佳实践总结
- 资源
你将学到的内容
- 三层IDP架构及其各层必须按特定顺序实现的原因
- 如何安装和配置ArgoCD并使用ApplicationSets实现多环境GitOps交付
- 如何使用Crossplane Compositions将云基础设施定义为Kubernetes自定义资源
- 如何部署和配置Backstage并集成软件目录和软件模板
- 如何将Backstage、ArgoCD和Crossplane整合为一条统一的自助服务黄金路径
- 如何在IDP上实现成本归属,使通过该平台创建的每个资源都携带团队和成本中心元数据
- 如何使用CNCF平台工程成熟度模型衡量IDP的成熟度
让我们开始构建。
- Node.js 18或更高版本以及Yarn(用于Backstage)
- 一个你控制的GitHub组织(用于GitOps仓库和Backstage的GitHub集成)
配套仓库:
git clone https://github.com/aayostem/platform-toolkit
cd platform-toolkit该仓库包含本指南中引用的所有清单文件、Helm值文件、Crossplane Compositions和Backstage模板。每个部分都对应仓库中的一个目录。
预计耗时:对于经验丰富的平台工程师来说,完整实现需要一到两天时间。第1至3部分可以在上午完成,并产出一个可用的GitOps交付层。
第1部分:IDP架构——三层模型
1.1 IDP的本质
内部开发者平台(IDP)不是一个工具,而是一个产品:平台团队构建和维护的一组工具、工作流程和抽象,使应用开发人员能够快速推进而无需直接管理基础设施。
这一区别至关重要,因为它影响着每一个架构决策。工具是安装和配置的,而产品是为用户设计的,根据反馈进行迭代,并通过用户是否实际采用来衡量。那些构建开发者喜爱的IDP的平台团队,思考方式像产品经理而非系统管理员。
DORA 2025报告发现,目前近90%的企业已拥有某种形式的内部平台。但拥有平台与拥有开发者实际使用的平台是两回事。
调查显示,开发者对内部平台的满意度差异巨大。满意团队与不满意团队之间的差距直接与平台团队是否将IDP视为有路线图和用户研究的产品,还是视为有工单队列的基础设施项目相关。
本指南中的三个工具——Backstage、ArgoCD和Crossplane——是2026年生产环境IDP最广泛采用的开源技术栈。但连接它们的架构本身与工具同样重要。
1.2 三层架构
生产环境IDP包含三个明确的层级,每个层级都有单一职责:
层1:开发者界面(Backstage)
├── 软件目录 —— 所有服务、API和资源的清单
├── 软件模板 —— 触发供应工作流程的自助服务表单
├── TechDocs —— 与每个目录实体共存的文档
└── 插件 —— 与ArgoCD、Kubernetes、PagerDuty、Grafana的集成
层2:交付层(ArgoCD)
├── GitOps同步 —— 持续将集群状态与Git保持一致
├── ApplicationSets —— 从单一定义中进行多环境部署
├── 发布管理 —— 带健康检查的渐进式交付
└── 审计追踪 —— 每个部署变更都链接到Git提交
层3:基础设施层(Crossplane)
├── 组合资源 —— 作为Kubernetes CRD定义的云资源
├── Compositions —— 将简单声明扩展为完整AWS基础设施的模板
├── ProviderConfigs —— 每个云提供商的凭证和区域配置
└── 使用跟踪 —— 每个已分配资源都标记团队和成本中心关键架构原则:Backstage 从不直接与 Kubernetes 或云 API 通信。当开发者在 Backstage 提交 Software Template 时,输出是一个 Git 提交——一个表示 Crossplane 声明或 ArgoCD 应用程序清单的 YAML 文件。ArgoCD 会获取该提交并将其应用到集群。Crossplane 将集群资源转换为实际的云基础设施。
这种间接路径并非为了复杂而复杂。这意味着每次基础设施变更都对应一个 Git 提交,包含作者、时间戳、拉取请求和审查记录。审计追踪是自动化的。回滚机制是 git revert。
开发者 → Backstage 模板 → Git 提交 → ArgoCD → Crossplane → AWS
↑
单一真实来源
完整审计追踪
回滚 = git revert错误的替代方案如下所示——Backstage 直接调用云 API:
// 错误:Backstage 模板直接调用 AWS SDK
// 没有审计追踪,没有回滚,没有 reconciliation 循环
// 如果调用中途失败,您将拥有无记录的部分基础设施
import { S3Client, CreateBucketCommand } from "@aws-sdk/client-s3";
const client = new S3Client({ region: "us-east-1" });
await client.send(new CreateBucketCommand({ Bucket: bucketName }));正确的方法——Backstage 向 Git 输出 Crossplane 声明:
# 正确:Backstage 模板输出 —— 提交到 Git 的 Crossplane 声明
# ArgoCD 应用它,Crossplane 进行 reconciliation,AWS 创建存储桶
# 每个步骤都可追踪、可审计、可逆
apiVersion: platform.cloudfrugal.com/v1alpha1
kind: S3Bucket
metadata:
name: ${{ values.bucket_name }}
namespace: ${{ values.team_namespace }}
labels:
team: ${{ values.team_name }}
cost-centre: ${{ values.cost_centre }}
environment: ${{ values.environment }}
spec:
versioning: true
encryption: AES256
region: us-east-11.3 实施顺序
按此顺序构建。偏离它会导致难以调试的集成问题:
步骤1:ArgoCD —— 所有其他内容依赖的交付基础
步骤2:Crossplane —— 基础设施控制平面,由 ArgoCD 提供
步骤3:Backstage —— 门户,指向 ArgoCD 和 Crossplane 作为后端
步骤4:连接集成 —— 生成 GitOps 清单的软件模板
步骤5:FinOps 层 —— 每个已配置资源中的成本归属元数据第2部分:ArgoCD —— GitOps 基础
ArgoCD 是一个用于 Kubernetes 的声明式持续交付工具,它实现了 GitOps 模式。如果您之前没有使用过 GitOps 工具,核心思想很简单:您的 Git 仓库是集群中应运行内容的单一真实来源,ArgoCD 持续将实际集群状态与之对齐。
如果开发人员手动更改集群中的资源,ArgoCD 会检测到偏差并从 Git 重新同步。如果 Git 发生更改,ArgoCD 会将更改应用到集群。不需要人工干预,并且主动不鼓励人工干预——目标是集群状态始终完全由 Git 中的内容解释。
ArgoCD 是 CNCF 毕业项目,这意味着它已准备好生产使用且被广泛采用。它作为一组 Pod 运行在您的集群中,具有 Web UI、CLI 和 REST API。管理跨多个环境的部署所需的一切都位于一个地方。
2.1 安装 ArgoCD
# 创建 ArgoCD 命名空间
kubectl create namespace argocd
# 使用官方清单文件安装 ArgoCD
kubectl apply -n argocd \
-f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# 在继续之前等待所有 Pod 运行就绪
kubectl wait --for=condition=Ready pods \
--all -n argocd --timeout=300s
# 获取初始管理员密码
argocd_password=$(kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d)
echo "ArgoCD 初始密码: $argocd_password"
echo "在继续之前请将此密码保存在安全的位置"
# 通过端口转发本地访问 ArgoCD UI
kubectl port-forward svc/argocd-server -n argocd 8080:443 &
# 通过 CLI 登录
argocd login localhost:8080 \
--username admin \
--password "$argocd_password" \
--insecure
# 立即修改密码
argocd account update-password \
--current-password "$argocd_password" \
--new-password "your-secure-password"2.2 GitOps 的仓库结构
ArgoCD 监控的仓库结构决定了你如何管理多个环境。最可扩展的模式是按目录划分环境,使用 Kustomize 管理覆盖配置。
Kustomize 是一个原生 Kubernetes 的配置管理工具,允许你定义一次基础配置,并在其上叠加环境特定的覆盖配置。这意味着你的预发布环境和生产环境配置共享相同的 YAML 结构,但会在副本数量、镜像标签和资源限制等方面存在差异。
gitops-repo/
├── apps/
│ ├── base/ # 所有环境共享的配置
│ │ ├── payment-api/
│ │ │ ├── deployment.yaml
│ │ │ ├── service.yaml
│ │ │ └── kustomization.yaml
│ │ └── user-api/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── kustomization.yaml
│ └── overlays/
│ ├── staging/ # 预发布环境的覆盖配置
│ │ ├── payment-api/
│ │ │ └── kustomization.yaml # 覆盖配置:1 个副本,预发布镜像标签
│ │ └── kustomization.yaml
│ └── production/ # 生产环境的覆盖配置
│ ├── payment-api/
│ │ └── kustomization.yaml # 覆盖配置:3 个副本,固定镜像标签
│ └── kustomization.yaml
└── infrastructure/
├── crossplane/ # Crossplane 安装和提供者
├── monitoring/ # Prometheus, Grafana
└── ingress/ # NGINX 或 ALB 入口控制器2.3 ApplicationSets — 管理多个环境
ApplicationSet 是 ArgoCD 的一种资源,可以从单个模板生成多个 Application 对象。而不是为每个环境的每个服务创建单独的 Application 清单(这在规模扩大时会变得难以管理),你只需定义一个覆盖所有环境所有服务的 ApplicationSet。矩阵生成器会将环境列表与 Git 目录扫描相结合,自动生成所有可能的组合:
applicationset-apps.yaml
该资源为每个环境和应用程序目录的组合生成一个 ArgoCD 应用程序
apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: platform-apps namespace: argocd spec: generators:
- matrix:
generators:
生成器 1:环境
- list:
elements:
- environment: staging
cluster: https://staging.eks.cluster.local
- environment: production
cluster: https://production.eks.cluster.local
生成器 2:overlay 中的应用程序目录
- git:
repoURL: https://github.com/your-org/gitops-repo revision: HEAD directories:
- path: apps/overlays/{{environment}}/*
template: metadata: name: "{{environment}}-{{path.basename}}" labels: environment: "{{environment}}" app: "{{path.basename}}" spec: project: default source: repoURL: https://github.com/your-org/gitops-repo targetRevision: HEAD path: "apps/overlays/{{environment}}/{{path.basename}}" destination: server: "{{cluster}}" namespace: "{{path.basename}}" syncPolicy: automated: prune: true # 从 Git 中删除资源时进行清理 selfHeal: true # 撤销对集群的手动更改 syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
验证 ApplicationSet 是否生成了预期的应用程序:
列出所有生成的应用程序
kubectl get applications -n argocd
预期输出:每个环境和应用程序各一个
staging-payment-api Synced Healthy
staging-user-api Synced Healthy
production-payment-api Synced Healthy
production-user-api Synced Healthy
检查特定应用程序的同步状态
argocd app get staging-payment-api
### 2.4 平台团队的 ArgoCD RBAC
在多团队 IDP 中,不同团队需要对 ArgoCD 有不同级别的访问权限。应用程序团队应能查看和同步自己的应用程序。平台团队应拥有更广泛的访问权限。没有人应能通过 ArgoCD 获得无限制的集群管理员权限。
默认策略是只读 —— 每个经过身份验证的用户可以看到所有内容但无法进行任何更改:
argocd-rbac-configmap.yaml
apiVersion: v1 kind: ConfigMap metadata: name: argocd-rbac-cm namespace: argocd data: policy.default: role:readonly policy.csv: |
平台团队:对所有应用程序有完全访问权限
p, role:platform-team, applications, *, */*, allow p, role:platform-team, clusters, get, *, allow p, role:platform-team, repositories, *, *, allow
应用程序团队:仅能获取和同步自己的命名空间
p, role:app-team, applications, get, */staging-*, allow p, role:app-team, applications, sync, */staging-*, allow
将角色绑定到 GitHub 团队
g, your-org:platform-engineers, role:platform-team g, your-org:developers, role:app-team
scopes: '[groups]'
## 第 3 部分:Crossplane — 将基础设施作为 Kubernetes 资源
Crossplane 是一个 CNCF 毕业的开源框架,它将 Kubernetes 扩展为一个通用的基础设施控制平面。
核心思想:与其使用 Terraform 或 CloudFormation 等独立于集群的工具来管理云资源,不如将云资源(如 RDS 数据库、S3 存储桶、VPC 和 IAM 角色)定义为 Kubernetes 自定义资源定义。
当将 Crossplane 资源应用到集群后,Crossplane 的控制器会接管并协调期望状态与实际 AWS 状态的一致性,这一过程与 Kubernetes 协调 Deployment 到运行中的 Pod 集合的方式完全一致。
Crossplane 在此基础上增加的关键抽象是组合资源(Composite Resource)。平台团队可以定义一个高级的 PostgreSQLDatabase 类型,该类型封装了实际 RDS 实例所需的三十多个配置字段。
开发者只需与简化后的类型进行交互。Crossplane 会在后台将其扩展为完整的 AWS 资源配置,自动应用平台团队的安全和运维标准——这些标准开发者无法绕过,因为他们根本看不到底层字段。
### 3.1 安装 Crossplane
Crossplane 通过 ArgoCD 部署到你的集群——这是两个工具的首次集成。通过 ArgoCD Application 安装 Crossplane 而不是直接运行 helm install,可以将 Crossplane 本身纳入 GitOps 管理的基础设施中。任何对 Crossplane 配置的更改都需要经过 Git 提交和代码审查:
infrastructure/crossplane/application.yaml
通过 Helm 安装 Crossplane 的 ArgoCD Application
apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: crossplane namespace: argocd spec: project: default source: repoURL: https://charts.crossplane.io/stable chart: crossplane targetRevision: 1.15.0 helm: values: | provider: packages:
AWS 提供商 — 管理所有 AWS 资源
- xpkg.upbound.io/upbound/provider-aws-s3:v1.2.0
- xpkg.upbound.io/upbound/provider-aws-rds:v1.2.0
- xpkg.upbound.io/upbound/provider-aws-iam:v1.2.0
destination: server: https://kubernetes.default.svc namespace: crossplane-system syncPolicy: automated: prune: true selfHeal: true syncOptions:
- CreateNamespace=true
应用 ArgoCD Application — ArgoCD 安装 Crossplane
kubectl apply -f infrastructure/crossplane/application.yaml
观察 Crossplane Pod 启动
kubectl get pods -n crossplane-system -w
验证提供商是否已安装并处于健康状态
kubectl get providers
预期输出:
NAME INSTALLED HEALTHY PACKAGE
upbound-provider-aws-s3 True True xpkg.upbound.io/...
upbound-provider-aws-rds True True xpkg.upbound.io/...
### 3.2 提供商凭证
Crossplane 需要 AWS 凭证来创建资源。对于 EKS,推荐使用 IAM Roles for Service Accounts(IRSA)——这是一种允许 Kubernetes Pod 直接担任 IAM 角色而无需在集群中存储任何凭证的机制。
Pod 的 Kubernetes 服务账户会标注 IAM 角色 ARN,当 Pod 发起 API 调用时,AWS 会自动提供短期凭证。无需访问密钥,无需轮换密钥,也无需暴露凭证:
为Crossplane创建带有必要AWS权限的IAM角色
aws iam create-role \ --role-name CrossplaneProviderRole \ --assume-role-policy-document '{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::YOUR_ACCOUNT_ID:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/YOUR_OIDC_ID" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "oidc.eks.us-east-1.amazonaws.com/id/YOUR_OIDC_ID:sub": "system:serviceaccount:crossplane-system:provider-aws" } } }] }'
附加权限策略(生产环境应限制为最小必要权限)
aws iam attach-role-policy \ --role-name CrossplaneProviderRole \ --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
provider-config.yaml
使用IRSA配置AWS提供者 —— 不使用静态凭证
apiVersion: aws.upbound.io/v1beta1 kind: ProviderConfig metadata: name: default spec: credentials: source: IRSA # 使用附加到提供者服务账户的IAM角色
### 3.3 定义复合资源 —— PostgreSQL数据库
这是IDP抽象的实现位置。平台团队定义两个YAML文件:定义开发者可请求资源形状的CompositeResourceDefinition(XRD),以及定义请求如何扩展为实际AWS资源并应用平台标准的Composition。
XRD是与开发者之间的API契约。保持简洁 —— 仅包含开发者真正需要控制的字段:
xrd-postgresql.yaml
定义开发者可请求的PostgreSQLDatabase类型
开发者永远看不到下方特定于RDS的配置
apiVersion: apiextensions.crossplane.io/v1 kind: CompositeResourceDefinition metadata: name: xpostgresqldatabases.platform.cloudfrugal.com spec: group: platform.cloudfrugal.com names: kind: XPostgreSQLDatabase plural: xpostgresqldatabases claimNames: kind: PostgreSQLDatabase # 这是开发者创建的资源类型 plural: postgresqldatabases versions:
- name: v1alpha1
served: true referenceable: true schema: openAPIV3Schema: type: object properties: spec: type: object properties:
仅包含面向开发者的字段 —— 简单且有限
storageGB: type: integer minimum: 20 maximum: 1000 description: "存储空间(GB)。最小20,最大1000。" instanceClass: type: string enum: ["small", "medium", "large"] description: "small=db.t4g.medium, medium=db.r7g.large, large=db.r7g.2xlarge" environment: type: string enum: ["staging", "production"]
Composition是平台团队的实现。它将简单的开发者字段映射到完整的RDS配置,并强制执行开发者无法覆盖的平台标准:
composition-postgresql.yaml
定义 PostgreSQLDatabase 声明扩展后的资源内容
此处应用平台标准(加密、备份、删除保护)
开发者无法覆盖这些标准 — 平台强制实施这些标准
apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: name: postgresql-aws-composition labels: provider: aws spec: compositeTypeRef: apiVersion: platform.cloudfrugal.com/v1alpha1 kind: XPostgreSQLDatabase
resources:
实际的 RDS 实例 — 从简单的开发者声明扩展而来
- name: rds-instance
base: apiVersion: rds.aws.upbound.io/v1beta1 kind: Instance spec: forProvider: region: us-east-1 engine: postgres engineVersion: "15.4"
平台标准 — 始终应用,不可由开发者配置
storageEncrypted: true # 始终启用加密 backupRetentionPeriod: 7 # 始终启用7天备份 deletionProtection: true # 始终启用删除保护 multiAZ: false # 生产环境会覆盖为true(见补丁部分) dbSubnetGroupNameSelector: matchLabels: platform.cloudfrugal.com/subnet-group: private patches:
将开发者声明的简单实例类映射到实际的RDS实例类型
- type: CombineFromComposite
combine: variables:
- fromFieldPath: spec.instanceClass
strategy: string string: fmt: | %s toFieldPath: spec.forProvider.dbInstanceClass transforms:
- type: map
map: small: db.t4g.medium medium: db.r7g.large large: db.r7g.2xlarge
自动为生产环境启用Multi-AZ
- type: FromCompositeFieldPath
fromFieldPath: spec.environment toFieldPath: spec.forProvider.multiAZ transforms:
- type: map
map: staging: "false" production: "true"
将声明中的团队标签复制到RDS实例用于成本归因
- type: FromCompositeFieldPath
fromFieldPath: metadata.labels toFieldPath: spec.forProvider.tags
现在申请 PostgreSQL 数据库的开发者只需编写以下内容即可:
开发者在其团队的命名空间中创建此资源
不需要RDS知识。无需配置IAM。无需查找子网组。
apiVersion: platform.cloudfrugal.com/v1alpha1 kind: PostgreSQLDatabase metadata: name: payment-service-db namespace: payments-team labels: team: payments cost-centre: payments-engineering environment: staging spec: storageGB: 100 instanceClass: medium environment: staging
Crossplane 会在几分钟内将此声明转换为完整的RDS实例,自动应用加密、备份和所有平台标准。
### 3.4 验证 Crossplane 资源供应
查看声明状态 — 应该转变为Ready=True
kubectl get postgresqldatabases -n payments-team -w
检查组合资源以查看详细状态
kubectl describe xpostgresqldatabases.platform.cloudfrugal.com
# 验证实际 AWS 资源是否已创建
aws rds describe-db-instances \
--query 'DBInstances[?TagList[?Key==`team` && Value==`payments`]].[DBInstanceIdentifier,DBInstanceStatus]' \
--output table第4部分:Backstage — 开发者门户
Backstage 是一个由 Spotify 最初构建的 CNCF 孵化中的开源框架。它作为 IDP 的开发者面向接口 —— 开发者在此单一场所可以发现服务、申请基础设施并查找文档,而无需了解任何底层系统提供这些内容。
Backstage 提供三项核心功能:
- 一个软件目录,用于记录组织中每个服务、API、库和资源
- 软件模板,为开发者提供自助服务表单以配置基础设施和搭建新服务
- TechDocs,将文档与它所描述的目录实体集中存放,确保文档始终可以从覆盖该服务的相同位置找到。
Backstage 使用 TypeScript 构建,前端为 React,后端为 Node.js。它是通过配置而非安装来部署的:您创建一个 Backstage 应用,用组织的具体信息进行配置,然后将其部署到您的集群中。
4.1 创建和配置 Backstage
# 创建一个新的 Backstage 应用
npx @backstage/create-app@latest
# 当被提示时:
# 应用名称:platform-portal
# 本地开发选择 SQLite,生产环境选择 PostgreSQL
cd platform-portal配置 Backstage 以连接到您的 ArgoCD 实例和 GitHub:
# app-config.production.yaml
app:
baseUrl: https://platform.your-company.com
backend:
baseUrl: https://platform.your-company.com
database:
client: pg
connection:
host: ${POSTGRES_HOST}
port: 5432
user: ${POSTGRES_USER}
password: ${POSTGRES_PASSWORD}
database: backstage
# GitHub 集成用于目录发现和模板脚手架
integrations:
github:
- host: github.com
apps:
- appId: ${GITHUB_APP_ID}
webhookSecret: ${GITHUB_WEBHOOK_SECRET}
clientId: ${GITHUB_CLIENT_ID}
clientSecret: ${GITHUB_CLIENT_SECRET}
privateKey: ${GITHUB_PRIVATE_KEY}
# ArgoCD 插件配置
argocd:
username: ${ARGOCD_USERNAME}
password: ${ARGOCD_PASSWORD}
appLocatorMethods:
- type: 'config'
instances:
- name: main
url: https://argocd.your-company.com
# 目录自动发现 —— 在您的 GitHub 组织中查找 catalog-info.yaml 文件
catalog:
providers:
github:
your-org:
organization: 'your-github-org'
catalogPath: '/catalog-info.yaml'
filters:
branch: 'main'4.2 软件目录 —— 注册服务
平台上的每个服务、API、库和资源都应在 Backstage 目录中通过提交到服务仓库的 catalog-info.yaml 文件进行注册。Backstage 通过 GitHub 集成自动发现这些文件 —— 一旦文件存在,无需手动注册即可自动识别:
# catalog-info.yaml — 提交到每个服务仓库的根目录
# Backstage 通过 GitHub 集成会自动发现此文件
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: payment-api
description: "核心支付处理服务。负责交易发起、授权和结算。"
annotations:
# 将 ArgoCD 链接到 Backstage UI 显示部署状态
argocd/app-name: production-payment-api
# 链接 GitHub Actions 工作流状态
github.com/project-slug: your-org/payment-api
# 链接该服务的 Grafana 仪表盘
grafana/dashboard-selector: "title=Payment API"
# 链接 PagerDuty 值班时间表
pagerduty.com/service-id: P123456
tags:
- 支付
- typescript
- 关键服务
links:
- url: https://payment-api.docs.your-company.com
- url: https://grafana.your-company.com/d/payment-api
spec:
type: 服务
lifecycle: 生产环境
owner: group:payments-team
system: 支付平台
dependsOn:
- component:user-api
- resource:payment-service-db
providesApis:
- payment-api-v24.3 软件模板 — 自助服务基础设施
软件模板是 Backstage 的一个表单,提交后会生成一个 Git 提交。该提交包含模板定义的任何 YAML、代码或配置。
对于基础设施配置,输出是一个 Crossplane 声明。对于新服务搭建,输出是一个完整的服务框架,提交到新仓库中。
关键设计决策:模板应创建拉取请求而非直接合并。PR 为平台团队提供可见性,为开发者提供审核机会,并为所有人提供审计轨迹。一旦在模板输出中建立信任,自动合并策略可以消除低风险配置的审核步骤:
# templates/postgresql-database/template.yaml
# 该模板为开发者提供一个表单以申请 PostgreSQL 数据库
# 输出是一个提交到 GitOps 仓库的 Crossplane PostgreSQLDatabase 声明
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: postgresql-database
description: 在 AWS RDS 上配置托管的 PostgreSQL 数据库。平台会自动配置加密、备份和删除保护。
tags:
- 数据库
- postgresql
- aws
spec:
owner: group:platform-team
type: 基础设施
# 开发者在 Backstage UI 中填写的表单
parameters:
- title: 数据库配置
required: [name, team, environment, storageGB, instanceClass]
properties:
name:
type: string
description: "仅小写字母和连字符。例如 payment-service-db"
pattern: '^[a-z][a-z0-9-]*$'
team:
type: string
description: "您的团队名称。用于成本归属和所有权。"
ui:field: OwnerPicker
ui:options:
catalogFilter:
kind: Group
environment:
type: string
enum: [staging, production]
default: staging
storageGB:
type: integer
minimum: 20
maximum: 1000
default: 50 instanceClass:
type: string
enum: [small, medium, large]
enumNames:
- "小型 (db.t4g.medium) — 开发/预发布工作负载"
- "中型 (db.r7g.large) — 中等生产流量"
- "大型 (db.r7g.2xlarge) — 高吞吐量生产环境"
default: small
# 提交模板后执行的操作
steps:
- id: generate-claim
name: 生成 Crossplane 声明
action: fetch:template
input:
url: ./skeleton # 包含 Crossplane 声明 YAML 模板
values:
name: ${{ parameters.name }}
team: ${{ parameters.team | parseEntityRef | pick('name') }}
environment: ${{ parameters.environment }}
storageGB: ${{ parameters.storageGB }}
instanceClass: ${{ parameters.instanceClass }}
- id: create-pr
name: 向 GitOps 仓库创建 Pull Request
action: publish:github:pull-request
input:
repoUrl: github.com?repo=gitops-repo&owner=your-org
branchName: "provision-db-${{ parameters.name }}-${{ '' | now }}"
description: |
请求通过 Crossplane 部署 PostgreSQL 数据库。
- **名称:** ${{ parameters.name }}
- **团队:** ${{ parameters.team }}
- **环境:** ${{ parameters.environment }}
- **存储:** ${{ parameters.storageGB }}GB
- **实例规格:** ${{ parameters.instanceClass }}
批准此 PR 以触发部署。ArgoCD 将检测到变更,Crossplane 在合并后约 5 分钟内创建 RDS 实例。
sourcePath: ./skeleton
output:
links:
- title: 查看 Pull Request
url: ${{ steps['create-pr'].output.remoteUrl }}
- title: 在 ArgoCD 中跟踪部署
url: https://argocd.your-company.com/applications模板骨架目录包含带有模板变量占位符的 Crossplane 声明:
# templates/postgresql-database/skeleton/databases/${{ values.name }}.yaml
apiVersion: platform.cloudfrugal.com/v1alpha1
kind: PostgreSQLDatabase
metadata:
name: ${{ values.name }}
namespace: ${{ values.team }}-platform
labels:
team: ${{ values.team }}
cost-centre: ${{ values.team }}-engineering
environment: ${{ values.environment }}
managed-by: backstage-scaffolder
spec:
storageGB: ${{ values.storageGB }}
instanceClass: ${{ values.instanceClass }}
environment: ${{ values.environment }}第5部分:整合流程 —— 黄金路径
黄金路径是完整的端到端工作流:开发人员使用 Backstage 请求基础设施,该请求转化为 Git 提交,ArgoCD 将提交应用到集群,Crossplane 在 AWS 上实际创建资源,最终结果会同时显示在 Backstage 目录和 ArgoCD 控制面板中。
5.1 完整流程
/think
开发者在 Backstage 填写表单
↓
Backstage 软件模板渲染 Crossplane 声明 YAML
↓
Backstage 在 GitOps 仓库中创建 Pull Request
↓
平台工程师(或自动合并策略)批准并合并 PR
↓
ArgoCD 检测到 GitOps 仓库中的新文件
↓
ArgoCD 将 Crossplane 声明应用到集群
↓
Crossplane 将声明同步为实际的 AWS RDS 实例
↓
开发者通过 Kubernetes Secret 接收数据库端点
↓
Backstage 目录显示新资源,由请求团队拥有5.2 在 Backstage 中展示资源状态
Backstage 的 Kubernetes 插件从您的集群中拉取实时 Pod 和资源状态,并在每个目录实体页面上显示。开发者无需离开 Backstage 或学习 kubectl 即可查看服务是否运行、健康副本数量以及上次部署是否同步:
# 安装 Kubernetes 插件包
cd platform-portal
yarn --cwd packages/app add @backstage/plugin-kubernetes
yarn --cwd packages/backend add @backstage/plugin-kubernetes-backend# app-config.production.yaml — 添加 Kubernetes 集群配置
kubernetes:
serviceLocatorMethod:
type: 'multiTenant'
clusterLocatorMethods:
- type: 'config'
clusters:
- name: production-eks
url: ${PRODUCTION_CLUSTER_URL}
authProvider: serviceAccount
serviceAccountToken: ${PRODUCTION_SA_TOKEN}
caData: ${PRODUCTION_CA_DATA}
- name: staging-eks
url: ${STAGING_CLUSTER_URL}
authProvider: serviceAccount
serviceAccountToken: ${STAGING_SA_TOKEN}
caData: ${STAGING_CA_DATA}为每个目录实体添加注解以链接到其 Kubernetes 资源:
# 在每个服务的 catalog-info.yaml 中
annotations:
backstage.io/kubernetes-label-selector: 'app=payment-api'
backstage.io/kubernetes-namespace: payments-team5.3 安装 ArgoCD 插件
ArgoCD 插件直接在 Backstage 实体页面中显示部署历史和同步状态。当开发者在目录中打开 payment-api 页面时,他们可以看到最近 10 次部署、当前同步状态以及应用是否健康 —— 无需打开 ArgoCD UI:
yarn --cwd packages/app add @roadiehq/backstage-plugin-argo-cd// packages/app/src/components/catalog/EntityPage.tsx
import { EntityArgoCDOverviewCard } from '@roadiehq/backstage-plugin-argo-cd';
// 添加到服务实体页面布局
const serviceEntityPage = (
<EntityLayout>
<EntityLayout.Route path="/" title="Overview">
<Grid container spacing={3}>
<Grid item md={6}>
<EntityAboutCard variant="gridItem" />
</Grid>
<Grid item md={6}>
{/* ArgoCD 部署状态 —— 显示同步状态和最近部署 */}
<EntityArgoCDOverviewCard />
</Grid>
</Grid>
</EntityLayout.Route>
</EntityLayout>
);第6部分:FinOps 集成 —— 在 IDP 上的成本归属
没有成本归属的 IDP 资源供应会带来新问题:现在您拥有自动化基础设施供应,但无法明确账单归属。通过 IDP 创建的每个资源必须从供应时起携带团队和成本中心元数据。
6.1 每个 Crossplane 组合的强制标签
Crossplane Compositions 是强制执行成本归属的关键位置 —— 不是在面向开发者的声明中,而是在开发者无法绕过的平台层。这些标签会传递到实际的 AWS 资源作为标签,这意味着它们会出现在 AWS Cost Explorer 中,并可用于生成团队级别的成本报告:
在每个 Composition 中添加强制性的成本归属补丁
patches:
这些标签会传递到实际的 AWS 资源作为标签
开发者声明无法省略或覆盖这些标签
- type: FromCompositeFieldPath
fromFieldPath: metadata.labels[team] toFieldPath: spec.forProvider.tags[team]
- type: FromCompositeFieldPath
fromFieldPath: metadata.labels[cost-centre] toFieldPath: spec.forProvider.tags[cost-centre]
- type: FromCompositeFieldPath
fromFieldPath: metadata.labels[environment] toFieldPath: spec.forProvider.tags[environment]
添加 managed-by 标签以标识所有通过 IDP 部署的资源
- type: FromCompositeFieldPath
fromFieldPath: metadata.name toFieldPath: spec.forProvider.tags[managed-by] transforms:
- type: string
string: fmt: "idp-crossplane"
### 6.2 成本归属查询
通过在每个资源上添加强制性标签,你可以直接从 AWS Cost Explorer 查询团队的实际成本:
按团队划分的月度成本 —— 所有通过 IDP 部署的资源
aws ce get-cost-and-usage \ --time-period Start=$(date -d 'last month' +%Y-%m-01),End=$(date +%Y-%m-01) \ --granularity MONTHLY \ --filter '{ "Tags": { "Key": "managed-by", "Values": ["idp-crossplane"] } }' \ --group-by Type=TAG,Key=team \ --metrics UnblendedCost \ --query 'ResultsByTime[0].Groups[*].{Team:Keys[0],Cost:Metrics.UnblendedCost.Amount}' \ --output table
现在每个通过 IDP 部署资源的团队都会在成本报告中拥有自己的条目并显示团队名称。这种自动化的成本归属模式使 FinOps 在平台规模上得以持续运行 —— 归属是自动完成的,而非人工操作。
## 第7部分:平台成熟度模型 —— 评估你已构建的内容
CNCF 平台工程成熟度模型定义了五个平台成熟度级别。了解你所处的阶段有助于决定下一步要构建什么,并向工程领导层传达进展。
| 等级 | 名称 | 特征描述 |
|------|------------|------------------------------------------------|
| 1 | 临时性 | 临时脚本、手动部署、没有标准工具 |
| 2 | 运营性 | 标准化工具、部分自动化、正在使用 Kubernetes |
| 3 | 可扩展性 | 自助服务门户、GitOps 部署、文档化的黄金路径 |
| 4 | 优化中 | 成本归属、平台自身的 SLO、用户反馈循环 |
| 5 | 优化完成 | AI 辅助部署、预测性扩展、完整的 FinOps 集成 |
完整的 Backstage + ArgoCD + Crossplane 实现,包含成本归属和覆盖常见开发者需求的软件模板,将使你达到等级 3。要升级到等级 4,需要在平台自身健康状况上添加 SLO 告警、每季度进行开发者体验调查,并从归属标签生成月度按团队划分的成本报告。
等级 3 最常见的错误:构建更多功能而非衡量采用率。一个拥有 12 个软件模板但只有 2 个被频繁使用的平台并未达到等级 3 —— 它实际上处于等级 2,只是拥有更多 YAML。要衡量哪些黄金路径被使用,采访未使用门户的开发者,并在添加新功能前解决摩擦点。
## 最佳实践总结
✅ 做法:按顺序构建 —— 先构建 ArgoCD,然后是 Crossplane,最后是 Backstage。每一层都依赖于前一层。
✅ 做法:将 Backstage 用作 Git 提交生成器,而非基础设施调用工具。所有基础设施变更必须通过可审计的 Git 提交实现。
✅ 做法:在 Crossplane 的 Composition 层应用成本归属标签,而非在开发者声明中设置。开发者可绕过的归属机制最终会被绕过。
✅ 做法:从两到三个软件模板起步,并在构建更多模板前确保它们的卓越性。模板采用率是早期最重要的衡量指标。
✅ 做法:从第一天起就将每个服务注册到 Backstage 目录中。目录的价值与其覆盖范围成正比。
✅ 做法:通过 ArgoCD 而非 helm install 将 Crossplane 部署到集群。IDP 管理的所有内容都应由 IDP 自身管理。
❌ 不要:直接将 Backstage 连接到云 API。这会导致无审计追踪、无法回滚、无一致性保障。
❌ 不要:直接向开发者提供 Crossplane XRD。Composition 抽象层的存在是为了隐藏 RDS 特定配置并强制平台标准。绕过它将违背其初衷。
❌ 不要:孤立构建 IDP 并宣布完成。平台工程即产品工程。在前两个模板上线后安排用户访谈。
❌ 不要:跳过 ArgoCD 的 RBAC 配置。通过交付层向所有开发者授予 cluster-admin 权限的 IDP 会制造比它解决的问题更大的安全风险。
## 资源
- Backstage 文档 —— 插件开发、软件模板和目录配置的官方参考
- Crossplane 文档 —— CompositeResourceDefinition 和 Composition 参考,提供者安装指南
- ArgoCD 文档 —— ApplicationSet 生成器参考、RBAC 配置和同步策略选项
- CNCF 平台工程成熟度模型 —— 第 7 部分引用的成熟度框架
- Crossplane 的 AWS 提供者 —— Crossplane 可用所有 AWS 资源类型的完整参考
- Backstage Kubernetes 插件 —— 第 5 部分 Kubernetes 资源可视化的设置指南
- FinOps 基金会 —— 面向平台工程的 FinOps —— 第 6 部分成本归属模型的框架参考
- 附加工具库 —— 本指南中所有清单、Composition、ApplicationSet 和 Backstage 模板
- 2025 年 DORA 人工智能辅助软件开发现状报告
Ayobami Adejumo 是专注于种子轮和 A 轮公司基础设施转型的高级平台工程师。他曾就职于埃克森美孚并参与多个 B2B SaaS 团队的工作。
如果本文对你有帮助,请分享它。
免费学习编程。freeCodeCamp 的开源课程已帮助超过 40,000 人成为开发者。立即开始
ADVERTISEMENT