背景与问题界定

某多云团队的"基础设施仓库"维护着 20 多个 Terraform 模块,覆盖 AWS、阿里云和自建 OpenStack 三个环境。随着服务数量增长到 200+个,Terraform 的状态管理(State)变得极其脆弱——一次错误的 terraform apply 导致跨环境的 S3 Bucket 被意外删除,依赖它的 Redis 集群配置丢失,恢复花了两天时间。更痛苦的是 Terraform 与 Kubernetes 之间的"地幔鸿沟":Terraform 创建 VPC 和 EKS 集群,Kubernetes 上部署应用,但两个世界之间的状态无法互通——Kubernetes 不知道它用了哪些 AWS 资源,Terraform 也感知不到集群内的变化。Crossplane 从 2023 年开始提出了一种新的范式:用 Kubernetes 的 CRD 和控制器模式来管理"任何云资源",让基础设施声明式地成为集群的一部分。

目标拆解与工程约束

  1. 状态管理的可靠性:基础设施的状态必须从"单点文件锁"(Terraform State + DynamoDB Lock)演进为"面向控制器的最终一致性"——不需要 state lockterraform refresh 等手工操作,状态通过 CRD 的 status 自动持久化到 etcd。
  2. 平台一致性 API:开发团队不关心底层是 AWS 还是阿里云,他们只需要声明"我需要一个 16C32G 的 PostgreSQL 实例和一个 Redis 7.0 集群",IaC 平台在背后自动映射到对应的云厂商资源。
  3. GitOps 原生集成:基础设施的变更必须通过 Git 提交触发,由 ArgoCD 或 Flux CD 自动调谐,而不是运维人员在终端执行 terraform plan && terraform apply 的手动流程。
  4. 多云统一编排:同一套 IaC 模板必须能够适应多个云厂商的差异——比如 AWS 的 RDS 和阿里云的 RDS 参数命名不同,但对外暴露的抽象语义必须一致,实现"写一次,跑遍多云"。

方案设计

架构设计采用"分层抽象"模型。底层是 Crossplane Provider(如 provider-awsprovider-helm),中间层是 Crossplane Composite Resource(XRD),最上层是开发团队直接使用的 Claim(声明式请求):

apiVersion: devops.platform.io/v1alpha1
kind: XPostgreSQLInstance
metadata:
  name: payment-db
  namespace: team-payment
spec:
  parameters:
    storageGB: 100
    instanceClass: db.r6g.large
    engineVersion: "15"
    multiAZ: true
    networkRef:
      id: production-vpc
  writeConnectionSecretToRef:
    name: db-conn

Crossplane 的 Composition 将上面的 Claim 翻译成底层的云资源:

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: postgresql-aws
spec:
  compositeTypeRef:
    apiVersion: devops.platform.io/v1alpha1
    kind: XPostgreSQLInstance
  resources:
  - name: rds-instance
    base:
      apiVersion: database.aws.crossplane.io/v1beta1
      kind: RDSInstance
      spec:
        forProvider:
          engine: postgres
          engineVersion: "15"
          dBInstanceClass: db.r6g.large
          allocatedStorage: 100
          multiAZ: true
          ...

对比 Terraform:Terraform 的模块是"声明式静态 DSL"的定义,通过 terraform apply 一次性应用;Crossplane 是"声明式持续调谐"——CR 创建后 Controller 不断将实际状态调谐到期望状态,天然支持漂移检测和自愈。例如某个运维人员通过 AWS Console 手动修改了 RDS 实例大小,Terraform 需要手动 terraform plan 发现漂移,而 Crossplane 会自动在下一调谐周期发现并恢复到 Composition 定义的状态。

对于 Terraform 已有投资的复用,Crossplane 提供了 provider-terraform,允许在 Composition 中嵌套 Terraform 模块(HCL 代码),将 Terraform State 作为 Kubernetes Secret 存储。这提供了从 Terraform 到 Crossplane 的渐进式迁移路径。

实施路径与关键决策

  • 第一步:搭建 Crossplane 控制平面,安装 Upbound Universal Crossplane(UXP),部署所需的 Provider(provider-aws、provider-helm、provider-kubernetes),配置 ProviderConfig 注入云厂商凭据。
  • 第二步:定义 XRD(Composite Resource Definition)——先从简单的"VPC + Subnet"场景开始,设计 Claim 和 Composition 的 API Schema,建立平台的资源抽象模型。
  • 第三步:迁移策略——新项目直接使用 Crossplane Claim 创建基础设施,老项目继续使用 Terraform 但逐步迁移。通过 Flux CD 的 Kustomize 控制器将 Crossplane 资源纳入 GitOps 工作流。
  • 第四步:建立资源成本标签机制——所有通过 Crossplane 创建的资源自动注入 created-by: crossplaneteam: ${namespace} 标签,配合 AWS Cost Explorer 实现成本分摊可视化。

验证指标与可持续迭代

IaC 平台效果量化指标:基础设施创建时间从"申请-审批-执行"的 2 天流程缩短到"Git commit -> ArgoCD sync"的 5 分钟;资源漂移检测收敛时间 < 1 分钟(Terraform 的 terraform plan 需要手工触发,可能间隔数天);跨云资源抽象复用率达到 80% 以上。基础设施自动化成熟度从 L2(Terraform 脚本化)提升到 L4(平台即产品的自助式供给)。

工程落地思考

Crossplane 和 Terraform 不是"二选一"的关系,而是"不同抽象层的互补"。Terraform 在"底层基础设施的初始配置"上仍然有优势——创建 Crossplane 依赖的 IAM Role、S3 Bucket 和 EKS 集群本身。一旦集群就绪,Crossplane 的持续调谐模型在"上层基础设施供给"上表现更出色。一个典型的模式是:Terraform 创建 EKS 集群 + Crossplane 的 IAM 基础角色,Crossplane 在上面管理 RDS、Redis 和 S3 Bucket 等应用依赖的云资源。基础设施即代码的本质不是"用某个工具替换写脚本",而是让基础设施的管理方式向 Kubernetes 的声明式模式靠拢——这才是跨云、跨环境的一致答案。