痛点:Terraform 好用,但和 Kubernetes 生态割裂
运维团队普遍面临一个尴尬局面:应用部署用 Kubernetes + GitOps(ArgoCD/Flux),基础设施管理用 Terraform + 独立 Pipeline。两套工具、两套工作流、两套状态管理,带来几个实际问题:
- 状态分裂 — Terraform state 在 S3/Consul 里,K8s 资源状态在 etcd 里,跨系统联动靠胶水脚本
- 权限模型不统一 — Terraform 需要云账号 AK/SK,K8s 用 RBAC,开发者自助申请资源要走两套审批
- 漂移检测各管各 — Terraform plan 检测 IaC 漂移,K8s controller 检测应用漂移,没有统一视图
- 团队协作摩擦 — 开发写 YAML 申请数据库,运维切到 Terraform 创建实例,再回填连接信息到 Secret
Crossplane 的核心思路:把云基础设施变成 Kubernetes CRD,用 K8s 原生的声明式 API + 控制器循环来管理一切。
方案:Crossplane 架构与核心概念
Crossplane 是 CNCF 毕业项目,本质是一组 Kubernetes Controller + CRD,核心组件:
| 概念 | 作用 | 类比 |
|---|---|---|
| Provider | 对接云 API(AWS/GCP/Azure) | Terraform Provider |
| Managed Resource (MR) | 单个云资源的 CRD 表示 | Terraform Resource |
| Composition | 资源编排模板,组合多个 MR | Terraform Module |
| XRD (CompositeResourceDefinition) | 自定义 API 抽象层 | 对外暴露的平台 API |
| Claim | 开发者使用的简化资源申请 | 类似 PVC 之于 PV |
整体流程:开发者提交 Claim → Crossplane 根据 Composition 展开为 MR → Provider Controller 调用云 API 创建资源 → 状态回写到 K8s Status。
实操步骤
第 1 步:安装 Crossplane 及 AWS Provider
# 安装 Crossplane(Helm)
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm install crossplane crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace \
--set args='{"--enable-usages"}'
# 等待 Pod 就绪
kubectl get pods -n crossplane-system -w
# 安装 AWS Provider(以 S3 + RDS 为例,使用 Provider Family)
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-s3
spec:
package: xpkg.upbound.io/upbound/provider-aws-s3:v1.14.0
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-rds
spec:
package: xpkg.upbound.io/upbound/provider-aws-rds:v1.14.0
EOF
# 验证 Provider 安装状态
kubectl get providers
# NAME INSTALLED HEALTHY PACKAGE AGE
# provider-aws-s3 True True xpkg.upbound.io/upbound/provider-aws-s3:v1.14.0 60s
# provider-aws-rds True True xpkg.upbound.io/upbound/provider-aws-rds:v1.14.0 60s
第 2 步:配置云凭证与 ProviderConfig
# 创建 AWS 凭证 Secret(生产建议用 IRSA / Pod Identity)
kubectl create secret generic aws-creds \
-n crossplane-system \
--from-file=creds=./aws-credentials.txt
# aws-credentials.txt 格式:
# [default]
# aws_access_key_id = AKIA...
# aws_secret_access_key = xxx
# 创建 ProviderConfig
cat <<EOF | kubectl apply -f -
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-creds
key: creds
EOF
生产最佳实践: 用 IRSA(IAM Roles for Service Accounts)替代静态 AK/SK:
spec:
credentials:
source: IRSA # Pod 通过 ServiceAccount 自动获取临时凭证
第 3 步:定义 Composition + XRD,暴露平台 API
这是 Crossplane 的精华 — 运维定义模板,开发者只需提交简化的 Claim:
# xrd.yaml — 定义平台级 API
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xpostgresqlinstances.database.example.org
spec:
group: database.example.org
names:
kind: XPostgreSQLInstance
plural: xpostgresqlinstances
claimNames:
kind: PostgreSQLInstance
plural: postgresqlinstances
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
parameters:
type: object
properties:
storageGB:
type: integer
default: 20
instanceClass:
type: string
default: db.t3.micro
enum: [db.t3.micro, db.t3.small, db.t3.medium]
required: [storageGB]
# composition.yaml — 运维定义资源编排逻辑
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: postgresql-aws
labels:
provider: aws
spec:
compositeTypeRef:
apiVersion: database.example.org/v1alpha1
kind: XPostgreSQLInstance
resources:
- name: rds-instance
base:
apiVersion: rds.aws.upbound.io/v1beta2
kind: Instance
spec:
forProvider:
region: ap-northeast-1
engine: postgres
engineVersion: "15"
instanceClass: db.t3.micro
allocatedStorage: 20
publiclyAccessible: false
skipFinalSnapshot: true
masterUsername: admin
masterPasswordSecretRef:
namespace: crossplane-system
name: rds-master-password
key: password
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.storageGB
toFieldPath: spec.forProvider.allocatedStorage
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.instanceClass
toFieldPath: spec.forProvider.instanceClass
- name: subnet-group
base:
apiVersion: rds.aws.upbound.io/v1beta1
kind: SubnetGroup
spec:
forProvider:
region: ap-northeast-1
subnetIds:
- subnet-xxxxxxxx
- subnet-yyyyyyyy
description: "Managed by Crossplane"
# claim.yaml — 开发者提交的资源申请(极简)
apiVersion: database.example.org/v1alpha1
kind: PostgreSQLInstance
metadata:
name: order-service-db
namespace: team-order
spec:
parameters:
storageGB: 50
instanceClass: db.t3.small
compositionSelector:
matchLabels:
provider: aws
开发者只需 kubectl apply -f claim.yaml,Crossplane 自动创建 RDS 实例 + Subnet Group,并将连接信息写入指定 Secret。
避坑指南
1. Provider 版本与 CRD 膨胀
Crossplane AWS Provider 全量安装会注册 900+ CRD,导致 API Server 内存飙升。
解法: 使用 Provider Family 按需安装(如只装 provider-aws-s3 + provider-aws-rds),不要装 monolithic provider-aws。
# 查看 CRD 数量
kubectl get crds | grep -c upbound
# 目标:控制在 100 个以内
2. 资源删除策略必须显式配置
默认 deletionPolicy: Delete,删除 Claim 会级联删除云资源(包括 RDS 数据!)。
解法: 生产环境强制设置 deletionPolicy: Orphan:
spec:
forProvider:
...
deletionPolicy: Orphan # 删除 CR 不删除云资源
配合 Usage 资源做删除保护:
apiVersion: apiextensions.crossplane.io/v1alpha1
kind: Usage
metadata:
name: protect-order-db
spec:
of:
apiVersion: rds.aws.upbound.io/v1beta2
kind: Instance
resourceRef:
name: order-service-db-xxxxx
reason: "Production database - cannot delete"
3. 调试技巧:资源创建失败时的排查路径
# 1. 查看 Claim 状态
kubectl describe postgresqlinstance order-service-db -n team-order
# 2. 查看 Composite Resource 事件
kubectl get composite -o wide
kubectl describe xpostgresqlinstance <name>
# 3. 查看 Managed Resource 具体报错
kubectl get managed | grep -i false
kubectl describe instance.rds <name>
# 4. Provider Pod 日志
kubectl logs -n crossplane-system -l pkg.crossplane.io/revision -c package-runtime --tail=50
常见报错及对策:
- cannot resolve references → 检查跨资源引用的 label/name
- access denied → 检查 IAM 权限,Provider IRSA Role 是否绑定正确
- resource already exists → 加 crossplane.io/external-name annotation 导入已有资源
总结
| 对比维度 | Terraform | Crossplane |
|---|---|---|
| 状态存储 | 外部 Backend(S3/Consul) | Kubernetes etcd |
| 漂移修复 | 手动 terraform apply | Controller 自动 reconcile |
| 权限模型 | 云 IAM 独立管理 | K8s RBAC 统一管控 |
| 开发者自助 | 需额外平台(Atlantis/Spacelift) | kubectl apply Claim |
| 生态成熟度 | 极成熟,Provider 覆盖广 | 快速追赶,核心云资源已覆盖 |
| 适用场景 | 一次性 provisioning、多云统一 | 持续 reconcile、平台工程 |
核心结论: Crossplane 不是 Terraform 的替代品,而是面向平台工程团队的补充方案。如果你已经在用 Kubernetes + GitOps 管理应用,用 Crossplane 管理基础设施可以实现 统一控制面 + 开发者自助 + 自动漂移修复 三合一。建议从非核心资源(S3 Bucket、SQS Queue)开始试点,再逐步扩展到数据库和网络。