Syself tests every Cluster Stack release before you can use it. A release ships only when everything passes. We check that a cluster built from a release comes up and runs, that it recovers when parts of it break, and that every upgrade path between our own versions works. The heavy checks run on real clusters of different shapes, not on mocks or on reading the code.
A release is one fixed set of parts: the node operating system, the shape of the cluster, and hundreds of components that all have to agree with each other. The kernel, the container runtime, the kubelet, the network layer, the storage driver, the cloud integration, and more. Each one has its own version and its own rules about what it works with.
Change one part and it can break another several layers down. A network module built for one kernel version may not load on another. A container runtime the kubelet ran yesterday can be rejected by a newer kubelet tomorrow. These problems only surface when the parts run together on a real machine, and every cluster combines them a bit differently, so there are many combinations to work through. You prove them by building the combinations and running them, not by reading the code or trying a handful by hand.
Before we release, we run the whole thing through several levels of testing, from quick file checks to full clusters under load. Each level catches a different kind of mistake.
The real-cluster level isn't one test but several kinds, each aimed at a different question:
More than three hundred of these run on real clusters. Many more run without one, because those checks are cheap and quick. Building a Cluster Stack carries the weight of building anything people trust their lives to: every part has to be correct, and it has to be tested to prove it. So most of our engineering goes into the tests, not the product they guard, and much of that work covers the edge cases, the rare states that only surface when something breaks. When we hit a problem, we fix it for everyone and add a test that keeps it fixed.
A check only means something on a cluster that has the feature it checks: a GPU test needs a GPU node, an encryption test needs encryption turned on. So the release picks the cluster shape each check needs, and a check with no cluster to run on is marked not covered, never counted as a pass. A skipped check showing up green would hide the gap it was meant to find, so we check for that too.
Both. A cluster behaving when nothing goes wrong is the easy case. The harder one is a cluster that keeps running when a node fails under real traffic, recovering on its own with no one stepping in.
So we break clusters on purpose. Our test scenarios drive a cluster through real events and watch how it reacts. One scenario kills a worker's kubelet and checks that the node heals itself, through one of three layers: the service restarts, the node reboots, or the platform replaces the machine. Exactly one of those has to fire, and a node that never recovers fails the test. Another scenario takes the control-plane load balancer out from under the workers and checks that they keep talking to the control plane anyway. We also remove nodes, cut the network, and drive upgrades while a workload is running, and check that the cluster does the right thing each time.
The full walkthrough of one of these paths is in control-plane failover.
Upgrades are the hardest part. An update and an upgrade are not the same thing:
1-36 release. You get patches, CVE fixes, and OS and addon revisions. The Kubernetes API and the way the cluster behaves do not change.1-36 to 1-37. This is where new features arrive, behaviour can change, and deprecated APIs can be removed.Moving a live cluster in either direction is not one step. It has to happen in the right order, run its migrations, and keep the API server reachable the whole time. A cluster that goes down during its own upgrade is a failed upgrade, even if it comes back afterward.
You can't jump straight into a new minor from an old release. The path is to first catch up to the latest available release within your current track, then move to the latest available release of the next minor. That is exactly what we test: the upgrade from the latest release of the previous track into the new track. Which releases are available in each track, and how the tracks move forward, is on the Version Hub.
| You are moving | Tested? |
|---|---|
| To a newer release within your current track (an update) | Yes |
| From the latest release of your track to the next minor (an upgrade) | Yes, that is the tested path |
| From an old release straight into a new minor, without catching up first | No — catch up within your track first |
To reach the next minor, first update to the latest release in your current track, then upgrade to the latest release of the next minor. Each of those steps is a path we ran on real clusters. There is no supported way to skip a minor.
Networking is the part that is easy to get wrong and hard to keep right, so it takes the largest share of the real-cluster testing.
It is not just the network layer's own settings. It is how Kubernetes networking, the kernel modules, and the operating system fit together, and whether they keep matching under load. Those pieces move at different speeds, and a change in one can quietly break another. So a lot of a real-cluster test is spent proving they still line up: a pod gets an address, a Service routes to the right backend, the load balancer serves traffic and keeps the real client IP, and traffic that should be blocked from the outside is blocked.
After a release passes, it's locked with a content hash. A cluster can only point at a name, and a name exists only after the tests for it pass, so a cluster can never run an untested combination. It's the same idea as an immutable node OS: the thing you run is fixed and identified, not assembled fresh each time.
Security rides along in the same process. Syself tracks CVEs and ships a vulnerability advisory with each release, in both OpenVEX and CSAF 2.0 formats, so a release is checked against known problems, not just built and shipped. Each release produces an SBOM with a verdict per CVE, a stack security report, and a recurring CVE feed with a patch deadline for each severity. The evidence is generated per release and published, so you can check it directly. Security evidence per release has the detail.
The tests prove our stack. The operating system, the cluster shape, the components, and the upgrade path between our own parts. They do not prove that your workload is ready for its nodes to come and go.
In a Syself Autopilot cluster, nodes are replaced, not patched. That happens on an upgrade, but it also happens when a node fails and self-healing replaces it, and when a machine simply dies. In all three cases the effect on your workload is the same: a node it was running on goes away, its pods are drained, and they have to start again elsewhere. A workload that handles that loses nothing. A workload that does not will drop requests, whether the node left for an upgrade, a repair, or a crash.
So an upgrade does not create the problem. It surfaces one that was already there. If you fix it, you are covered for repairs and outages too. A few habits make a workload ready for a node to disappear:
Prepare workloads for upgrades walks through all of this in one place.
One thing applies only to an upgrade, that is, a move to a new Kubernetes minor, say 1-35 to 1-36. A new minor can remove a Kubernetes API your manifests still use. The stack upgrade succeeds, but your deployment breaks because the API it called is gone. An update within a track never does this: on the same minor, Kubernetes behaviour does not change and no API is removed, so your manifests keep working. No release test catches the cross-minor case either, because no release test reads your manifests. So before an upgrade to a new minor, run pluto and kubent against your own manifests to find those APIs. It takes a few minutes.
Both, and at different levels. We check code and configuration on their own first, where the parts have clear inputs and interfaces, so we can run a very large number of these cheaply. We boot the node image in a virtual machine and feed it different inputs to see how it behaves. And we run more than three hundred tests on real clusters with a real topology, with workloads running inside them, to see how the whole thing acts under load. A passing simulation is a good early signal. It is not proof a cluster works.
For an update within your track, every release is tested against the move from the one immediately before it, so going forward inside a track is a tested path. For an upgrade to a new minor, we test the move from the latest release of the previous track into the new track — so catch up to the latest release in your current track first, then upgrade. Done in that order, each step is a path we ran on real clusters. There is no supported way to skip a minor.
No. The tests prove our stack and the upgrade path between our own parts. Getting your workload ready for a node to come and go is your side of it. Run enough replicas, set a PodDisruptionBudget, shut down gracefully, and scan with pluto and kubent before an upgrade to a new minor.
The rule of thumb: trust the stack, get your workloads ready for a node to disappear, and to reach a new minor, catch up within your track first, then upgrade one minor at a time.
Start with a 14-day free trial, and our step-by-step guides will walk you through your first cluster deployment in minutes.
Tags
In Syself Autopilot 1.36, a node-local proxy handles control-plane failover on every worker, so a load-balancer outage no longer marks the whole fleet NotReady.
Syself Autopilot 1.36 ships its own reverse tunnel so kubectl logs, exec, and pod metrics work—each node dials out, and the control plane never dials in.
KubeGate is Syself Autopilot 1.36's single front door to the Kubernetes API server—it controls who reaches the control plane and preserves the real client IP.