第2章 内部开发者平台(IDP)
平台的架构与组成
章节导读
如果说平台工程是一门学科,那么内部开发者平台(Internal Developer Platform,IDP)就是这门学科的「实验 apparatus」——所有理念最终都要通过 IDP 这个技术载体交付给开发者。但 IDP 恰恰是最容易被误解的概念:许多组织把「买一个开发者门户产品」等同于「建设 IDP」,结果门户上线后无人问津,因为它背后没有自动化能力支撑,只是一个漂亮的空壳。本章的任务是给出 IDP 的精确定义与边界,剖析其架构分层,梳理开源生态,并提供「自建 vs 采购 vs 开源组合」的决策框架。
社区对 IDP 最广为接受的定义来自 internaldeveloperplatform.org:「内部开发者平台由许多技术栈和工具组成,这些技术栈和工具被粘合在一起,为开发者提供自助服务的能力,贯穿整个软件开发生命周期。IDP 就像一份组装说明书,由平台团队精心编排,让开发者能够以最佳模式自主构建和交付产品。」这个定义中有三个关键词值得反复咀嚼。第一是「许多技术栈和工具的粘合」——IDP 不是单一产品,而是能力集合;它可能同时包含 Backstage(门户)、Crossplane(基础设施编排)、ArgoCD(GitOps 部署)、Tekton(流水线)、Vault(密钥)、Datadog(可观测性),IDP 的价值在于把这些工具「粘合」成连贯的体验,而不是发明新工具。第二是「自助服务」——这是 IDP 的验收标准:开发者能否在不与平台团队交互的情况下完成日常任务。第三是「平台团队精心编排」——IDP 是设计出来的产品,不是工具的自然堆积;没有产品思维的编排,工具再多也只是「碎片化的另一种形式」。
理解 IDP 最好的历史案例是 Spotify Backstage 的诞生。2016 年前后,Spotify 拥有数百个微服务与几十个自治小队,工程效率的瓶颈从「写代码」转移到了「管理服务的元数据与生命周期」:没人知道某个服务的所有者是谁,创建新服务需要复制粘贴旧仓库再手工修改十几处配置,各团队的部署方式五花八门。Spotify 的解决方案不是购买工具,而是内部构建一个「开发者门户」:以软件目录(Software Catalog)为核心数据模型,把每个服务、API、数据集、网站的元数据集中管理;在目录之上叠加脚手架模板(Software Templates,一键创建符合规范的新服务)、TechDocs(文档即代码)、以及数百个插件(集成 CI/CD、监控、告警、成本数据)。2020 年 Backstage 开源并捐赠给 CNCF,如今已有超过 2800 家组织在使用,形成了拥有数千插件的生态系统。Backstage 的成功验证了一个关键洞察:IDP 的核心不是 UI,而是「以目录为中心的元数据模型 + 在其上编排的自动化能力」。
从架构视角看,成熟的 IDP 通常呈现三层结构。最上层是「门户层」(Portal/Interface Layer):开发者直接交互的界面,包括 Web 门户、CLI 工具、IDE 插件、ChatOps 机器人(Slack/Teams 集成)与 API。门户层的设计原则是「多入口、一致体验」——开发者可以在自己习惯的环境中触发平台能力。中间是「能力层」(Capability Layer,也称编排层):把底层工具的能力封装为面向开发者任务的「服务」,如「创建服务」「部署到生产」「申请数据库」。这一层是 IDP 的灵魂,它负责工作流编排(一个「创建服务」动作可能串联 Git 仓库创建、CI 配置注入、K8s namespace 分配、监控注册、目录登记五个步骤)、策略执行与审计。最底层是「基础设施层」(Infrastructure Layer):Kubernetes 集群、云资源、CI/CD 引擎、可观测性后端、密钥管理系统等实际执行工作的工具。IDP 与 Kubernetes 的关系尤其值得澄清:K8s 是当今 IDP 最常见的底座(因为其声明式 API、控制器模式与多租户能力天然适合平台编排),但 K8s 本身不是 IDP——直接让业务开发者操作 K8s YAML 恰恰是 IDP 要消除的认知负担;IDP 是架设在 K8s 之上的抽象层,把「namespace + deployment + service + ingress + configmap + secret + serviceaccount + networkpolicy」的八件套封装为「一个环境」这样的领域概念。
开源生态方面,2024 年的 IDP 版图已经相当丰富:Backstage 提供门户与目录骨架;Crossplane 把云资源纳入 K8s API 管理;KubeVela 提供以应用为中心的交付抽象与多环境工作流;Port、OpsLevel、Cortex 是商业化的软件目录/门户产品;Humanitec 的 Score 框架探索「工作负载规范与平台解耦」的标准化;Kratix 提出「平台即产品」的框架化实现。面对这个生态,技术领导者最常见的困惑是:自建、采购还是开源组合?本章将给出一个基于组织规模、工程能力、差异化需求与总拥有成本(TCO)四维度的决策框架。一个经验法则是:门户与目录层优先采用开源或商业产品(差异化价值低、重复造轮子成本高),能力层的编排逻辑值得自建(它编码了你组织特有的最佳实践与合规要求),基础设施层直接使用云厂商与 CNCF 成熟项目。IDP 建设的真正难点从来不是选工具,而是定义「平台应该暴露哪些能力、以什么抽象暴露」——这是产品设计与架构设计的结合,也是后续章节反复深入的主题。
核心概念
- IDP
- 服务目录
- Backstage
- 平台架构
要点精析
【IDP 的定义与边界:能力集合而非单一工具】IDP 最精确的理解方式是「能力的集合与粘合层」。判断一个系统是否是 IDP,可以用三个测试:自助服务测试——开发者能否独立完成高频任务(创建服务、部署、扩缩容、查日志)而无需平台团队人工介入?生命周期覆盖测试——能力是否贯穿从脚手架到退役的完整生命周期,而非只覆盖某个片段(如只有 CI 没有环境管理)?编排测试——底层多个工具的动作是否被编排为面向任务的连贯工作流,而非简单地并列摆放?三个测试都通过,才称得上 IDP。边界方面需要澄清 IDP「不是什么」:它不是 PaaS 的简单同义词——传统 PaaS(如 Cloud Foundry)倾向于强约束的单一运行时抽象,而 IDP 强调可组合与可定制;它不是运维工单系统的门户化——如果「自助」只是把工单表单搬到网页上,本质仍是人工响应;它也不是监控大盘的聚合——没有自动化执行能力的可视化只是「只读平台」。CNCF 白皮书特别强调,IDP 的价值在于「为开发者提供恰到好处的抽象」:抽象太少,认知负担依旧;抽象太多太死,平台变成牢笼。边界的艺术在于:平台暴露「任务级」接口(部署我的服务),隐藏「资源级」细节(Pod 调度策略),同时保留「逃生舱口」(高级用户可下钻修改底层配置)。
【IDP 的核心组成:五大能力域】一个完整的 IDP 通常覆盖五大能力域。第一,服务目录(Service Catalog):集中管理所有服务、API、资源、团队的元数据与所有权关系,是 IDP 的「数据中枢」——其他能力(脚手架、部署、可观测性、成本分摊)都以目录实体为锚点。第二,脚手架与模板(Scaffolding):一键创建符合黄金路径的新服务/新资源,包括代码仓库、CI 配置、部署清单、监控注册的自动化初始化,把「创建服务的正确方式」固化为可执行模板。第三,部署与环境自动化(Deployment & Environments):自助创建/销毁开发、测试、预发环境,标准化的部署流水线,渐进式交付(金丝雀/蓝绿)能力,环境间配置与密钥的差异化管理。第四,可观测性集成(Observability Integration):日志、指标、追踪的默认接入与标准化仪表盘,告警模板,从服务目录一键跳转到该服务的监控视图。第五,安全与合规能力(Security & Compliance):密钥管理、镜像扫描、策略执行、审计日志、合规报告的自助化。五大能力域并非要求一次性全部建成——TVP 原则建议从痛点最集中的 1-2 个能力域切入。但架构设计时应预留全部五个域的扩展点,尤其是目录的数据模型要提前设计好,因为后期更换目录系统的迁移成本极高(所有自动化都引用目录实体 ID)。
【IDP 架构模式:门户层、能力层、基础设施层】三层架构是 IDP 设计的标准参考模型。门户层解决「交互」问题:Web UI 适合探索性任务(浏览目录、查看仪表盘),CLI 适合高频重复任务与脚本集成(开发者可以在自己的自动化中调用平台 CLI),IDE 插件把平台能力嵌入编码现场(在 VS Code 中直接创建服务、查看部署状态),ChatOps 适合协作性任务与通知(在 Slack 中审批部署、接收告警),API 则是所有界面的基础——成熟平台坚持「API-first」,任何 UI 能做的操作都有对应 API,这保证了平台能力可被程序化组合。能力层解决「编排」问题:其核心是工作流引擎与策略引擎。工作流引擎把跨系统的多步骤操作编排为原子化的「平台动作」,需要处理幂等性(重试不产生副作用)、补偿(部分失败时回滚)、异步长任务(环境创建可能需要 20 分钟)与审计(谁在何时做了什么)。策略引擎(OPA、Kyverno 等)在编排的关键节点执行准入校验——配额、安全基线、合规规则。基础设施层解决「执行」问题:K8s、云 API、CI/CD 引擎、Vault、可观测性后端。三层之间的接口设计决定了平台的可演进性:能力层应通过声明式 API 与基础设施层交互(而非硬编码的脚本调用),门户层应通过能力层的统一 API 交互(而非直接调用底层工具),这样才能在替换底层工具时保持上层体验稳定。
【开源 IDP 生态:Backstage、Crossplane、KubeVela 与 Port】主流开源/商业组件各有清晰的定位。Backstage(CNCF 孵化):以软件目录为核心的开发者门户框架,强项是元数据模型、插件生态(数千个社区插件)与脚手架模板系统;弱项是它本质是「前端框架 + 目录」,不包含底层自动化执行能力,需要与其他工具组合;采用 TypeScript/React 技术栈,定制需要前端工程能力。Crossplane(CNCF 毕业):把云基础设施(数据库、网络、存储、IAM)建模为 K8s 自定义资源(CRD),通过 Composition 机制让平台团队定义「复合资源」(如一个「生产级 PostgreSQL」组合了 RDS 实例 + 备份策略 + 监控 + 网络规则),开发者只需申请复合资源;它是「基础设施层能力 API 化」的关键组件。KubeVela(CNCF 孵化):以应用为中心的交付平台,其 OAM(Open Application Model)抽象把应用定义为「组件 + 运维特征 + 工作流」,原生支持多环境、多集群交付与自助运维操作;适合需要复杂应用编排的场景。Port、OpsLevel、Cortex(商业 SaaS):提供开箱即用的目录 + 门户 + 记分卡(scorecards,用规则度量服务的生产就绪度)能力,省去自建维护成本,代价是订阅费用与数据出域的合规考量。选型的核心问题不是「哪个最好」,而是「哪些能力买、哪些能力建」——下一要点展开。
【IDP 与 Kubernetes 的关系:底座与抽象层】Kubernetes 在 IDP 中扮演的角色需要精确界定:它是平台最常用、最强大的「基础设施层底座」,但绝不是「开发者接口」。K8s 适合做底座的原因有四:声明式 API 与最终一致性模型(期望状态写入 etcd,控制器持续调和)天然适合自动化编排;CRD + Operator 模式允许平台团队把任何领域概念(环境、数据库申请、部署策略)扩展为一等公民 API;RBAC、namespace、ResourceQuota、NetworkPolicy 提供了多租户隔离的原生原语;庞大的 CNCF 生态(ArgoCD、Tekton、Cert-Manager、Prometheus Operator)都以 K8s 为集成点。但 K8s 的抽象层级对业务开发者太低:部署一个简单 Web 服务需要理解 Deployment、Service、Ingress、ConfigMap、Secret、ServiceAccount、HPA、PDB 等近十种资源及其相互作用——这正是认知负担的来源。IDP 的使命是在 K8s 之上建立「领域抽象层」:把资源八件套封装为「环境」,把镜像 + 副本数 + 资源规格封装为「部署」,把 CRD 组合封装为「数据库申请」。Humanitec 的 Score 规范与 KubeVela 的 OAM 模型都是这一层的标准化尝试:开发者用一份与平台无关的工作负载规范描述应用,平台负责翻译为具体的 K8s(或云)资源。判断抽象层设计好坏的标准是「泄漏程度」:当 K8s 的细节(如 Pod 驱逐、镜像拉取策略)频繁穿透到开发者界面并迫使其学习时,说明抽象层太薄;当开发者合理的定制需求无法满足时,说明抽象层太厚或缺少逃生舱口。
【自建 vs 采购 vs 开源组合的决策框架】这是每个组织启动 IDP 建设时的第一个重大决策,可以用四维度框架分析。维度一:组织规模与工程能力——少于 50 名工程师的组织通常不值得自建 IDP(平台团队的固定成本无法摊薄),应优先使用云厂商托管服务 + 少量脚本;50-500 人规模适合「开源组合 + 轻度定制」(如 Backstage + Crossplane + ArgoCD);500 人以上且有强平台工程能力的组织可以考虑深度自建能力层。维度二:差异化需求——如果你的行业有独特合规要求(金融的审计追踪、医疗的数据隔离)或独特技术栈(嵌入式、ML 工作流),商业产品可能无法覆盖,需要自建或深度定制;如果需求是通用的(Web 服务 + 数据库 + 缓存),商业产品或开源组合足够。维度三:TCO 的诚实核算——自建的隐性成本包括:初始开发(6-18 个月)、持续维护(框架升级、安全补丁、插件兼容)、文档与支持、以及人员流动带来的知识流失;商业产品的隐性成本包括:订阅费(通常按开发者人数计费)、供应商锁定、数据出域合规、定制能力上限。经验数据:维护一个中等定制程度的 Backstage 部署需要 2-4 名全职工程师。维度四:演进速度——平台需求变化快的组织(业务快速扩张期)适合开源方案(改代码的自由度),需求稳定的组织适合商业方案。一个实用的混合策略:目录与门户用 Backstage 或商业产品,基础设施编排用 Crossplane/Terraform,部署用 ArgoCD,把自建精力集中在「能力层的编排逻辑」——那里才是组织特有知识的沉淀处。
【案例深析:Spotify Backstage 的诞生与开源】Backstage 的演进史是 IDP 建设的教科书案例,其时间线揭示了平台成长的普遍规律。2016 年,Spotify 的工程效率痛点集中在「服务元数据混乱」:数百个服务的所有权、依赖、文档散落各处,新人上手与故障排查成本高昂。第一版 Backstage 的核心决策是「以目录为中心」而非「以流水线为中心」或「以部署为中心」——先解决「我们知道我们有什么」的问题,再在目录之上逐步叠加能力。这个顺序至关重要:目录是所有自动化的「实体注册表」,没有目录,脚手架不知道往哪登记新服务,可观测性不知道服务归属,成本分摊无从谈起。2017-2019 年,Backstage 通过插件机制扩展能力:每个插件是一个独立的前端模块 + 可选后端,团队可以为自己使用的工具(Spotify 内部有数十种 CI 系统)编写插件并挂载到目录实体页面。插件架构是 Backstage 生态成功的关键——它把「集成一切」的不可能任务分布式化了。2020 年开源时,Spotify 做出重要治理决策:捐赠给 CNCF 而非独立基金会,采用 Apache 2.0 协议,保持开放的指导委员会。开源后的挑战是「从单一公司工具到通用框架」的转型:Spotify 内部的许多假设(如特定的认证体系、内部工具)需要抽象为可配置项,这催生了 Backstage 的「软件模板」与「认证提供者」等扩展点设计。对平台建设者的启示:(1)从数据模型(目录)开始,而非从 UI 开始;(2)插件化/可扩展架构决定生态生命力;(3)平台的通用化重构最好在开源/推广前完成,否则技术债会指数级累积。
【IDP 的反模式清单】失败的 IDP 项目呈现出高度一致的反模式,提前识别能避免大量浪费。反模式一:「空壳门户」——先建漂亮的 UI 门户,背后没有自动化能力,开发者点开「创建环境」按钮发现还是跳转到工单系统;门户的价值密度取决于其背后的自动化深度,UI 应该是最后建的部分而非最先。反模式二:「工具堆砌」——把 Jenkins、Grafana、Rancher 等十几个工具的链接汇总到一个页面就宣称有了 IDP;没有编排与统一数据模型的链接聚合只是「书签页」。反模式三:「强制迁移大爆炸」——要求所有团队在某个日期前全部迁移到新平台,引发强烈抵触与影子平台;正确做法是吸引式采纳(新服务默认走平台,存量服务自愿迁移)。反模式四:「平台团队的自嗨架构」——追求技术先进性(全内部自研、最新框架)而非用户价值,抽象设计基于平台团队的想象而非用户研究。反模式五:「无退役计划」——平台组件只增不减,废弃的能力无人下线,维护成本吞噬团队精力;每个平台能力都应有生命周期管理(实验→稳定→废弃→下线)。反模式六:「忽视平台自身的可运维性」——IDP 本身是生产系统,需要 SLO、监控、灾备与变更管理;IDP 宕机时全公司的部署能力瘫痪,其可用性要求实际上高于大多数业务服务。反模式七:「一次性项目心态」——把 IDP 当作有明确终点的项目而非持续演进的产品,项目验收后团队解散,平台迅速腐烂。
【IDP 的数据模型设计:实体、关系与所有权】IDP 架构中最值得前期投入的设计是其实体关系模型。以 Backstage 的目录模型为参考,一个良好的 IDP 数据模型应包含以下实体类型:Component(服务/应用,区分 service、website、library 等子类型)、API(组件对外暴露的接口,含 OpenAPI/AsyncAPI 定义)、Resource(数据库、队列、存储等有状态资源)、System(一组相关组件与资源的业务系统边界)、Domain(更高层的业务领域,对应业务限界上下文)、Group 与 User(团队与个人,通常从企业目录如 LDAP/Okta 同步)、Location(实体的元数据来源位置)。实体间的关系同样重要:owns(所有权,回答「谁负责」)、dependsOn/providesApis(依赖与供给,构成依赖图谱)、partOf(组件属于系统、系统属于领域的层级)、consumesApis(谁在用这个 API,变更影响面分析的基础)。所有权模型需要特别设计:每个实体必须有且仅有一个 owner(团队而非个人,避免人员流动导致孤儿服务);所有权变更应有流程与审计。这个数据模型的价值随时间复利增长:第一年它回答「我们有什么、谁负责」;第二年它支撑依赖分析与影响面评估;第三年它成为成本分摊、安全响应(漏洞影响哪些服务)、合规审计(PCI 范围内有哪些组件)的统一数据源。反之,数据模型设计草率的 IDP 会在能力叠加时不断遭遇「实体对不上」的集成噩梦。
【IDP 的采纳策略与演进路线】IDP 建成只是开始,采纳(adoption)才是价值实现的关口。成熟的采纳策略包含以下要素。第一,「新服务默认路径」:与工程领导层达成共识,所有新创建的服务默认通过 IDP 脚手架创建——新服务没有迁移成本,是最容易的采纳切入点,且随着时间推移自然提高覆盖率。第二,「灯塔团队」策略:选择 2-3 个痛点强烈、态度积极的团队作为首批深度用户,平台团队与其结对工作,快速迭代满足其需求;灯塔团队的成功故事(「X 团队用平台把上线时间从 3 周缩短到 2 天」)是最有说服力的内部营销素材。第三,「拉力而非推力」:绝不通过行政命令强制存量服务迁移;相反,让平台能力产生自然拉力——例如安全团队宣布「只有通过 IDP 部署的服务才能获得自动化的漏洞响应」,迁移就变成了团队自利的选择。第四,「白手套服务」(white-glove onboarding):对首批迁移的团队提供手把手支持,平台团队成员亲自帮助完成迁移,把摩擦降到最低并收集第一手反馈。第五,分阶段演进路线:阶段 0(1-2 个月)部署目录并导入现有服务元数据;阶段 1(3-6 个月)上线脚手架与标准 CI,覆盖「新服务创建」旅程;阶段 2(6-12 个月)自助环境与部署自动化;阶段 3(12 个月+)可观测性、安全、成本能力的深度集成与存量服务规模化迁移。每个阶段都有明确的采纳指标(目录覆盖率、脚手架使用率、自助部署占比),未达标不进入下一阶段——这迫使平台团队持续验证价值而非盲目扩张功能。
代码示例
/* 示例 1:Backstage 软件模板——「创建 Node.js 服务」的脚手架定义 */
/* 开发者在门户中填写表单,模板自动完成仓库创建、CI 注入、目录登记 */
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: nodejs-service-golden-path
title: 创建 Node.js 服务(黄金路径)
description: 按照公司标准创建一个生产就绪的 Node.js 服务
spec:
owner: group:platform-team
type: service
parameters:
- title: 服务信息
required:
- name
- owner
properties:
name:
title: 服务名
type: string
pattern: "^[a-z0-9-]+$"
description: 小写字母、数字与连字符
description:
title: 服务描述
type: string
owner:
title: owning 团队
type: string
ui:field: OwnerPicker
ui:options:
catalogFilter:
kind: Group
- title: 部署配置
properties:
tier:
title: 服务等级
type: string
enum: [critical, standard, experimental]
default: standard
description: critical 等级自动启用多可用区与更严格的 SLO
steps:
- id: fetch-template
name: 拉取服务骨架
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
description: ${{ parameters.description }}
tier: ${{ parameters.tier }}
- id: publish
name: 创建 GitHub 仓库
action: publish:github
input:
allowedOrganizations: ["acme"]
repoUrl: github.com?owner=acme&repo=${{ parameters.name }}
defaultBranch: main
- id: register
name: 登记到软件目录
action: catalog:register
input:
repoUrl: ${{ steps.publish.output.remoteUrl }}
catalogInfoUrl: ${{ steps.publish.output.remoteUrl }}/blob/main/catalog-info.yaml
output:
links:
- title: 代码仓库
url: ${{ steps.publish.output.remoteUrl }}
- title: 目录条目
icon: catalog
entityRef: ${{ steps.register.output.entityRef }}解释:这份 Backstage Template 是 IDP「脚手架能力」的完整实现,展示了门户层与能力层如何协作。parameters 部分定义了开发者需要填写的表单:服务名(带正则校验,从源头杜绝命名混乱)、owning 团队(OwnerPicker 组件从目录的 Group 实体中选择,保证所有权数据准确)、服务等级(tier 参数是「渐进式披露」的范例——大多数开发者用默认值 standard,只有真正关键的服务才选 critical,而 tier 会在骨架代码中驱动不同的副本数、SLO 与告警配置)。steps 部分是编排逻辑的核心:fetch:template 从骨架目录生成代码(骨架中包含 Dockerfile、CI 配置、K8s 清单、监控注册、README 与 catalog-info.yaml——即黄金路径的全部默认实践);publish:github 创建仓库并推送;catalog:register 把新服务登记进目录,使其立即可被发现、被关联监控、被纳入治理。整个流程把传统上需要数天(复制旧仓库、手工改配置、找运维建 CI、登记 Wiki)的工作压缩为一次 2 分钟的表单提交,且产出 100% 符合规范。注意 output.links 的设计:完成后直接给出仓库与目录条目的链接,形成闭环体验。平台团队维护这份模板即维护了「创建服务的正确方式」——模板更新(如新增默认的 SBOM 生成步骤)后,所有新服务自动继承,这就是「黄金路径版本化演进」的机制基础。/* 示例 2:Crossplane Composition——把「生产级 PostgreSQL」定义为一个复合资源 */
/* 平台团队编写一次,开发者 thereafter 只需提交一个 XPostgreSQL 申请 */
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: xpostgresql-production-aws
labels:
platform.acme.com/tier: production
spec:
compositeTypeRef:
apiVersion: platform.acme.com/v1alpha1
kind: XPostgreSQL
resources:
- name: rds-instance
base:
apiVersion: rds.aws.crossplane.io/v1alpha1
kind: DBInstance
spec:
forProvider:
dbInstanceClass: db.r6g.large
engine: postgres
engineVersion: "15.4"
multiAZ: true
storageEncrypted: true
backupRetentionPeriod: 30
publiclyAccessible: false
patches:
- fromFieldPath: spec.parameters.size
toFieldPath: spec.forProvider.dbInstanceClass
transforms:
- type: map
map:
small: db.r6g.large
medium: db.r6g.xlarge
large: db.r6g.2xlarge
- name: subnet-group
base:
apiVersion: rds.aws.crossplane.io/v1alpha1
kind: DBSubnetGroup
spec:
forProvider:
description: 平台管理的私有子网组
subnetIdRefs:
- name: platform-private-subnet-a
- name: platform-private-subnet-b
- name: monitoring-secret
base:
apiVersion: kubernetes.crossplane.io/v1alpha1
kind: Object
metadata:
name: postgres-exporter-config
spec:
forProvider:
manifest:
apiVersion: v1
kind: ConfigMap
metadata:
namespace: observability
data:
scrape-target: 由平台自动注入
---
/* 开发者侧的申请只需 12 行 */
apiVersion: platform.acme.com/v1alpha1
kind: XPostgreSQL
metadata:
name: orders-db
namespace: team-orders
spec:
parameters:
size: medium
version: "15"解释:这个示例展示了 IDP 基础设施层最关键的设计模式——「复合资源」(Composite Resource)。传统方式下,业务团队申请一个生产数据库需要:理解 RDS 的几十个参数、知道公司要求多可用区与加密、手工配置子网组与备份策略、再自己搭建 postgres-exporter 监控——每一步都是认知负担与出错机会。Crossplane 的 Composition 机制让平台团队把这些知识「编译」进平台:一个 Composition 声明了「当有人申请 XPostgreSQL 且标签为 production 时,创建 RDS 实例(强制 multiAZ、加密、30 天备份、私有子网)+ 子网组 + 监控配置」这一完整组合。开发者侧的接口被压缩为 12 行 YAML,唯一需要决策的是 size(三档枚举)与 version——这正是「恰到好处的抽象」:暴露必要的选择,隐藏危险的细节(publiclyAccessible: false 与 storageEncrypted: true 开发者根本无法覆盖)。patches 中的 map transform 展示了参数翻译机制:开发者说 small/medium/large(业务语言),平台翻译为具体的实例规格(基础设施语言),未来更换实例族只需改 Composition 一处。更深层的价值是「策略的不可绕过性」:因为开发者操作的是 XPostgreSQL 这个 CRD 而非 RDS 原语(RBAC 禁止业务命名空间创建 aws.crossplane.io 资源),安全基线在 API 层面就被强制执行了。这个模式可以推广到一切基础设施:XRedis、XKafkaTopic、XS3Bucket——每个复合资源都是平台团队沉淀的一份「基础设施最佳实践」。/* 示例 3:IDP 能力层的自助环境创建工作流(Tekton Pipeline 表达) */
/* 「创建预览环境」被编排为一个原子化平台动作:建 namespace、配配额、部署、注册目录 */
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: create-preview-environment
namespace: platform-workflows
spec:
params:
- name: service-name
type: string
- name: team
type: string
- name: pr-number
type: string
tasks:
- name: validate-quota
taskRef:
name: opa-policy-check
params:
- name: policy
value: env-quota.rego
- name: input
value: '{"team":"$(params.team)","env":"preview"}'
- name: provision-namespace
runAfter: ["validate-quota"]
taskRef:
name: kubernetes-actions
params:
- name: script
value: |
kubectl create namespace preview-$(params.service-name)-$(params.pr-number)
kubectl apply -f - <<EOF
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-quota
namespace: preview-$(params.service-name)-$(params.pr-number)
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "20"
EOF
- name: deploy-service
runAfter: ["provision-namespace"]
taskRef:
name: helm-upgrade
params:
- name: chart
value: acme-service-chart
- name: values
value: |
image.tag: pr-$(params.pr-number)
ingress.host: $(params.service-name)-$(params.pr-number).preview.acme.io
- name: register-in-catalog
runAfter: ["deploy-service"]
taskRef:
name: http-request
params:
- name: url
value: http://backstage-catalog.platform.svc/v1/entities
- name: method
value: POST
- name: notify
runAfter: ["register-in-catalog"]
taskRef:
name: slack-message
params:
- name: text
value: "预览环境已就绪: https://$(params.service-name)-$(params.pr-number).preview.acme.io"解释:这份 Tekton Pipeline 是 IDP 能力层「工作流编排」的具象化,它把「创建预览环境」这个开发者任务分解为五个自动化步骤并处理了它们之间的依赖与策略。逐步分析:validate-quota 首先执行 OPA 策略检查——该团队本月已创建多少预览环境?是否超过配额?策略前置意味着「审批」被自动化:符合策略立即通过,不符合立即拒绝并给出原因,无需人工介入。provision-namespace 创建独立的 K8s namespace 并施加 ResourceQuota(4 CPU/8Gi 请求上限、最多 20 个 Pod)——这是多租户隔离与成本控制的关键:预览环境是「用完即弃」的,配额防止某个 PR 的环境吞噬集群资源。deploy-service 用统一的 Helm chart 部署服务,镜像标签与 Ingress 主机名由 PR 号参数化生成,保证每个 PR 有独立的访问地址。register-in-catalog 把新环境登记到 Backstage 目录(作为 location 实体或环境的 annotation),使其在门户中可发现、可关联。notify 通过 Slack 把环境 URL 推送给开发者——体验闭环的最后一步。整个流水线由 PR 创建事件自动触发(配合 GitHub webhook),开发者提交 PR 后约 5 分钟收到可点击的预览环境链接,而在此之前这个流程需要找运维手工搭建。设计要点:每个 task 都是幂等的(重试安全);runAfter 显式声明依赖形成 DAG;策略检查放在最前(fail fast);所有参数来自触发事件而非人工输入。这个模式可以复制到 IDP 的每个自助动作:创建生产环境、申请数据库、轮换密钥——「任务 → 策略校验 → 多系统编排 → 通知闭环」是能力层工作流的通用骨架。/* 示例 4:IDP 架构决策记录(ADR)——记录「目录选型」这一关键决策 */
/* 平台团队用 ADR 沉淀决策上下文,避免组织知识随人员流动而流失 */
# ADR-007: 软件目录选型
状态: 已接受
日期: 2024-03-15
决策者: 平台团队 + 架构评审委员会
## 上下文
IDP 第一阶段需要一个软件目录作为元数据中枢。候选方案:
A. 自建目录服务(PostgreSQL + REST API + React 前端)
B. Backstage 开源框架(含目录后端与插件生态)
C. 商业产品 Port(SaaS,按开发者席位计费)
评估维度:初始交付时间、三年 TCO、定制自由度、
数据主权、社区生态、团队技能匹配度。
## 分析摘要
方案 A:完全可控,但预估初始开发 9-12 个月,且需长期
维护 UI、认证、插件集成;目录是「无差异化重活」
(undifferentiated heavy lifting),自建不符合 TVP 原则。
方案 B:目录模型成熟(Component/API/System/Group 实体),
插件生态 2000+,社区活跃(CNCF 孵化);成本在于需要
2-3 名工程师持续维护与升级,前端定制需要 React 能力
(团队具备)。数据完全自持。
方案 C:交付最快(数周),记分卡与自动化开箱即用;
但年订阅费约 15 万美元(300 开发者),元数据出域需要
安全评审,深度定制受限于产品路线图。
## 决策
选择方案 B(Backstage),理由:
1. 目录数据模型是 IDP 长期资产,需要完全的数据主权与演进自由;
2. 组织规模(300+ 工程师)足以摊薄维护成本;
3. 插件生态覆盖我们 80% 的集成需求(GitHub、ArgoCD、
Datadog、PagerDuty 均有官方插件);
4. 团队具备 TypeScript 能力,定制成本可接受。
## 后果
正面:数据自持、无许可费、可按需定制。
负面:需要承诺 2-3 FTE 的长期维护;升级 Backstage
主版本每季度约需 1-2 周工作量。
缓解:指定专人负责版本升级;建立插件兼容性测试套件。
## 复审触发条件
若维护成本连续两个季度超过 3 FTE,或商业产品出现
本地化部署选项,重启评估。解释:架构决策记录(ADR)是平台团队工程文化的重要组成部分,这个示例记录了 IDP 建设中最关键的决策之一——目录选型。为什么目录选型值得如此郑重?因为如前所述,目录是 IDP 的「数据中枢」,所有后续能力都锚定在目录实体上,更换目录系统意味着重写全部集成——这是一个「单向门」决策(one-way door),应当用最高标准审慎做出。这份 ADR 展示了良好决策记录的要素:上下文明确列出候选方案与评估维度(避免「我们为什么当初选了 X」的考古式追问);分析摘要诚实呈现每个方案的代价(自建的时间成本、商业产品的费用与数据主权问题);决策理由与组织上下文绑定(300+ 工程师的规模、团队的 TypeScript 能力——同样的决策在不同组织可能完全不同);后果部分不回避负面代价(2-3 FTE 的持续维护承诺)并给出缓解措施;复审触发条件把决策从「永久绑定」变为「有条件承诺」,这是成熟工程组织的标志。特别值得注意的是分析中引用的「无差异化重活」概念(来自 Amazon 的文化语言):目录、门户 UI、认证集成这些能力在所有组织中都大同小异,自建它们消耗的工程资源本可以投入到真正差异化的能力层编排上——这个原则可以推广到 IDP 的所有选型决策:差异化能力自建,通用能力采用开源或商业方案。/* 示例 5:IDP 统一 API 网关的路由配置——门户层背后的能力聚合 */
/* 所有平台能力通过统一 API 暴露,UI/CLI/ChatOps 共享同一后端 */
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: platform-api-routes
namespace: platform
spec:
parentRefs:
- name: platform-gateway
hostnames:
- api.platform.acme.internal
rules:
- matches:
- path:
type: PathPrefix
value: /v1/catalog
backendRefs:
- name: backstage-backend
port: 7007
- matches:
- path:
type: PathPrefix
value: /v1/environments
backendRefs:
- name: env-orchestrator
port: 8080
- matches:
- path:
type: PathPrefix
value: /v1/deployments
backendRefs:
- name: deployment-service
port: 8080
- matches:
- path:
type: PathPrefix
value: /v1/workflows
backendRefs:
- name: workflow-engine
port: 8080
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Platform-Audit
value: "enabled"
---
/* 能力层服务的统一接口契约(OpenAPI 片段) */
openapi: 3.0.3
info:
title: Platform Environments API
version: 1.0.0
paths:
/v1/environments:
post:
summary: 自助创建环境
operationId: createEnvironment
requestBody:
content:
application/json:
schema:
type: object
required: [serviceRef, type]
properties:
serviceRef:
type: string
example: component:default/payments-api
type:
type: string
enum: [preview, staging, production]
ttl:
type: string
example: 72h
description: 预览环境的自动回收时限
responses:
"202":
description: 创建已受理(异步工作流)
content:
application/json:
schema:
type: object
properties:
workflowId:
type: string
statusUrl:
type: string解释:这个示例展示 IDP 门户层与能力层之间的「API-first」架构。HTTPRoute(K8s Gateway API 资源)把统一的平台 API 域名路由到不同的能力服务:/v1/catalog 到 Backstage 后端,/v1/environments 到自研的环境编排器,/v1/workflows 到工作流引擎。统一入口的价值在于:Web 门户、CLI、Slack 机器人、IDE 插件全部消费同一套 API,保证行为一致(不会出现「UI 能创建环境但 CLI 不能」的割裂);认证、限流、审计在网关层统一实施(注意 X-Platform-Audit 头的注入);底层服务可以独立演进甚至替换,只要 API 契约稳定。OpenAPI 片段定义了「创建环境」的接口契约,几个设计细节体现平台产品思维:serviceRef 使用 Backstage 实体引用格式(component:default/payments-api),把环境 API 与目录数据模型显式关联;type 枚举区分环境等级,不同等级触发不同的策略校验与资源规格;ttl 字段内置了「预览环境 72 小时自动回收」的成本治理机制——平台把最佳实践(临时环境必须有时限)设计进 API 而非依赖纪律;响应码 202(Accepted)+ workflowId 表明这是异步长任务,客户端通过 statusUrl 轮询或订阅事件获取进度,这是能力层工作流引擎的标准交互模式。契约先行(contract-first)的开发方式还带来额外收益:API 规范可以生成客户端 SDK、Mock 服务器与文档站点,门户团队与能力团队可以并行开发。实验笔记
【实验目标】本实验通过动手部署一个真实的 Backstage 实例并完成「目录 + 模板」的最小闭环,让学习者建立对 IDP 架构的直观理解。完成后你将拥有:(1)一个运行中的 Backstage 门户,包含至少 5 个目录实体(组件、API、系统、组、资源)及其关系;(2)一个可用的软件模板,能够通过表单创建新服务骨架;(3)一份手绘的 IDP 三层架构图,标注你环境中每个组件所属的层次。预计耗时 4-5 小时。
【环境准备】需要:Docker Desktop 或等价的容器运行时(至少 4GB 可用内存);Node.js 20+ 与 yarn;Git;一个 GitHub 组织或 Gitea 实例(模板的 publish 步骤需要,若无可用 GitHub 个人账号 + fine-grained token,或改用本地文件输出跳过发布步骤)。拉取官方演示镜像快速启动:docker run -it --rm -p 7007:7007 -p 7008:7008 spotify/backstage-demo 可在数分钟内获得一个预置数据的 Backstage(注意该镜像仅供体验,数据不持久)。若要深入定制,使用 npx @backstage/create-app 创建自己的实例(首次构建约 15-25 分钟)。
【步骤一:部署与初始探索(60 分钟)】启动 Backstage 后访问 http://localhost:7007。依次探索:软件目录(Catalog)页面的实体列表与过滤器;点开任一 Component 实体,观察其 Overview(所有权、生命周期、标签)、Dependencies(依赖图谱)、Docs、CI/CD 等标签页;进入 Settings 查看已安装插件。记录你的观察:目录展示了哪些实体类型?实体页面聚合了哪些信息源?思考:如果你的组织采用此目录,第一天需要导入哪些数据?
【步骤二:构建组织的数据模型(90 分钟)】设计一个虚构公司「Acme Shop」的目录数据:2 个 Domain(电商交易、用户增长)、2 个 System(checkout-system、user-profile-system)、4 个 Component(payments-api、cart-service、profile-service、web-storefront)、2 个 API(payments-api-v1、profile-graphql)、2 个 Resource(payments-postgres、profile-redis)、3 个 Group(payments-team、growth-team、platform-team)。为每个实体编写 catalog-info.yaml(参考本章代码示例 1 的结构),正确设置 owner、system、dependsOn、providesApis、partOf 关系。通过 Backstage 的 app-config.yaml 配置 catalog.locations 指向你的 YAML 文件目录(file:// 目标即可),重启后验证实体全部出现且关系图谱正确。重点检查:从 payments-api 的页面能否看到它依赖 fraud-detection、被 checkout-system 包含、由 payments-team 拥有?
【步骤三:创建软件模板(90 分钟)】编写一个简化的 Template(参考代码示例 1,可去掉 publish:github 步骤改用 debug:log 输出):参数包含服务名、描述、owning 团队、服务等级;步骤包含 fetch:template 拉取一个本地骨架(骨架中放一个最小的 Node.js 或 Python 服务 + catalog-info.yaml 模板文件,使用 Cookiecutter 风格的占位符)与 catalog:register 登记。在门户的 Create 页面触发模板,填写表单,观察执行日志的每个步骤;完成后验证新实体出现在目录中。记录遇到的问题:参数校验如何生效?步骤失败时如何重试?
【步骤四:架构复盘(60 分钟)】手绘你的 Backstage 环境的三层架构图:门户层(React UI、哪些插件)、能力层(scaffolder 后端、catalog 后端、你配置的模板与位置源)、基础设施层(本地文件系统/GitHub、数据库)。在图上标注:如果要把「创建环境」能力加入这个 IDP,需要新增哪些组件?如果底层从 GitHub 换成 GitLab,哪些层需要修改?这两个思想实验检验你对分层解耦的理解。
【检查清单】(1)Backstage 实例可访问且目录包含全部 13 个设计的实体;(2)实体间关系(owns/partOf/dependsOn/providesApis)在 UI 中正确渲染;(3)软件模板可通过表单成功执行并登记新实体;(4)三层架构图完成且标注了两个思想实验的答案;(5)记录了一份「问题与解决」笔记(至少 3 个遇到的具体问题)。
【进阶挑战】(1)为 Backstage 安装一个社区插件(如 backstage-community/kubernetes 插件连接一个 kind 集群,或 TechDocs 插件启用文档渲染),体验插件生态;(2)把步骤三的模板扩展为多步骤工作流:创建骨架后自动生成 GitHub Actions CI 文件并输出「下一步指引」链接;(3)部署一个最小 Crossplane(kind 集群 + crossplane helm chart),定义一个 XPostgreSQL 复合资源并在本地 provider(如 provider-kubernetes 模拟)上验证 Composition 机制;(4)撰写一份 2 页的「Acme Shop IDP 一期建设方案」:基于本实验的动手经验,列出能力清单、组件选型、团队配置与 90 天里程碑。
延伸阅读
- internaldeveloperplatform.org:IDP 概念的社区权威站点,包含 IDP 定义、设计原则、参考架构与案例集合。其「What is an Internal Developer Platform」一文是理解「IDP 是能力集合而非单一工具」的最佳短文;站点还维护了 IDP 生态的工具图谱,适合选型调研时快速扫描市场。
- Backstage 官方文档(backstage.io/docs):重点阅读 Software Catalog 的数据模型章节(实体类型、关系、well-known annotations)与 Software Templates 的编写指南(参数、步骤、动作系统)。文档中的「Creating your Backstage App」教程是本章实验的官方版本,架构章节解释了前后端分离与插件系统的设计。
- CNCF《Platforms White Paper》与《IDP Patterns》:白皮书给出平台的正式定义、价值主张与组织建议;IDP Patterns 文档归纳了常见的设计模式(如「薄平台」「编排层模式」)。两份文档合计约 60 页,是社区共识的浓缩表达,适合平台团队集体研读并对照自评。
- Crossplane 官方文档(docs.crossplane.io):重点阅读 Concepts 中的 Compositions 与 Composite Resource Definitions(XRD)章节,理解「平台团队定义组合、开发者申请复合资源」的分工模型;Quickstart 提供了 AWS/GCP/Azure 的完整动手路径。Crossplane 是理解「K8s API 作为基础设施控制平面」的关键项目。
- KubeVela 与 OAM 规范(kubevela.io、github.com/oam-dev/spec):OAM(Open Application Model)由微软与阿里联合提出,其「组件 + 运维特征 + 工作流」的应用抽象是「以应用为中心」交付模式的代表设计。阅读 OAM 规范论文可理解应用抽象层与基础设施层解耦的理论基础。
- Spotify 工程博客 Backstage 系列文章:《What the Heck is Backstage Anyway?》《How We Use Backstage at Spotify》等文章记录了 Backstage 从内部工具到开源项目的一手历程,包含大量设计决策的背景与教训,是本章 Spotify 案例的原始出处。
- 《Platform Engineering: A Guide for Tech Leaders》第 3-5 章(O'Reilly 2024):详细展开 IDP 的架构分层、能力域划分与选型决策,包含作者咨询过的多家企业的真实架构图与踩坑记录,与本章内容形成「概览 + 深潜」的互补关系。