## Step 1: Applying the Cluster Stack A [Cluster Stack](/docs/hetzner/apalla/concepts/foundations/cluster-stacks) defines a complete, opinionated set of Kubernetes resources including cluster templates, node image configurations, and add-on manifests which are needed to create a production-ready cluster. For each release, these resources and configurations are heavily tested by Syself to guarantee integrity and interoperability. The first step for cluster creation is making a Cluster Stack Release available. Create a file named `clusterstack.yaml`, with the following content: {#if release === minor.latest} ```yaml vars title="clusterstack.yaml" apiVersion: clusterstack.x-k8s.io/v1alpha1 kind: ClusterStack metadata: name: hetzner-apalla-1-34 spec: provider: hetzner name: apalla kubernetesVersion: "1.34" channel: stable autoSubscribe: true providerRef: name: hetzner-apalla-1-34 kind: HetznerClusterStackReleaseTemplate apiVersion: infrastructure.clusterstack.x-k8s.io/v1alpha1 --- apiVersion: infrastructure.clusterstack.x-k8s.io/v1alpha1 kind: HetznerClusterStackReleaseTemplate metadata: name: hetzner-apalla-1-34 spec: template: spec: nodeImages: - controlplaneamd64hcloud - workeramd64hcloud ``` {:else} ```yaml vars title="clusterstack.yaml" apiVersion: clusterstack.x-k8s.io/v1alpha1 kind: ClusterStack metadata: name: hetzner-apalla-1-34 spec: provider: hetzner name: apalla kubernetesVersion: "1.34" channel: stable autoSubscribe: false versions: - v10 providerRef: name: hetzner-apalla-1-34 kind: HetznerClusterStackReleaseTemplate apiVersion: infrastructure.clusterstack.x-k8s.io/v1alpha1 --- apiVersion: infrastructure.clusterstack.x-k8s.io/v1alpha1 kind: HetznerClusterStackReleaseTemplate metadata: name: hetzner-apalla-1-34 spec: template: spec: nodeImages: - controlplaneamd64hcloud - workeramd64hcloud ``` {/if} And apply it to the management cluster: ```console $ kubectl apply -f clusterstack.yaml clusterstack.clusterstack.x-k8s.io/clusterstack created hetznerclusterstackreleasetemplate.infrastructure.clusterstack.x-k8s.io/clusterstack created ``` When a Cluster Stack is applied, a ClusterStackRelease is created from it, and the necessary components starts to be prepared in your Hetzner account. In our case, we applied a Cluster Stack with `autoSubscribe` set to true, so it'll fetch the latest release and create the ClusterStackRelease object based on that. You don't need to interact directly with the release. It takes around 5 minutes for the ClusterStackRelease to be ready, as the node images are being built. You can check the status of these node images by running `kubectl get HetznerNodeImageReleases`. These objects have a one-to-one relationship with the snapshots in your Hetzner project, which you can view under Servers / Snapshots in the Hetzner Console. > [!NOTE] > If you already have a Cluster Stack applied from a previous cluster, there is no need to apply it again since the HetznerNodeImageReleases and ClusterStackRelease are already there. You can use the same release and node images for any number of clusters. After the node images are successfully built, the ClusterStackRelease hetzner-apalla-1-34-v10 will be ready for you to use in your cluster. Check with: ```console vars $ kubectl get clusterstackrelease NAME K8S VERSION READY AGE REASON MESSAGE hetzner-apalla-1-34-v10 v1.34.10 true 1m ``` ## Step 2: Creating your cluster > [!TIP] > If you need your clusters to be SCS-compatible, you can refer to the [Creating SCS compatible clusters](/docs/hetzner/apalla/clusters/configure/scs-compatible-cluster) page. > > The [SCS (Sovereign Cloud Stack)](https://sovereigncloudstack.org/en/) is a European initiative for an open, transparent and vendor-neutral cloud ecosystem that guarantees sovereignty. Now that we have a ClusterStackRelease ready, we can create a cluster from it. For that, create a `cluster.yaml` file with the contents below: ```yaml vars title="cluster.yaml" apiVersion: cluster.x-k8s.io/v1beta2 kind: Cluster metadata: name: mycluster spec: clusterNetwork: services: cidrBlocks: ["10.128.0.0/12"] pods: cidrBlocks: ["192.168.0.0/16"] serviceDomain: "cluster.local" topology: classRef: name: hetzner-apalla-1-34-v10 version: v1.34.10 controlPlane: class: hcloud replicas: 3 workers: machineDeployments: - class: workeramd64hcloud name: md-0 replicas: 1 failureDomain: nbg1 variables: overrides: - name: workerMachineTypeHcloud value: cpx42 variables: - name: region value: nbg1 - name: controlPlaneMachineTypeHcloud value: cpx42 ``` And apply it to the management cluster with: ```console $ kubectl apply -f cluster.yaml cluster.cluster.x-k8s.io/mycluster created ``` Cluster creation will take a few more minutes. You can monitor the process by looking at the machine objects: ```console vars $ kubectl get machines NAME CLUSTER NODENAME PROVIDERID PHASE AGE VERSION mycluster-jndgf-r4k7v mycluster mycluster-hb2wb-pb6d4 hcloud://12345678 Running 10m v1.34.10 mycluster-jndgf-sb6b8 mycluster mycluster-hb2wb-2g9wq hcloud://87654321 Running 8m v1.34.10 mycluster-jndgf-vhbsb mycluster mycluster-hb2wb-bnkjh hcloud://12348765 Running 5m v1.34.10 mycluster-md-0-zw8ln-pxztl-j4stb mycluster mycluster-md-0-bp4v2-7r2sv hcloud://43215678 Running 4m v1.34.10 ``` These represent actual machines in your Hetzner project. If all of them are in the `Running` phase, it means your cluster is ready! > [!NOTE] > If a control plane node replacement or rolling update is stuck provisioning, this is most likely a regional HCloud capacity issue and the operation will remain blocked until capacity returns. > > Baremetal control planes are not subject to this, as updates and recovery operate on existing inventory. See > [Baremetal Control Planes](/docs/hetzner/apalla/clusters/configure/fully-bare-metal-cluster) > for setup instructions. ## Step 3: Accessing your cluster To get the kubeconfig of your workload cluster, you can use the command: ```console $ kubectl get secrets mycluster-kubeconfig -o=jsonpath='{.data.value}' \ | base64 -d \ > mycluster-kubeconfig.yaml ``` Now, you can change the `KUBECONFIG` environment variable to point to your new cluster: ```console $ export KUBECONFIG=mycluster-kubeconfig.yaml ``` If you want more information about workload and management clusters, check the [Management and Workload Clusters](/docs/hetzner/apalla/concepts/foundations/management-and-workload-clusters) section. When accessing your cluster, you may see some pods still pending. This is normal, you just have to wait for it to be completely initialized. When all pods are running and the four nodes are in ready state, it means your cluster is completely provisioned. Your cluster is up, managed by Syself Autopilot. Because everything is defined as Kubernetes manifests, you can keep the whole cluster configuration in Git and manage it with GitOps. ## Optional: Run sample workload Deploy the sample pod to your cluster: ```console $ cat < 80 Forwarding from [::1]:8080 -> 80 Handling connection for 8080 ``` Now, go to [http://localhost:8080](http://localhost:8080) in your browser. ### Further Reading In the [Cluster management](/docs/hetzner/apalla/clusters/configure/high-availability-control-plane) section you can find tutorials for common tasks you might want to do in your cluster. We recommend you go over it after creating your first cluster. For a list of all servers supported by Syself Autopilot and recommendations, you can refer to the [Adding HCloud Servers](/docs/hetzner/apalla/servers-and-nodes/provision/add-cloud-servers) page.