Documentation is tailored to each Cluster Stack release. Pick the one your cluster runs. {#if release.hasArmImages && minor !== stack.latest.minor} ## Check for ARM-based nodes If your cluster isn't running ARM-based nodes, skip this step. Starting from `hetzner-apalla-1-33-v11`, `hetzner-apalla-1-34-v8`, and `hetzner-apalla-1-35-v3`, ARM is temporarily not supported. If your cluster has any, the upgrade will fail unless you migrate them to x86 nodes first — see [Migrate ARM servers to x86 in your cluster](/docs/hetzner/apalla/servers-and-nodes/provision/migrate-arm-to-x86) for instructions. {/if} {#if release === stack.latest} ## You are up to date! 🎉 If you need to upgrade from an old Kubernetes version, select it in the picker at the top of this page. {:else if minor === stack.latest.minor} ## You are on the latest Kubernetes version! 🎉 Right now you are on the latest Kubernetes version available in the Cluster Stacks. If you need to upgrade from an old Kubernetes version, select it in the picker at the top of this page. If you want to upgrade the Cluster Stack version instead, go to the [Updating the cluster with same Kubernetes version](/docs/hetzner/apalla/clusters/upgrades/update-within-a-version) guide. {:else if upgrade.toNextMinor.length === 0 || upgrade.toNextMinor[0] !== upgrade.nextMinorEntry} You are viewing documentation for Kubernetes 1.33, Cluster Stack release hetzner-apalla-1-33-v13. To upgrade to Kubernetes 1.34, first update your cluster to Cluster Stack release hetzner-apalla-1-33-v13 by following this guide: [Updating the cluster with same Kubernetes version](/docs/hetzner/apalla/clusters/upgrades/update-within-a-version). Once that update is complete, return to this guide to upgrade your Kubernetes version. Not sure which Kubernetes minor and Cluster Stack release your cluster uses? [Check the Kubernetes version and Cluster Stack](/docs/hetzner/apalla/clusters/configure/how-to-check-the-kubernetes-version-and-stack) of your cluster. {:else} This guide will detail the process of upgrading your cluster from Kubernetes 1.33 to 1.34. Not sure which Kubernetes minor and Cluster Stack release your cluster uses? [Check the Kubernetes version and Cluster Stack](/docs/hetzner/apalla/clusters/configure/how-to-check-the-kubernetes-version-and-stack) of your cluster. {#if nextMinor?.version === "1.36"} ## Before you upgrade to 1.36 Upgrading to 1.36 moves your nodes to a new operating system, Syself Linux, and makes a few defaults stricter. As in any upgrade, every node is replaced, and your workloads keep running through it. Most of them need no changes. The ones that might are below, with what to check for each. For everything else that changed in 1.36, see [What's New in Syself Autopilot 1.36](/resources/whats-new-syself-autopilot-1-36). - **If you run something on the node itself.** Syself Linux is immutable and minimal: no package manager, and nothing on it a Kubernetes node doesn't need. Anything that writes to the host, installs packages, or loads kernel modules worked on the old general-purpose Linux, but won't on this one. This is mostly monitoring agents, security agents, and storage helpers that run as a DaemonSet. Check that each one works on a read-only host, and test it in a non-production cluster first. - **AppArmor.** Every non-privileged container now runs under an enforcing AppArmor profile, with nothing to set up. It leaves normal workloads alone and blocks what a container rarely does: writing to host paths, opening raw sockets, tracing other processes. A workload that needs one of those keeps working once it declares it in `securityContext`. Privileged pods run unconfined, so keep those rare. See [Use AppArmor](/docs/hetzner/apalla/security/use-apparmor) for how to allow what a workload needs. - **Admission webhooks.** A validating or mutating webhook can no longer point at the authentication, authorization, or admission APIs. That was a way to lock admins out or build a webhook loop, so 1.36 rejects any webhook scoped that wide. If you run your own, scope each one to the resources it inspects. Syself's own admission policies protect themselves, so nothing removes them by accident. - **Host-network metrics.** Every component on the host network now serves its metrics on `127.0.0.1`, so nothing is exposed on a node's public IP. A Prometheus or agent that scrapes control-plane or other host-network metrics from outside the node stops getting them. Move that scraping onto the node, to a collector on the host network. See [Control-plane metrics](/docs/hetzner/apalla/observability/metrics/control-plane-metrics) for the supported way to collect them. - **Network policies.** Cilium moves to 1.20, and policies that need its userspace proxy (HTTP rules, DNS rules, and `toFQDNs`) are now [rejected when you apply them](/docs/hetzner/apalla/security/segment-with-network-policies), with a clear error instead of quietly breaking connectivity for other workloads on the node. Plain address, port, and identity rules work as before. If any of your policies use the proxy features, rewrite them before you upgrade. {/if} ## Upgrading the cluster Adding a new Cluster Stack Add a new `ClusterStack` and `HetznerClusterStackReleaseTemplate` for the newer Kubernetes minor version: {#if upgrade.nextMinorEntry === nextMinor?.latest} > [!NOTE] > The cluster manifest below uses `cluster.x-k8s.io/v1beta2`, the current default API version for CAPI core resources. See [Cluster API v1beta2](/docs/hetzner/apalla/clusters/upgrades/migrate-a-manifest-to-v1beta2) for more information. ```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: true versions: [] 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} ```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 ``` Apply it to the cluster with your tool of choice. > [!TIP] > For versions before hetzner-apalla-1-35-v1, node images for the new version will start to build. The build process takes around 5 minutes. You can check the status of the newly created Cluster Stack object if something seems wrong. Checking the available ClusterStackReleases The next step is to is to check the available `ClusterStackReleases`: {#if upgrade.nextMinorEntry === nextMinor?.latest} ```console vars $ kubectl get clusterstackrelease NAME K8S VERSION READY AGE REASON MESSAGE hetzner-apalla-1-33-v13 v1.33.13 true 2d hetzner-apalla-1-34-v10 v1.34.10 true 1m ``` {:else} ```console vars $ kubectl get clusterstackrelease NAME K8S VERSION READY AGE REASON MESSAGE hetzner-apalla-1-33-v13 v1.33.13 true 2d ... ... true 1m hetzner-apalla-1-34-v10 v1.34.10 true 1m ``` {/if} Note down the values of the `NAME` and `K8S VERSION` columns from the release you want to upgrade to. Now we edit our cluster and change the `spec.topology.class` and `spec.topology.version` to match the `NAME` and `K8S VERSION` of our cluster stack release: {#if upgrade.nextMinorEntry === nextMinor?.latest} ```yaml vars persistBlur title="cluster.yaml" apiVersion: cluster.x-k8s.io/v1beta2 kind: Cluster metadata: name: mycluster spec: topology: classRef: name: hetzner-apalla-1-34-v10 version: v1.34.10 controlPlane: 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 ``` {:else} {/if} This can be achieved either by editing the resource inside the management cluster, or by updating it in your GitOps repository. Syself now rolls the cluster to the new Kubernetes minor version, one node at a time. The control plane and the API server stay available throughout. Bare-metal control-plane and worker pools run one fewer node during each step, so size them with headroom; the [prechecks](/docs/hetzner/apalla/clusters/upgrades/plan-maintenance-and-prechecks) cover this. When the roll finishes, confirm every node reports the new version and `Ready`, the control plane and etcd are healthy, and your workloads still serve traffic. If a rollout stalls, see [Stuck or failed upgrade](/docs/hetzner/apalla/clusters/troubleshooting/stuck-or-failed-upgrade). If you are no longer using the old `ClusterStack` and `HetznerClusterStackReleaseTemplate` anymore, you can remove them now. {/if}