讲讲Crossplane
Crossplane 的核心思路是把 Kubernetes 的声明式 API 机制搬到”管理云资源”这件事上——你不再直接调用 AWS/GCP 的 SDK 或写 Terraform,而是像创建 Kubernetes 对象一样,”创建”一个描述你想要什么资源的 YAML,Crossplane 负责协调(reconcile)出实际的云资源并保持状态一致。围绕这个思路,有几个层层递进的核心概念。
最底层是 Provider。Provider 是 Crossplane 的插件,负责对接具体的云厂商或系统(比如 AWS、GCP、Azure、GitHub、Kubernetes 本身等),它把该厂商的资源类型转换成一批 Kubernetes CRD,比如 AWS Provider 会带来 RDSInstance、S3Bucket 这样的自定义资源类型。Provider 本身也运行一个控制器,专门负责把这些资源对象的期望状态同步到真实云端。
在 Provider 提供的 CRD 之上,实际创建出来的对象叫 Managed Resource(MR),比如你创建一个 RDSInstance 对象,Provider 的控制器就会去 AWS 上创建一个真实的 RDS 实例,并持续对齐两边的状态。MR 是 Crossplane 里最贴近底层云资源的一层,颗粒度通常和云厂商 API 一一对应,直接拿给业务团队用会显得太底层、太厂商相关。
于是 Crossplane 提供了一层抽象,让平台团队可以把多个 MR 组合成一个更高层、面向业务的自定义 API,这就是 **XRD(CompositeResourceDefinition)**加 Composition 的组合。XRD 定义的是”这个自定义 API 长什么样”——它规定了这个新 API 的名字、可以传哪些参数、参数类型和校验规则(基于 OpenAPI v3),本质上是个模式(schema)。你把 XRD 应用到集群后,Crossplane 会自动帮你生成一个对应的 Kubernetes CRD。
XRD 定义了”有什么”,而 Composition 定义的是”怎么实现”:它描述当有人根据这个 XRD 创建了一个实例时,具体应该组合创建出哪些底层 MR(甚至在 v2 里还可以是任意 Kubernetes 资源),以及参数如何在这些资源之间传递映射。一个 XRD 可以对应多个 Composition,这样平台团队就能针对不同环境或云厂商提供不同的实现,比如”生产环境用高可用配置的 Composition,测试环境用便宜的单实例 Composition”,而使用者感知不到这些差异。现在写 Composition 逻辑主流做法是用 Composition Functions(一段可以用 Go、Python 等语言写的小程序,作为 Pipeline 的一步执行,接收请求、返回要创建的资源),取代了早期纯 YAML patch-and-transform 的写法,灵活性高很多,之前提到的 function-pkl 就是这样一个 Function。
按照 XRD 的 schema、依据某个 Composition 实际创建出来的对象,叫 Composite Resource(XR)——它是用户(通常是应用开发者)真正拿来使用的高层资源实例。在 Crossplane v1 里,XR 是集群作用域的,所以平台团队通常还会额外用一层 Claim 机制,让业务团队在自己的命名空间里创建一个”申领”对象,由 Claim 去关联/创建实际的 XR,从而做到命名空间级别的隔离和权限控制。
到了 Crossplane v2(也是你之前问的那些集成项目所处的版本),架构做了几处简化:XR 本身可以直接设置成命名空间作用域(scope: Namespaced),这样业务团队可以直接在自己命名空间里创建 XR,不再需要 Claim 这层额外抽象;同时 Managed Resource 也可以命名空间化,方便做更细粒度的权限管控;更重要的是,Composition 不再局限于只能组合 Crossplane 自己的 MR,而是可以组合任意 Kubernetes 资源(比如原生的 Deployment、Service,或者其他 Operator 管理的自定义资源),这让 Crossplane 从”云资源编排工具”进一步变成了通用的”Kubernetes 资源编排/平台工程框架”。v2 还新增了 Operation、CronOperation、WatchOperation 这类”运维工作流”资源,用来处理证书轮换、定期巡检这种不属于”创建资源”范畴的运维任务。
总结一下这条链路:Provider 把云厂商能力接入集群 → 产出 Managed Resource 这种底层资源类型 → 平台团队用 XRD 定义一个更友好的高层 API schema → 用 Composition(配合 Composition Function)描述这个高层 API 该如何组合出底层资源 → 业务团队创建 Composite Resource(v1 里可能通过 Claim)来实际使用这个高层 API,最终由 Crossplane 的控制器持续协调,保证声明的状态和云上真实状态一致。
如果你想深入某一块,比如 Composition Function 具体怎么写、或者 v1 到 v2 迁移时 Claim 怎么处理,可以告诉我,我再展开。
简单地说Crossplane相当于把各个云平台的产品能力更抽象了一层?
可以这么理解,但更准确地说,Crossplane 做的是两层抽象,而且价值主要在于把这两层抽象都”Kubernetes 化”了。
第一层抽象是把不同云厂商的产品能力都统一成 Kubernetes 风格的声明式 API——不管是 AWS 的 RDS、GCP 的 Cloud SQL 还是 Azure 的数据库服务,到了 Crossplane 里都变成”创建一个 YAML 对象,控制器帮你协调出真实资源”这一套统一的操作方式和心智模型。这一层的价值主要是”统一交互方式”,让你用管理 Kubernetes 的那套工具链(kubectl、GitOps、RBAC)去管理云资源,但这时候资源粒度还是和厂商 API 差不多细,一个 MR 基本对应一个云产品。
第二层抽象才是你说的”更抽象”——通过 XRD/Composition,平台团队可以把多个底层云资源打包成一个业务视角的高层 API,比如把”VPC + RDS + 安全组 + IAM 角色”这一堆东西封装成一个叫 XPostgresDatabase 的自定义资源,应用开发者只需要传几个参数(比如”要多大”、”哪个环境”),不需要知道底下具体用了哪家云、哪些具体产品。这一层的价值是”隐藏实现细节、统一多云差异”,跟 Terraform module 或者云厂商的托管服务编排有点像,但因为是原生 Kubernetes CRD,天然能接入 K8s 生态的权限控制、GitOps 工作流、可观测性工具等。
所以简单说是对的:本质上 Crossplane 是把各家云平台的能力抽象成了一层统一的、可以进一步再抽象/组合的声明式 API,而且这个抽象是”活的”(有控制器持续协调状态),不是像 Terraform 那样一次性 apply 完就结束,这也是它和传统 IaC 工具的一个关键区别。
给一个具体的简单一点的crossplane例子
Searched the web
好,给你一个从简单到完整的例子,正好把之前聊的 Provider / MR / XRD / Composition / XR 串起来。这是 Crossplane 官方文档里的真实例子(v2.3),用的是创建 AWS S3 桶。
第一步:最简单的层次——直接用一个 Provider 创建一个 Managed Resource
先装一个对接 AWS S3 的 Provider:
apiVersion: pkg.crossplane.io/v1 kind: Provider metadata: name: crossplane-contrib-provider-aws-s3 spec: package: xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0
再给它配置好 AWS 凭证(引用一个存了 AWS key 的 Kubernetes Secret):
apiVersion: aws.m.upbound.io/v1beta1
kind: ClusterProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-secret
key: creds
然后你就可以直接创建一个 Bucket 对象了:
apiVersion: s3.aws.m.upbound.io/v1beta1
kind: Bucket
metadata:
namespace: default
generateName: crossplane-bucket-
spec:
forProvider:
region: us-east-2
kubectl apply 这个 YAML 之后,Crossplane 就会在 AWS 上真的创建一个 S3 桶。这一层还比较”薄”,Bucket 这个 CRD 基本就是 AWS S3 API 的直接映射,用户还是得懂 AWS 的概念(region、bucket 之类)。
第二步:加一层抽象——用 XRD + Composition 包装成业务 API
假设平台团队不想让业务开发者直接接触 Bucket 这种云厂商细节,而是想给他们一个更简单的 App 抽象(这里官方例子换成了组合 Kubernetes 原生资源,展示 v2 的新能力,但道理和组合云资源完全一样)。先用 XRD 定义这个新 API 长什么样:
apiVersion: apiextensions.crossplane.io/v2
kind: CompositeResourceDefinition
metadata:
name: apps.example.crossplane.io
spec:
scope: Namespaced
group: example.crossplane.io
names:
kind: App
plural: apps
versions:
- name: v1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
image:
description: The app's OCI container image.
type: string
required:
- image
这个 XRD 说:”我要提供一个叫 App 的新 API,用户只需要填一个 image 字段。” 应用之后 Crossplane 会自动帮你生成对应的 CRD。
接着用 Composition 定义”创建一个 App 的时候,底层实际要造出什么东西”:
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: app-yaml
spec:
compositeTypeRef:
apiVersion: example.crossplane.io/v1
kind: App
mode: Pipeline
pipeline:
- step: create-deployment-and-service
functionRef:
name: crossplane-contrib-function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: deployment
base:
apiVersion: apps/v1
kind: Deployment
spec:
replicas: 2
template:
spec:
containers:
- name: app
ports:
- containerPort: 80
这段的意思是:每当有人创建一个 App,就用 function-patch-and-transform 这个 Composition Function,帮它生成一个 Deployment(这里省略了把 spec.image 映射进容器镜像字段的 patch 逻辑,实际项目里会用 patches 把用户传入的参数映射到底层资源上)。
最后,业务开发者要用的时候,完全不用管 AWS 或者 Deployment 长什么样,只需要写:
apiVersion: example.crossplane.io/v1 kind: App metadata: namespace: default name: my-app spec: image: nginx
一个 kubectl apply,Crossplane 就会按照 Composition 里的逻辑,自动帮他把底层的 Deployment(乃至 Service、数据库、S3 桶等,取决于 Composition 怎么写)都创建出来。对开发者来说,他看到的只是一个简单的 App 对象;对平台团队来说,他们可以随时调整 Composition 里的实现细节(比如把 Deployment 换成更复杂的配置,或者接入云资源),而不用改动业务方的接口。
这就是前面说的”两层抽象”在具体 YAML 上的样子:第一段是”统一交互方式”那层(Provider/MR),第二段是”隐藏实现细节”那层(XRD/Composition/XR)。
Sources:
