A Syself Autopilot cluster is made of upstream Cluster API (CAPI) objects, and you edit one of them: the `Cluster`. You set your intent on `Cluster.spec.topology`, and the topology controller expands that into every other object below it. Each object below shows its `apiVersion`, who reconciles it, and which fields are yours to change versus which the platform generates and owns. The rule to carry through the page: edit the `Cluster`, and let the controllers derive the rest. A change you make on a derived object does not last. ## The object graph A `Cluster` with `spec.topology` expands into a tree. Each object names the controller that reconciles it. | Object | apiVersion | Reconciled by | Role | | --------------------------------------------------------- | ----------------------------------------- | ---------------------------------- | ---------------------------------------------- | | `Cluster` (`spec.topology`: classRef, version, variables) | `cluster.x-k8s.io/v1beta2` | topology controller | your intent | | `ClusterClass` | `cluster.x-k8s.io/v1beta2` | authored by the stack, consumed | templates and patches | | `HetznerClusterTemplate` → `HetznerCluster` | `infrastructure.cluster.x-k8s.io/v1beta1` | CAPH | load balancer, endpoint, region | | `KubeadmControlPlane` (KCP) | `controlplane.cluster.x-k8s.io/v1beta2` | KCP controller | the control plane; owns control-plane Machines | | `MachineDeployment` (one per worker pool) | `cluster.x-k8s.io/v1beta2` | MachineDeployment controller | a worker pool; owns a MachineSet | | `MachineSet` → `Machine` | `cluster.x-k8s.io/v1beta2` | MachineSet and Machine controllers | one Machine is one node | | `KubeadmConfig` (per Machine) | `bootstrap.cluster.x-k8s.io/v1beta2` | CABPK | renders the bootstrap Secret | | `HCloudMachine` / `HetznerBareMetalMachine` (per Machine) | `infrastructure.cluster.x-k8s.io/v1beta1` | CAPH | provisions the server | The Hetzner objects (`HetznerCluster`, `HCloudMachine`, `HetznerBareMetalMachine`) are reconciled by CAPH, the Cluster API Provider Hetzner. Syself created and maintains CAPH as open source: [github.com/syself/cluster-api-provider-hetzner](https://github.com/syself/cluster-api-provider-hetzner). It turns a `Cluster` and its Machines into real Hetzner load balancers, cloud VMs, and bare-metal servers. ## Cluster and spec.topology The `Cluster` is the object you edit. Everything you configure lives under `spec.topology`. | Field | What it sets | | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `spec.topology.classRef` | The `ClusterClass` this cluster is built from, by name. Leaving it empty is rejected by the API with `classRef.name: Required value: cannot be empty`. | | `spec.topology.version` | The Kubernetes version. Changing it rolls the control plane and then the workers. | | `spec.topology.variables` | The cluster variables. The `ClusterClass` turns each one into a patch on the generated infrastructure and bootstrap objects. See [Cluster variables](/docs/hetzner/apalla/reference/cluster-variables). | | `spec.topology.workers.machineDeployments` | The worker pools. Each entry becomes one `MachineDeployment`. | | `spec.topology.controlPlane` | The control-plane settings, including its rollout controls. | ## ClusterClass and the shipped template The `ClusterClass` is authored by the cluster stack, not by you. It holds the templates and the per-cluster `jsonPatch` expressions that wire your variables onto the generated objects. The Cluster Stack Operator (CSO) reconciles a `ClusterStackRelease` into the `ClusterClass`, so its name is the release name. You reference it from `spec.topology.classRef`; you do not edit it. Because the class is shared by every cluster built from that release, do not patch it in place. Change behavior through `spec.topology.variables` on your `Cluster` instead. ## MachineDeployment, MachineSet, and Machine These three are derived, not authored. The topology controller creates one `MachineDeployment` per worker pool, each `MachineDeployment` owns a `MachineSet`, and each `MachineSet` owns `Machine` objects. One `Machine` is one node. Each `Machine` carries a `KubeadmConfig` (CABPK renders the bootstrap Secret) and an infrastructure machine (`HCloudMachine` or `HetznerBareMetalMachine`, provisioned by CAPH). The control plane follows the same pattern under a different owner: the `KubeadmControlPlane` owns the control-plane `Machine` objects directly. ## What the topology controller owns Do not edit the derived objects directly. The topology controller re-expands the `Cluster` against its `ClusterClass` on every reconcile and recomputes the machine specs. It evaluates the class `jsonPatch` expressions each time the `Cluster` is reconciled, so a `MachineDeployment`, `MachineSet`, `KubeadmControlPlane`, or generated template you edit by hand is recomputed from the class and your edit is dropped. To change a derived object, change the source it is derived from: `spec.topology.variables` for configuration, `spec.topology.version` for the Kubernetes version, or `spec.topology.classRef` for a new cluster-stack release. ## Scaling Scale by changing the replica count on the `Cluster`, not on a derived object. A worker pool scales through its entry under `spec.topology.workers.machineDeployments`; the control plane scales through `spec.topology.controlPlane`. The topology controller owns the resulting `MachineDeployment` and `KubeadmControlPlane`, so setting a count directly on those objects is reverted on the next reconcile. ## Reading status and conditions Bring-up progresses through conditions on the `Machine`, in order. Read these to see where a node is. | Condition or status field | Meaning | | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `Machine` `BootstrapConfigReady` | CABPK wrote the bootstrap Secret. Gates infrastructure provisioning. | | `Machine` `InfrastructureReady` | CAPH reports the server installed and booted. Gates the node join. | | `Machine.status.nodeRef` | The node registered in the workload cluster. On the first control-plane Machine this flips `KubeadmControlPlane` `Initialized`. | | `KubeadmControlPlane` `Initialized` | The first control plane is up; the cluster components begin to be applied. | | `KubeadmControlPlane` `Available` | The control plane can serve: etcd has quorum and at least one control-plane Machine is healthy. | ## Relationship to the provider objects The `Cluster` and its Machines are backend-agnostic. The Hetzner-specific detail lives on the provider objects that CAPH reconciles: `HetznerCluster` (load balancer, endpoint, region), and per Machine, `HCloudMachine` or `HetznerBareMetalMachine`. CAPH provisions the actual server, and once the CCM initializes the node, `spec.providerID` on the `Node` carries the Hetzner server's numeric ID. ## Related - [Cluster variables](/docs/hetzner/apalla/reference/cluster-variables): every variable you set under `spec.topology.variables`. - [Declarative cluster management](/docs/hetzner/apalla/concepts/foundations/declarative-cluster-management): how a variable becomes a node file or an API server flag. - [Managed Kubernetes](/docs/hetzner/apalla/concepts/overview)