Skip to main content

Creating the workload cluster

Generate the cluster.yaml

The clusterctl generate cluster command returns a YAML template for creating a workload cluster. It generates a YAML file named my-cluster.yaml with a predefined list of Cluster API objects (Cluster, Machines, MachineDeployments, etc.) to be deployed in the current namespace.

shell
				clusterctl generate cluster my-cluster --kubernetes-version v1.36.0 --control-plane-machine-count=3 --worker-machine-count=3  > my-cluster.yaml
			
Note

With the --target-namespace flag, you can specify a different target namespace.

Run the clusterctl generate cluster --help command for more information.

Note

Please note that ready-to-use Kubernetes configurations, production-ready node images, kubeadm configuration, cluster add-ons like CNI, and similar services need to be separately prepared or acquired to ensure a comprehensive and secure Kubernetes deployment. This is where Syself Autopilot comes into play, taking on these challenges to offer you a seamless, worry-free Kubernetes experience. Feel free to contact us via e-mail: info@syself.com⁠.

Apply the workload cluster

The following command applies the configuration of the workload cluster:

shell
				kubectl apply -f my-cluster.yaml
			

Access the workload cluster

The cluster will now start provisioning. You can check status with:

shell
				kubectl get cluster
			

You can also view the cluster and its resources at a glance by running:

shell
				clusterctl describe cluster my-cluster
			

To verify the first control plane is up, use the following command:

shell
				kubectl get kubeadmcontrolplane
			

Wait until the INITIALIZED column reports True before moving on. The READY column will stay False until we install a CNI in the next step — that is expected. If you'd like to follow the progression live, run kubectl get kubeadmcontrolplane -w.

Note

If you fetch the kubeconfig (next step) before INITIALIZED is True, kube-apiserver will not be listening yet and helm / kubectl calls will fail with Kubernetes cluster unreachable: ... EOF.

Once initialized, retrieve the kubeconfig of the workload cluster:

shell
				export CAPH_WORKER_CLUSTER_KUBECONFIG=/tmp/workload-kubeconfig
clusterctl get kubeconfig my-cluster > $CAPH_WORKER_CLUSTER_KUBECONFIG
			

A quick reachability check before installing the CNI:

shell
				KUBECONFIG=$CAPH_WORKER_CLUSTER_KUBECONFIG kubectl get --raw='/readyz'
			

You should see ok (a few component-level failures are still acceptable at this stage). If the call hangs or returns an EOF, give it another minute and retry.

Deploy the CNI solution

Cilium is used as a CNI solution in this guide. The values file lives in this repo at templates/cilium/values.yaml; we install it directly from the raw URL:

shell
				helm repo add cilium https://helm.cilium.io/
 
KUBECONFIG=$CAPH_WORKER_CLUSTER_KUBECONFIG helm upgrade --install cilium cilium/cilium \
--namespace kube-system \
-f https://raw.githubusercontent.com/syself/cluster-api-provider-hetzner/main/templates/cilium/values.yaml
			

You can, of course, also install an alternative CNI, e.g., calico.

Deploy the Cloud Controller Manager (CCM)

The CCM runs in the workload cluster and integrates Kubernetes with the Hetzner APIs. In practice, it is responsible for tasks such as setting the ProviderID on nodes and managing load balancers. You need to install a CCM in this flow so the workload cluster can properly interact with Hetzner infrastructure.

You have two options here:

  • Syself CCM: the ccm-hetzner chart maintained by Syself.
  • Hetzner CCM: the upstream hcloud-cloud-controller-manager from Hetzner Cloud.

Syself CCM

CAPH already syncs the hcloud secret you created on the previous page into the workload cluster's kube-system namespace, so the CCM only needs to be pointed at it (the chart default is hetzner, so we override secret.name):

shell
				helm repo add syself https://charts.syself.com
helm repo update syself
 
KUBECONFIG=$CAPH_WORKER_CLUSTER_KUBECONFIG helm upgrade --install ccm syself/ccm-hetzner \
  --version 2.0.6 \
  --namespace kube-system \
  --set secret.name=hcloud
			

Hetzner CCM (upstream)

The upstream hcloud-cloud-controller-manager static manifest (deploy/ccm.yaml) is hardcoded to read the token from secret hcloud with key token. Even though the management secret you created on the previous page only has the key hcloud, CAPH's compatibility shim writes the workload-cluster copy with both keys (hcloud and token) — so the upstream manifest works as-is, no patching required:

shell
				KUBECONFIG=$CAPH_WORKER_CLUSTER_KUBECONFIG kubectl apply \
  -f https://raw.githubusercontent.com/hetznercloud/hcloud-cloud-controller-manager/main/deploy/ccm.yaml
			

If you install the upstream CCM via its Helm chart instead, the defaults also point at secret hcloud / key token, so no --set overrides are needed.

For upstream CCM details and bare-metal ProviderID format, see the .

Deploy the CSI (optional)

The Hetzner CSI chart lives in the hcloud Helm repo, which we add first. The chart's default controller.hcloudToken.existingSecret already points at secret hcloud with key token, which matches what CAPH wrote into the workload cluster — so no overrides are needed beyond the storage class definition:

shell
				helm repo add hcloud https://charts.hetzner.cloud
helm repo update hcloud
 
cat << EOF > csi-values.yaml
storageClasses:
- name: hcloud-volumes
  defaultStorageClass: true
  reclaimPolicy: Retain
EOF
 
KUBECONFIG=$CAPH_WORKER_CLUSTER_KUBECONFIG helm upgrade --install csi hcloud/hcloud-csi \
--namespace kube-system -f csi-values.yaml
			

Clean up (optional)

If you want to continue with the next step and move the Cluster API components to your workload cluster (so it becomes the new management cluster), do not run the cleanup command.

If you want to stop here, delete the workload cluster and remove all of the components by using:

shell
				kubectl delete cluster my-cluster
			
Important

In order to ensure a proper clean-up of your infrastructure, you must always delete the cluster object. Deleting the entire cluster template with the kubectl delete -f my-cluster.yaml command might lead to pending resources that have to be cleaned up manually.

Delete management cluster with the following command:

shell
				kind delete cluster