Cluster Provisioning
This page describes the Crossplane XRDs and Compositions for provisioning infrastructure cluster pools (Phase 1). These pools are consumed by OpenStack clusters in Phase 2.
The pool model defines separate XRDs for each cluster type that can be provisioned independently:
XControlPlaneCluster (Control Plane Provisioning)
yaml
# XRD - Control Plane Cluster API
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xcontrolplaneclusters.crossplane.c5c3.io
spec:
group: crossplane.c5c3.io
names:
kind: XControlPlaneCluster
plural: xcontrolplaneclusters
claimNames:
kind: ControlPlaneCluster
plural: controlplaneclusters
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
required:
- region
properties:
region:
type: string
description: "Gardener region (e.g., eu-de-1)"
kubernetesVersion:
type: string
default: "1.29"
workers:
type: integer
default: 5
description: "Number of worker nodes"
machineType:
type: string
default: "m5.2xlarge"
volumeSize:
type: string
default: "200Gi"
highAvailability:
type: boolean
default: true
description: "HA mode with multi-AZ"
status:
type: object
properties:
phase:
type: string
enum: [Provisioning, Ready, Failed]
clusterName:
type: string
kubeconfig:
type: string
description: "Secret reference for kubeconfig"XHypervisorCluster (Hypervisor Pool Provisioning)
yaml
# XRD - Hypervisor Cluster Pool API
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xhypervisorclusters.crossplane.c5c3.io
spec:
group: crossplane.c5c3.io
names:
kind: XHypervisorCluster
plural: xhypervisorclusters
claimNames:
kind: HypervisorCluster
plural: hypervisorclusters
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
required:
- region
- name
properties:
region:
type: string
description: "Gardener region (e.g., eu-de-1)"
name:
type: string
description: "Pool name (e.g., hv-pool-a)"
kubernetesVersion:
type: string
default: "1.29"
workers:
type: integer
default: 20
description: "Number of hypervisor nodes in the pool"
maxWorkers:
type: integer
default: 100
description: "Maximum number for autoscaling"
ironcore:
type: object
required:
- machinePool
properties:
machinePool:
type: string
description: "IronCore machine pool name"
machineClass:
type: string
default: "baremetal-kvm"
labels:
type: object
additionalProperties:
type: string
description: "Labels for scheduling (e.g., availability-zone, hardware-gen)"
status:
type: object
properties:
phase:
type: string
enum: [Provisioning, Ready, Scaling, Failed]
clusterName:
type: string
nodeCount:
type: integer
availableCapacity:
type: object
properties:
vcpus:
type: integer
memoryGB:
type: integerXStorageCluster (Storage Pool Provisioning)
yaml
# XRD - Storage Cluster Pool API
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xstorageclusters.crossplane.c5c3.io
spec:
group: crossplane.c5c3.io
names:
kind: XStorageCluster
plural: xstorageclusters
claimNames:
kind: StorageCluster
plural: storageclusters
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
required:
- region
- name
properties:
region:
type: string
description: "Gardener region (e.g., eu-de-1)"
name:
type: string
description: "Pool name (e.g., st-pool-a)"
kubernetesVersion:
type: string
default: "1.29"
workers:
type: integer
default: 5
description: "Number of storage nodes in the pool"
ironcore:
type: object
required:
- machinePool
properties:
machinePool:
type: string
description: "IronCore machine pool name"
machineClass:
type: string
default: "baremetal-storage"
ceph:
type: object
properties:
osdCount:
type: integer
default: 15
description: "OSDs per node"
deviceClass:
type: string
default: "nvme"
enum: [hdd, ssd, nvme]
targetCapacity:
type: string
description: "Target capacity (e.g., 500Ti)"
replicationFactor:
type: integer
default: 3
arbiterCluster:
type: string
description: "Reference to arbiter cluster for stretch setup"
status:
type: object
properties:
phase:
type: string
enum: [Provisioning, Ready, Expanding, Failed]
clusterName:
type: string
capacity:
type: object
properties:
total:
type: string
available:
type: string
used:
type: string
health:
type: string
enum: [HEALTH_OK, HEALTH_WARN, HEALTH_ERR]Compositions: Cluster Pool Templates
Each cluster type has its own Composition that enables independent provisioning.
Composition: Control Plane Cluster
yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: control-plane-cluster
labels:
crossplane.io/xrd: xcontrolplaneclusters.crossplane.c5c3.io
spec:
compositeTypeRef:
apiVersion: crossplane.c5c3.io/v1alpha1
kind: XControlPlaneCluster
resources:
# Control Plane Cluster (Gardener Shoot)
- name: control-plane-shoot
base:
apiVersion: core.gardener.cloud/v1beta1
kind: Shoot
spec:
cloudProfileName: converged-cloud
secretBindingName: cc-credentials
region: "" # Patched
kubernetes:
version: "1.29"
provider:
type: openstack
workers:
- name: control-plane
machine:
type: "" # Patched
minimum: 3
maximum: 10
volume:
size: "" # Patched
purpose: production
controlPlane:
highAvailability:
failureTolerance:
type: zone
patches:
- fromFieldPath: metadata.name
toFieldPath: metadata.name
- fromFieldPath: spec.region
toFieldPath: spec.region
- fromFieldPath: spec.kubernetesVersion
toFieldPath: spec.kubernetes.version
- fromFieldPath: spec.machineType
toFieldPath: spec.provider.workers[0].machine.type
- fromFieldPath: spec.workers
toFieldPath: spec.provider.workers[0].minimum
- fromFieldPath: spec.volumeSize
toFieldPath: spec.provider.workers[0].volume.size
# ProviderConfig for provider-kubernetes
- name: provider-config
base:
apiVersion: kubernetes.crossplane.io/v1alpha1
kind: ProviderConfig
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
key: kubeconfig
patches:
- fromFieldPath: metadata.name
toFieldPath: metadata.name
- fromFieldPath: metadata.name
toFieldPath: spec.credentials.secretRef.name
transforms:
- type: string
string:
fmt: "%s-kubeconfig"Composition: Hypervisor Cluster Pool
yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: hypervisor-cluster-pool
labels:
crossplane.io/xrd: xhypervisorclusters.crossplane.c5c3.io
spec:
compositeTypeRef:
apiVersion: crossplane.c5c3.io/v1alpha1
kind: XHypervisorCluster
resources:
# Hypervisor Cluster (Gardener Shoot with IronCore)
- name: hypervisor-shoot
base:
apiVersion: core.gardener.cloud/v1beta1
kind: Shoot
spec:
cloudProfileName: ironcore
secretBindingName: ironcore-credentials
region: "" # Patched
kubernetes:
version: "1.29"
provider:
type: ironcore
workers:
- name: hypervisor
machine:
type: "" # Patched
image:
name: gardenlinux
minimum: 5
maximum: 100
patches:
- fromFieldPath: spec.name
toFieldPath: metadata.name
- fromFieldPath: spec.region
toFieldPath: spec.region
- fromFieldPath: spec.kubernetesVersion
toFieldPath: spec.kubernetes.version
- fromFieldPath: spec.ironcore.machineClass
toFieldPath: spec.provider.workers[0].machine.type
- fromFieldPath: spec.workers
toFieldPath: spec.provider.workers[0].minimum
- fromFieldPath: spec.maxWorkers
toFieldPath: spec.provider.workers[0].maximum
- fromFieldPath: spec.labels
toFieldPath: metadata.labels
policy:
mergeOptions:
appendSlice: trueComposition: Storage Cluster Pool
yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: storage-cluster-pool
labels:
crossplane.io/xrd: xstorageclusters.crossplane.c5c3.io
spec:
compositeTypeRef:
apiVersion: crossplane.c5c3.io/v1alpha1
kind: XStorageCluster
resources:
# Storage Cluster (Gardener Shoot with IronCore)
- name: storage-shoot
base:
apiVersion: core.gardener.cloud/v1beta1
kind: Shoot
spec:
cloudProfileName: ironcore
secretBindingName: ironcore-credentials
region: "" # Patched
kubernetes:
version: "1.29"
provider:
type: ironcore
workers:
- name: storage
machine:
type: "" # Patched
image:
name: gardenlinux
minimum: 3
maximum: 30
patches:
- fromFieldPath: spec.name
toFieldPath: metadata.name
- fromFieldPath: spec.region
toFieldPath: spec.region
- fromFieldPath: spec.kubernetesVersion
toFieldPath: spec.kubernetes.version
- fromFieldPath: spec.ironcore.machineClass
toFieldPath: spec.provider.workers[0].machine.type
- fromFieldPath: spec.workers
toFieldPath: spec.provider.workers[0].minimumClaims: Provision Cluster Pools
The pools are provisioned independently of each other. Once ready, they can be referenced by OpenStack cluster claims. For full provisioning flow details, see Operations.
yaml
# Claim: Control Plane Cluster
apiVersion: crossplane.c5c3.io/v1alpha1
kind: ControlPlaneCluster
metadata:
name: eu-de-1-control-plane
namespace: infrastructure
spec:
region: eu-de-1
kubernetesVersion: "1.29"
workers: 5
machineType: m5.4xlarge
volumeSize: 200Gi
highAvailability: true
---
# Claim: Hypervisor Pool A (50 Nodes)
apiVersion: crossplane.c5c3.io/v1alpha1
kind: HypervisorCluster
metadata:
name: hv-pool-a
namespace: infrastructure
spec:
region: eu-de-1
name: hv-pool-a
workers: 50
maxWorkers: 100
ironcore:
machinePool: ironcore-baremetal-kvm
machineClass: baremetal-kvm
labels:
tier: standard
availability-zone: az-1
---
# Claim: Hypervisor Pool B (100 Nodes, Premium)
apiVersion: crossplane.c5c3.io/v1alpha1
kind: HypervisorCluster
metadata:
name: hv-pool-b
namespace: infrastructure
spec:
region: eu-de-1
name: hv-pool-b
workers: 100
maxWorkers: 200
ironcore:
machinePool: ironcore-baremetal-kvm-premium
machineClass: baremetal-kvm-premium
labels:
tier: premium
availability-zone: az-2
---
# Claim: Storage Pool A (500TB Ceph)
apiVersion: crossplane.c5c3.io/v1alpha1
kind: StorageCluster
metadata:
name: st-pool-a
namespace: infrastructure
spec:
region: eu-de-1
name: st-pool-a
workers: 10
ironcore:
machinePool: ironcore-baremetal-storage
machineClass: baremetal-storage
ceph:
osdCount: 30
deviceClass: nvme
targetCapacity: 500Ti
replicationFactor: 3