Crossplane云原生基础设施管理技能Skill crossplane

Crossplane是一个基于Kubernetes的云原生控制平面技能,用于通过声明式API管理多云基础设施。它支持平台工程、自服务基础设施供应、复合资源定义和基础设施即代码,实现多云资源的统一管理和自动化部署。关键词:Crossplane, Kubernetes, 云原生, 基础设施即代码, 平台工程, 多云管理, 声明式API, 复合资源, 自服务基础设施, 云控制平面。

云原生架构 0 次安装 0 次浏览 更新于 3/24/2026

名称: crossplane 描述: 使用Kubernetes API进行云原生基础设施管理的Crossplane。构建内部平台API以实现自服务基础设施供应。适用于实施基础设施即代码、平台工程、复合资源、XRD、组合、声明、提供商配置或多云供应。触发词: crossplane, XRD, 组合, 声明, 提供商, 托管资源, 复合资源, 基础设施API, 平台工程, 平台API, 基础设施抽象, 自服务基础设施, Kubernetes基础设施, 云控制平面。 允许工具: 读取, Grep, Glob, 编辑, 写入, Bash

Crossplane 基础设施管理

Crossplane 扩展了 Kubernetes,使用声明式 API 管理云基础设施。它使平台团队能够构建具有自服务能力的内部云平台。

架构概述

核心组件

  1. 提供商: Kubernetes 控制器,在外部系统(AWS、GCP、Azure 等)中供应基础设施。
  2. 托管资源 (MRs): 表示外部基础设施(S3 存储桶、RDS 实例等)的自定义资源。
  3. 复合资源 (XRs): 由多个托管资源组成的高级抽象。
  4. 复合资源定义 (XRDs): 定义复合资源类型的模式。
  5. 组合: 模板,使用转换逻辑将 XRs 映射到托管资源。
  6. 声明: 命名空间范围资源,为应用团队供应复合资源。
  7. 组合函数: 用于复杂转换逻辑的扩展点。

资源层次结构

声明(命名空间范围) -> 复合资源(集群范围) -> 托管资源 -> 云基础设施

安装和设置

安装 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

最佳实践

组合模式

分层抽象策略

以递增的抽象层次构建组合:

  1. 基础层: 提供商特定的托管资源(S3、RDS、GCS)
  2. 资源层: 云无关的 XRD(数据库、对象存储)
  3. 平台层: 应用关注的 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 迁移

  1. 导出资源的 Terraform 状态
  2. 创建等效托管资源并匹配外部名称
  3. 使用 external-name 注释导入到 Crossplane
  4. 逐步围绕托管资源构建组合
  5. 迁移团队到声明

参考资料