名称: crossplane 描述: 使用Kubernetes API进行云原生基础设施管理的Crossplane。构建内部平台API以实现自服务基础设施供应。适用于实施基础设施即代码、平台工程、复合资源、XRD、组合、声明、提供商配置或多云供应。触发词: crossplane, XRD, 组合, 声明, 提供商, 托管资源, 复合资源, 基础设施API, 平台工程, 平台API, 基础设施抽象, 自服务基础设施, Kubernetes基础设施, 云控制平面。 允许工具: 读取, Grep, Glob, 编辑, 写入, Bash
Crossplane 基础设施管理
Crossplane 扩展了 Kubernetes,使用声明式 API 管理云基础设施。它使平台团队能够构建具有自服务能力的内部云平台。
架构概述
核心组件
- 提供商: Kubernetes 控制器,在外部系统(AWS、GCP、Azure 等)中供应基础设施。
- 托管资源 (MRs): 表示外部基础设施(S3 存储桶、RDS 实例等)的自定义资源。
- 复合资源 (XRs): 由多个托管资源组成的高级抽象。
- 复合资源定义 (XRDs): 定义复合资源类型的模式。
- 组合: 模板,使用转换逻辑将 XRs 映射到托管资源。
- 声明: 命名空间范围资源,为应用团队供应复合资源。
- 组合函数: 用于复杂转换逻辑的扩展点。
资源层次结构
声明(命名空间范围) -> 复合资源(集群范围) -> 托管资源 -> 云基础设施
安装和设置
安装 Crossplane
# 添加 Crossplane Helm 仓库
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
# 安装 Crossplane
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace \
--set args='{"--enable-composition-functions"}' \
--wait
# 验证安装
kubectl get pods -n crossplane-system
安装 Crossplane CLI
# 安装 CLI 用于本地开发
curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | sh
sudo mv crossplane /usr/local/bin/
# 验证 CLI
crossplane --version
提供商配置
AWS 提供商
# providers/aws-provider.yaml
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-s3
spec:
package: xpkg.upbound.io/upbound/provider-aws-s3:v1.1.0
controllerConfigRef:
name: aws-config
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-rds
spec:
package: xpkg.upbound.io/upbound/provider-aws-rds:v1.1.0
controllerConfigRef:
name: aws-config
---
apiVersion: pkg.crossplane.io/v1alpha1
kind: ControllerConfig
metadata:
name: aws-config
spec:
podSecurityContext:
fsGroup: 2000
args:
- --poll=1m
- --max-reconcile-rate=100
提供商认证
# 创建 AWS 凭证密钥
kubectl create secret generic aws-creds \
-n crossplane-system \
--from-file=creds=/path/to/aws-credentials.txt
# credentials.txt 格式:
# [default]
# aws_access_key_id = AKIAIOSFODNN7EXAMPLE
# aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# providers/aws-provider-config.yaml
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-creds
key: creds
GCP 提供商
# providers/gcp-provider.yaml
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp-storage
spec:
package: xpkg.upbound.io/upbound/provider-gcp-storage:v1.1.0
---
apiVersion: gcp.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
projectID: my-gcp-project
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: gcp-creds
key: creds.json
托管资源
直接使用托管资源
# managed-resources/s3-bucket.yaml
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: my-app-data-bucket
spec:
forProvider:
region: us-west-2
tags:
Environment: production
ManagedBy: crossplane
providerConfigRef:
name: default
deletionPolicy: Delete
# managed-resources/rds-instance.yaml
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
metadata:
name: my-postgres-db
spec:
forProvider:
region: us-west-2
allocatedStorage: 20
engine: postgres
engineVersion: "14.7"
instanceClass: db.t3.micro
dbName: myappdb
username: dbadmin
passwordSecretRef:
namespace: crossplane-system
name: db-password
key: password
skipFinalSnapshot: true
publiclyAccessible: false
vpcSecurityGroupIdSelector:
matchLabels:
role: database
providerConfigRef:
name: default
writeConnectionSecretToRef:
namespace: production
name: postgres-connection
复合资源定义 (XRDs)
数据库 XRD
# xrds/database-xrd.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xpostgresqlinstances.database.example.com
spec:
group: database.example.com
names:
kind: XPostgreSQLInstance
plural: xpostgresqlinstances
claimNames:
kind: PostgreSQLInstance
plural: postgresqlinstances
connectionSecretKeys:
- username
- password
- endpoint
- port
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
parameters:
type: object
properties:
storageGB:
type: integer
description: 数据库大小(GB)
default: 20
minimum: 20
maximum: 1000
size:
type: string
description: 实例大小(small, medium, large)
enum: [small, medium, large]
default: small
engineVersion:
type: string
description: PostgreSQL 版本
default: "14.7"
highAvailability:
type: boolean
description: 启用多可用区部署
default: false
backupRetentionDays:
type: integer
description: 备份保留天数
default: 7
minimum: 1
maximum: 35
networkRef:
type: object
description: 网络配置引用
properties:
id:
type: string
description: 网络标识符
required:
- id
required:
- size
- networkRef
required:
- parameters
status:
type: object
properties:
address:
type: string
description: 数据库端点地址
应用平台 XRD
# xrds/app-platform-xrd.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xappplatforms.platform.example.com
spec:
group: platform.example.com
names:
kind: XAppPlatform
plural: xappplatforms
claimNames:
kind: AppPlatform
plural: appplatforms
connectionSecretKeys:
- bucket_name
- database_endpoint
- database_password
- cache_endpoint
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
parameters:
type: object
properties:
environment:
type: string
description: 环境(dev, staging, prod)
enum: [dev, staging, prod]
appName:
type: string
description: 应用名称
pattern: "^[a-z0-9-]+$"
region:
type: string
description: AWS 区域
default: us-west-2
databaseSize:
type: string
description: 数据库实例大小
enum: [small, medium, large]
default: small
enableCache:
type: boolean
description: 启用 Redis 缓存
default: false
required:
- environment
- appName
required:
- parameters
组合
带大小映射的数据库组合
# compositions/postgres-composition.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: postgres.aws.database.example.com
labels:
provider: aws
database: postgresql
spec:
writeConnectionSecretsToNamespace: crossplane-system
compositeTypeRef:
apiVersion: database.example.com/v1alpha1
kind: XPostgreSQLInstance
resources:
# 数据库安全组
- name: database-sg
base:
apiVersion: ec2.aws.upbound.io/v1beta1
kind: SecurityGroup
spec:
forProvider:
description: PostgreSQL 数据库的安全组
tags:
Name: database-sg
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.networkRef.id
toFieldPath: spec.forProvider.vpcId
- type: FromCompositeFieldPath
fromFieldPath: metadata.labels[crossplane.io/claim-namespace]
toFieldPath: spec.forProvider.tags.namespace
- type: FromCompositeFieldPath
fromFieldPath: metadata.labels[crossplane.io/claim-name]
toFieldPath: spec.forProvider.tags.claim
# 安全组规则 - Postgres 端口
- name: database-sg-rule
base:
apiVersion: ec2.aws.upbound.io/v1beta1
kind: SecurityGroupRule
spec:
forProvider:
type: ingress
fromPort: 5432
toPort: 5432
protocol: tcp
cidrBlocks:
- 10.0.0.0/8
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.networkRef.id
toFieldPath: spec.forProvider.vpcId
- type: PatchSet
patchSetName: security-group-id
# RDS 子网组
- name: subnet-group
base:
apiVersion: rds.aws.upbound.io/v1beta1
kind: SubnetGroup
spec:
forProvider:
description: 数据库子网组
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.networkRef.id
toFieldPath: metadata.labels[network-id]
- type: FromCompositeFieldPath
fromFieldPath: metadata.uid
toFieldPath: spec.forProvider.subnetIdSelector.matchLabels[subnet-group-id]
# RDS 实例
- name: rds-instance
base:
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
spec:
forProvider:
engine: postgres
skipFinalSnapshot: true
publiclyAccessible: false
username: dbadmin
passwordSecretRef:
namespace: crossplane-system
key: password
dbSubnetGroupNameSelector:
matchControllerRef: true
vpcSecurityGroupIdSelector:
matchControllerRef: true
writeConnectionSecretToRef:
namespace: crossplane-system
patches:
# 实例大小映射
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.size
toFieldPath: spec.forProvider.instanceClass
transforms:
- type: map
map:
small: db.t3.micro
medium: db.t3.medium
large: db.m5.large
# 存储配置
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.storageGB
toFieldPath: spec.forProvider.allocatedStorage
# 引擎版本
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.engineVersion
toFieldPath: spec.forProvider.engineVersion
# 高可用性
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.highAvailability
toFieldPath: spec.forProvider.multiAz
# 备份保留
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.backupRetentionDays
toFieldPath: spec.forProvider.backupRetentionPeriod
# 生成唯一密码密钥名称
- type: FromCompositeFieldPath
fromFieldPath: metadata.uid
toFieldPath: spec.forProvider.passwordSecretRef.name
transforms:
- type: string
string:
fmt: "%s-password"
# 连接密钥名称
- type: FromCompositeFieldPath
fromFieldPath: metadata.uid
toFieldPath: spec.writeConnectionSecretToRef.name
transforms:
- type: string
string:
fmt: "%s-connection"
# 将端点暴露到状态
- type: ToCompositeFieldPath
fromFieldPath: status.atProvider.endpoint
toFieldPath: status.address
# 将连接密钥复制到声明命名空间
- type: FromCompositeFieldPath
fromFieldPath: metadata.labels[crossplane.io/claim-namespace]
toFieldPath: spec.writeConnectionSecretToRef.namespace
policy:
fromFieldPath: Optional
patchSets:
- name: security-group-id
patches:
- type: FromCompositeFieldPath
fromFieldPath: metadata.labels[security-group-id]
toFieldPath: spec.forProvider.securityGroupIdSelector.matchLabels[security-group-id]
多资源应用平台组合
# compositions/app-platform-composition.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: appplatform.aws.platform.example.com
labels:
provider: aws
spec:
writeConnectionSecretsToNamespace: crossplane-system
compositeTypeRef:
apiVersion: platform.example.com/v1alpha1
kind: XAppPlatform
resources:
# 应用数据的 S3 存储桶
- name: storage-bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
tags:
ManagedBy: crossplane
deletionPolicy: Delete
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.region
toFieldPath: spec.forProvider.region
- type: CombineFromComposite
combine:
variables:
- fromFieldPath: spec.parameters.appName
- fromFieldPath: spec.parameters.environment
strategy: string
string:
fmt: "%s-%s-data"
toFieldPath: metadata.name
- type: ToCompositeFieldPath
fromFieldPath: metadata.name
toFieldPath: status.bucketName
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.environment
toFieldPath: spec.forProvider.tags.Environment
# S3 存储桶版本控制
- name: bucket-versioning
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: BucketVersioning
spec:
forProvider:
versioningConfiguration:
status: Enabled
bucketSelector:
matchControllerRef: true
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.region
toFieldPath: spec.forProvider.region
# S3 存储桶加密
- name: bucket-encryption
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: BucketServerSideEncryptionConfiguration
spec:
forProvider:
rule:
applyServerSideEncryptionByDefault:
sseAlgorithm: AES256
bucketSelector:
matchControllerRef: true
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.region
toFieldPath: spec.forProvider.region
# PostgreSQL 数据库(使用我们的 XRD)
- name: database
base:
apiVersion: database.example.com/v1alpha1
kind: XPostgreSQLInstance
spec:
parameters:
engineVersion: "14.7"
storageGB: 20
highAvailability: false
backupRetentionDays: 7
networkRef:
id: vpc-12345
compositionSelector:
matchLabels:
provider: aws
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.databaseSize
toFieldPath: spec.parameters.size
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.environment
toFieldPath: spec.parameters.highAvailability
transforms:
- type: map
map:
dev: false
staging: false
prod: true
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.environment
toFieldPath: spec.parameters.backupRetentionDays
transforms:
- type: map
map:
dev: 1
staging: 7
prod: 30
- type: ToCompositeFieldPath
fromFieldPath: status.address
toFieldPath: status.databaseEndpoint
# ElastiCache Redis
# 注意:对于真正有条件的资源,使用组合函数(如 function-conditional)或创建单独的组合。此示例在包含在组合中时总是供应缓存。
- name: cache
base:
apiVersion: elasticache.aws.upbound.io/v1beta1
kind: ReplicationGroup
spec:
forProvider:
description: Redis 缓存集群
engine: redis
engineVersion: "7.0"
nodeType: cache.t3.micro
numCacheClusters: 1
automaticFailoverEnabled: false
atRestEncryptionEnabled: true
transitEncryptionEnabled: true
securityGroupIdSelector:
matchControllerRef: true
subnetGroupNameSelector:
matchControllerRef: true
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.region
toFieldPath: spec.forProvider.region
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.environment
toFieldPath: spec.forProvider.automaticFailoverEnabled
transforms:
- type: map
map:
dev: false
staging: false
prod: true
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.environment
toFieldPath: spec.forProvider.numCacheClusters
transforms:
- type: map
map:
dev: 1
staging: 2
prod: 3
- type: ToCompositeFieldPath
fromFieldPath: status.atProvider.primaryEndpointAddress
toFieldPath: status.cacheEndpoint
声明(自服务资源)
数据库声明
# claims/my-app-database.yaml
apiVersion: database.example.com/v1alpha1
kind: PostgreSQLInstance
metadata:
name: my-app-db
namespace: production
spec:
parameters:
size: medium
storageGB: 100
engineVersion: "14.7"
highAvailability: true
backupRetentionDays: 30
networkRef:
id: vpc-0a1b2c3d4e5f6g7h8
compositionSelector:
matchLabels:
provider: aws
database: postgresql
writeConnectionSecretToRef:
name: my-app-db-connection
应用平台声明
# claims/my-app-platform.yaml
apiVersion: platform.example.com/v1alpha1
kind: AppPlatform
metadata:
name: my-application
namespace: team-alpha
spec:
parameters:
environment: prod
appName: my-app
region: us-west-2
databaseSize: large
enableCache: true
compositionSelector:
matchLabels:
provider: aws
writeConnectionSecretToRef:
name: my-app-platform-secrets
组合函数
组合函数使用 WebAssembly 或基于容器的函数实现复杂转换逻辑。
函数配置
# compositions/postgres-with-functions.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: postgres.function-based.aws.database.example.com
spec:
compositeTypeRef:
apiVersion: database.example.com/v1alpha1
kind: XPostgreSQLInstance
mode: Pipeline
pipeline:
# 步骤 1: 使用函数生成密码
- step: generate-password
functionRef:
name: function-auto-ready
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: db-password-secret
base:
apiVersion: v1
kind: Secret
metadata:
namespace: crossplane-system
type: Opaque
stringData:
password: ""
patches:
- type: FromCompositeFieldPath
fromFieldPath: metadata.uid
toFieldPath: metadata.name
transforms:
- type: string
string:
fmt: "%s-password"
- type: CombineFromComposite
combine:
variables:
- fromFieldPath: metadata.uid
strategy: string
string:
fmt: "GENERATE_PASSWORD_32"
toFieldPath: stringData.password
# 步骤 2: 修补和转换资源
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
patchSets:
- name: common-tags
patches:
- type: FromCompositeFieldPath
fromFieldPath: metadata.labels[crossplane.io/claim-name]
toFieldPath: spec.forProvider.tags.ClaimName
- type: FromCompositeFieldPath
fromFieldPath: metadata.labels[crossplane.io/claim-namespace]
toFieldPath: spec.forProvider.tags.ClaimNamespace
resources:
- name: rds-instance
base:
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
spec:
forProvider:
engine: postgres
username: dbadmin
skipFinalSnapshot: true
patches:
- type: PatchSet
patchSetName: common-tags
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.size
toFieldPath: spec.forProvider.instanceClass
transforms:
- type: map
map:
small: db.t3.micro
medium: db.t3.medium
large: db.m5.large
# 步骤 3: 标记为就绪
- step: auto-ready
functionRef:
name: function-auto-ready
安装组合函数
# 安装 function-patch-and-transform
kubectl apply -f - <<EOF
apiVersion: pkg.crossplane.io/v1beta1
kind: Function
metadata:
name: function-patch-and-transform
spec:
package: xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.2.1
EOF
# 安装 function-auto-ready
kubectl apply -f - <<EOF
apiVersion: pkg.crossplane.io/v1beta1
kind: Function
metadata:
name: function-auto-ready
spec:
package: xpkg.upbound.io/crossplane-contrib/function-auto-ready:v0.2.1
EOF
最佳实践
组合模式
分层抽象策略
以递增的抽象层次构建组合:
- 基础层: 提供商特定的托管资源(S3、RDS、GCS)
- 资源层: 云无关的 XRD(数据库、对象存储)
- 平台层: 应用关注的 XRD(应用平台、数据平台)
这使团队能在适当的抽象级别使用基础设施。
并行资源创建
当没有依赖关系时,Crossplane 自动并行供应资源。优化:
- 使用选择器(matchControllerRef、matchLabels)而不是显式引用
- 让 Crossplane 从资源关系中推断依赖
- 避免人工顺序约束
转换模式
常见的修补转换模式:
- 大小映射: 将 small/medium/large 映射到实例类型
- 环境逻辑: 将 dev/staging/prod 映射到不同配置
- 字符串格式化: 使用 CombineFromComposite 和 fmt 命名
- 数学操作: 乘以存储大小和环境因子
- 条件值: 将布尔标志映射到提供商特定设置
密钥聚合
合并来自多个托管资源的连接密钥:
- 每个托管资源写入唯一密钥
- 使用 XRD 中的 connectionSecretKeys 定义合并字段
- Crossplane 自动聚合到复合密钥
- 复制到声明命名空间供应用使用
声明设计模式
命名空间策略
选择适合组织的命名空间模型:
- 每团队命名空间: team-alpha、team-beta(适合多租户)
- 每环境命名空间: dev、staging、prod(适合环境隔离)
- 混合方法: team-alpha-prod、team-alpha-dev(最大隔离)
使用 RBAC 控制哪些团队可以在哪些命名空间中创建声明。
自服务护栏
在 XRD 中构建护栏以防止错误配置:
- 使用枚举限制选择(small/medium/large,非任意值)
- 设置存储、副本、保留期的最小/最大约束
- 为可选参数提供合理默认
- 使用正则模式命名约定
- 在字段描述中记录预期值
声明生命周期管理
为第 2 天操作设计声明:
- 启用无需替换的更新(使用 forProvider.applyMethod)
- 通过参数更改支持扩展操作
- 从第 1 天包含备份/恢复配置
- 规划灾难恢复场景
- 记录哪些参数可在创建后更改
成本可见性
使成本影响对声明用户可见:
- 添加成本相关元数据到 XRD 描述
- 使用标签进行成本分配(团队、项目、环境)
- 记录大小级别和大致成本
- 通过验证 webhook 实现预算控制
- 导出成本标签到云提供商账单
提供商配置策略
多账户架构
为不同账户/环境使用单独的 ProviderConfigs:
- 在云账户级别隔离生产和非生产
- 使用 IRSA(IAM 角色服务账户)进行 AWS 认证
- 配置 GCP 的工作负载身份
- 实现 Azure 的托管身份
在组合或允许声明指定中引用适当的 ProviderConfig。
凭证轮换
实施安全凭证管理:
- 使用外部密钥存储(Vault、AWS Secrets Manager)
- 配置 ESO(External Secrets Operator)集成
- 定期轮换凭证
- 尽可能使用短期凭证
- 避免在 Git 中存储凭证
提供商范围
战略性地安装提供商系列:
- 使用范围化提供商(provider-aws-s3)而非单一提供商(provider-aws)
- 减少内存占用和调和负载
- 仅安装必需的提供商系列
- 为高流量系列配置单独控制器副本
- 按提供商调优轮询间隔(–poll 标志)
速率限制
为生产规模配置提供商控制器:
- 基于 API 配额设置 --max-reconcile-rate
- 配置 --poll 间隔以平衡新鲜度和负载
- 使用 --enable-management-policies 进行精细控制
- 监控提供商控制器 CPU/内存使用情况
- 为高资源计数扩展控制器副本
XRD 设计
保持 XRD 简单专注
- 每个 XRD 应代表单一逻辑资源类型
- 避免将无关基础设施合并到一个 XRD 中
- 使用组合从简单 XRD 构建复杂平台
版本化您的 API
- 从 v1alpha1 开始,演变为 v1beta1,然后 v1
- 使用多个版本支持向后兼容性
- 清晰记录破坏性更改
定义清晰的模式
- 使用 OpenAPI 验证(枚举、模式、最小/最大)
- 提供合理默认
- 明确标记必需字段
- 为所有字段添加描述
连接密钥
- 仅暴露必要的连接详情
- 跨 XRD 使用一致的密钥名称
- 记录预期的密钥密钥
组合指南
资源命名
- 基于复合 UID 使用确定性名称
- 避免与 CombineFromComposite 修补冲突
- 考虑外部名称要求
修补策略
- 使用 PatchSets 处理公共修补
- 应用 FromCompositeFieldPath 处理用户输入
- 使用 ToCompositeFieldPath 进行状态更新
- 利用转换(映射、字符串格式化、数学)
资源依赖
- 使用选择器(matchControllerRef、matchLabels)进行引用
- Crossplane 自动处理依赖排序
- 避免循环依赖
环境特定逻辑
- 使用映射转换按环境变化资源
- 示例:dev 用小实例,prod 用大实例
- 基于布尔标志的条件资源
连接密钥传播
- 先将密钥写入 crossplane-system 命名空间
- 使用修补复制到声明命名空间
- 合并来自多个资源的密钥
声明组织
命名空间策略
- 每个团队或环境一个命名空间
- 使用 RBAC 控制声明创建
- 声明是命名空间范围,XRs 是集群范围
命名约定
- 使用描述性声明名称(app-name-db,非 db-1)
- 如果未使用命名空间分离,则在名称中包含环境
- 遵循组织命名标准
标签和注释
- 添加所有权标签(团队、成本中心)
- 使用注释记录元数据(jira-ticket、owner-email)
- 标签可用于组合修补
ProviderConfig 最佳实践
多个 Provider Configs
- 为不同账户/项目使用不同的 ProviderConfigs
- 使用描述性名称(prod-aws、dev-aws)
- 在组合或声明中显式引用
凭证管理
- 尽可能使用 IRSA(IAM 角色服务账户)
- 以最小权限存储凭证到密钥
- 定期轮换凭证
资源限制
- 配置提供商控制器资源限制
- 设置适当的轮询间隔(–poll 标志)
- 为大型部署限制最大调和速率
生产准备
删除策略
- 对开发环境使用
deletionPolicy: Delete - 对生产数据库使用
deletionPolicy: Orphan - 记录平台用户的删除行为
资源标记
- 用 ManagedBy: crossplane 标记所有资源
- 包括环境、团队和成本分配标签
- 将标签从复合传播到托管资源
监控和可观测性
- 监控 Crossplane 控制器指标
- 设置故障调和警报
- 导出提供商指标到监控系统
- 定期检查资源同步状态
测试
- 在推广到生产前在开发中测试组合
- 使用 kube-linter 或类似工具验证 XRD
- 对高风险更改使用试运行模式
文档
- 用示例记录 XRD 模式
- 为平台用户提供声明模板
- 维护组合变更日志
安全
- 使用最小权限 IAM 策略
- 启用静态和传输中加密
- 尽可能使用私有端点
- 实现网络安全组/防火墙
常见操作
调试
# 检查 Crossplane 状态
kubectl get crossplane
# 查看提供商状态
kubectl get providers
# 检查托管资源
kubectl get managed
# 查看复合资源
kubectl get composite
# 描述声明以查看事件
kubectl describe postgresqlinstance my-app-db -n production
# 查看组合函数
kubectl get functions
# 检查提供商日志
kubectl logs -n crossplane-system -l pkg.crossplane.io/provider=provider-aws-s3
# 获取由组合创建的所有资源
kubectl get managed -l crossplane.io/composite=<composite-name>
故障排除
# 检查提供商是否健康
kubectl get providers
kubectl describe provider provider-aws-s3
# 验证 ProviderConfig
kubectl get providerconfigs
kubectl describe providerconfig default
# 检查调和错误
kubectl describe <resource-type> <resource-name>
# 查看条件
kubectl get <resource> <name> -o jsonpath='{.status.conditions}'
# 测试声明创建
kubectl apply -f claim.yaml --dry-run=server
# 验证 XRD
kubectl apply -f xrd.yaml --dry-run=server
更新资源
# 更新组合(更改仅适用于新复合资源)
kubectl apply -f composition.yaml
# 通过添加注释强制调和
kubectl annotate claim my-app-db crossplane.io/paused=false --overwrite
# 更新 XRD(注意破坏性更改)
kubectl apply -f xrd.yaml
# 升级提供商
kubectl apply -f provider.yaml # 使用新版本
高级模式
多区域部署
# 创建多个组合,每个区域一个
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: postgres.us-west-2.aws.database.example.com
labels:
provider: aws
region: us-west-2
spec:
compositeTypeRef:
apiVersion: database.example.com/v1alpha1
kind: XPostgreSQLInstance
# ... 为 us-west-2 配置的资源
---
# 带区域选择器的声明
apiVersion: database.example.com/v1alpha1
kind: PostgreSQLInstance
metadata:
name: my-db
spec:
compositionSelector:
matchLabels:
region: us-west-2
蓝绿部署
# 使用标签管理活动/非活动组合
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: app-v2
labels:
version: v2
active: "true"
spec:
# ... 新组合
---
# 声明选择活动版本
spec:
compositionSelector:
matchLabels:
active: "true"
条件资源创建
使用组合函数基于输入参数有条件地包含资源:
# compositions/conditional-cache-composition.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: appplatform-with-conditional-cache
spec:
compositeTypeRef:
apiVersion: platform.example.com/v1alpha1
kind: XAppPlatform
mode: Pipeline
pipeline:
# 步骤 1: 创建基础资源
- step: create-resources
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: storage-bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: us-west-2
# 步骤 2: 使用 function-kcl 或 function-go-templating 有条件地添加缓存
- step: add-cache-if-enabled
functionRef:
name: function-go-templating
input:
apiVersion: gotemplating.fn.crossplane.io/v1beta1
kind: GoTemplate
source: Inline
inline:
template: |
{{ if .observed.composite.resource.spec.parameters.enableCache }}
apiVersion: elasticache.aws.upbound.io/v1beta1
kind: ReplicationGroup
metadata:
name: {{ .observed.composite.resource.metadata.name }}-cache
annotations:
gotemplating.fn.crossplane.io/composition-resource-name: cache
spec:
forProvider:
description: Redis 缓存
engine: redis
engineVersion: "7.0"
nodeType: cache.t3.micro
numCacheClusters: 1
{{ end }}
# 步骤 3: 标记资源就绪
- step: auto-ready
functionRef:
name: function-auto-ready
替代方法使用单独组合:
# 创建两个组合:一个有缓存,一个没有
# composition-with-cache.yaml
metadata:
labels:
cache: enabled
# ... 包含缓存资源
# composition-without-cache.yaml
metadata:
labels:
cache: disabled
# ... 排除缓存资源
# 声明选择适当组合
spec:
compositionSelector:
matchLabels:
cache: enabled # 或 disabled
成本优化
# 使用基于环境的大小设置
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.environment
toFieldPath: spec.forProvider.instanceClass
transforms:
- type: map
map:
dev: db.t3.micro # $0.017/小时
staging: db.t3.small # $0.034/小时
prod: db.m5.large # $0.192/小时
迁移策略
导入现有资源
# 导入现有基础设施
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: existing-bucket
annotations:
crossplane.io/external-name: my-existing-bucket-name
spec:
forProvider:
region: us-west-2
providerConfigRef:
name: default
# Crossplane 将发现并管理此现有存储桶
从 Terraform 迁移
- 导出资源的 Terraform 状态
- 创建等效托管资源并匹配外部名称
- 使用 external-name 注释导入到 Crossplane
- 逐步围绕托管资源构建组合
- 迁移团队到声明