Skip to content
Beta

Kubernetes upgrades

An upgrade moves a cluster to a newer Kubernetes version in place: its nodes keep their names, addresses and volumes. The platform takes a snapshot of the cluster's state first, then upgrades the control plane, then the workers, one node at a time. The cluster's system add-ons move with Kubernetes in the same upgrade, tested together: cluster DNS, the Service proxy, pod networking and network policy, the network plugins, the link to the control plane, the metrics API, the node load balancer and the pod sandbox image.

You decide when to upgrade: now, or at a time you schedule. When we offer a version to the cluster, you have a grace period to do it in, after which we upgrade the cluster during its maintenance window.

Versions a cluster can move to

  • The newest patch of its minor, such as from 1.36.4 to 1.36.5, marked Patch. A patch brings bug and security fixes to the same minor.
  • The next minor, such as from 1.36 to 1.37, marked Minor version. A minor brings new features and can remove APIs that were deprecated, so check what your manifests, charts and tools use before you take it.

Upgrades go one minor at a time and never down: to go from 1.36 to 1.38, upgrade to 1.37 first. Only versions we have tested and approved are offered. The cluster's page shows the exact version it runs, such as Kubernetes 1.36.4.

After a minor upgrade, use a kubectl within one minor of the cluster, such as kubectl 1.36 to 1.38 for 1.37: older clients may not work with it.

Upgrade now or schedule

On the cluster's Overview, the Upgrade available card lists each version the cluster can move to, with What happens during the upgrade and What changes: the Kubernetes version and each add-on, from and to, with a link to the release notes. For the version you want, choose:

  • Upgrade now to start at once.
  • Schedule to pick a date and time, in your own time zone, up to 30 days ahead. For a version we offered, it must also be before the end of its grace period.

Before an upgrade starts, its confirmation also says what the cluster's Insights found that blocks it or that it would disrupt. A minor waits for each finding that blocks it until you fix it or accept it, with a reason, in the cluster's Insights.

Upgrades you start or schedule yourself run at the time you choose, inside or outside the maintenance window. You can start one while the cluster is Ready, and a cluster has one upgrade open at a time, an offer included: while we offer a version, upgrade to that one first.

An upgrade begins once the cluster is settled: every node ready, and no node pool change, state backup or restore under way. If the cluster is still busy 30 minutes after the upgrade's time, the upgrade does not start, and the console says so.

Owners, admins and developers can upgrade a cluster, schedule or cancel an upgrade and set the maintenance window. Viewers can see them.

Offers and the grace period

We offer a new version to the clusters it upgrades. Each offered cluster gets a grace period:

What is offeredGrace period
A patch14 days
A security patch, marked Security update7 days
The next minor, once the cluster's minor has reached its end of support30 days
The next minor, before thenNo offer: moving to it is your choice
  • Until the grace period ends, choose Upgrade now, or Schedule a time before its end.
  • Once it has ended, the cluster is due, and we upgrade it during its maintenance window. Until we do, you can still choose Upgrade now.
  • The end of the grace period cannot be moved later from the console. If you need more time, contact support: they can extend it.
  • No cluster is upgraded on a timer: after a grace period, our team starts the upgrades, and each one begins in its cluster's maintenance window. Only an emergency, such as a security fix that cannot wait, makes us upgrade a cluster before its grace period ends or outside its window.

Each minor's end of support is in the Kubernetes reference, and the workspace's owners and admins are emailed 30 days and 7 days before it.

The maintenance window

The maintenance window is when we may upgrade the cluster once a grace period is over. By default it is Tuesday, Wednesday and Thursday from 23:00 UTC, for 4 hours: 02:00 to 06:00 in Amman.

To change it, open the cluster's Settings and go to Maintenance window:

DefaultTuesday, Wednesday and Thursday from 23:00 UTC, for 4 hours
WeeknightsSunday to Thursday from 22:00, for 4 hours
WeekendsFriday and Saturday from 22:00, for 4 hours
CustomThe days, a start time on the hour or the half hour, and a length of 2 to 8 hours

Apart from Default, the days and the start time are in a time zone, yours to begin with; pick another under Time zone. With daylight saving time the start follows the local clock, and the window is never shortened. The card shows when the window opens next, in your time zone and in the window's. Choose Save window to keep it.

  • Upgrades we start begin only inside the window, and their control plane starts moving only while at least an hour of it is left. A worker being upgraded when the window closes finishes; the next one waits for the next window.
  • Upgrades you start or schedule yourself ignore it.

What happens during an upgrade

  1. Preparing. Every node downloads the new version and verifies it, and workers load the add-ons' new images. Nothing restarts yet.
  2. Snapshot. The platform takes a snapshot of the cluster's state, like the hourly state backups. The control plane starts within 15 minutes of it, or another one is taken.
  3. Control plane. Its nodes are upgraded one at a time. Without high availability, the cluster's API pauses for about a minute while the control plane restarts; your workloads keep running. With high availability, the API keeps answering. The add-ons then move to their new versions, and the workers wait until they all run and are ready.
  4. Workers, pool by pool, one at a time. Each one is checked before the next starts: its system pods must be ready on their new versions.
    • A patch upgrades each worker in place, without draining it, so its pods keep running.
    • A minor first drains a worker when its node pool has another ready worker to take the pods, then upgrades it. The drain respects your pod disruption budgets and never forces a pod out: when a budget does not let one go, it waits and shows which pods hold it. A worker alone in its pool, such as the only worker of a cluster, is upgraded in place with its pods running.
  5. Done. Every node runs the new version, and the add-ons have moved with it. Workers added later, or that replace a failed one, join on the new version.

A node that does not come back healthy on the new version goes back to the version it ran, and the upgrade stops there; the console says what happened. Our team is alerted, and can take the upgrade on from that node or move the upgraded nodes back. If an upgrade stops before its control plane moves, nothing on the cluster has changed.

While an upgrade runs

  • Your workloads keep running: a patch moves no pods, and a minor moves them one worker at a time.
  • A worker that stops working is not replaced until the upgrade is over.
  • Change node pools before or after an upgrade, not while it runs.
  • No other upgrade can start until this one ends.

Pod disruption budgets

A minor upgrade drains workers by evicting their pods, each with its full termination grace period, so a PodDisruptionBudget decides how many pods of a workload may be away at once. Run at least two replicas of anything that must stay up, and give it a budget that lets one go at a time:

yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app: web
bash
kubectl apply -f web-pdb.yaml
kubectl get pdb web

ALLOWED DISRUPTIONS shows how many of its pods may go now. A budget that allows none, such as maxUnavailable: 0 or a minAvailable as high as the replicas, holds the drain: the worker stays on Moving pods and lists the pods it waits for. Add a replica or relax the budget, and the drain goes on by itself.

  • A pod that no controller manages, such as one started with kubectl run, holds the drain too, since nothing would start it again elsewhere: delete it, or run it from a Deployment.
  • A workload with a single replica is down while its pod starts again on another worker.
  • A pod's emptyDir data does not move with it: it is deleted when the pod leaves the worker.

Removing workers or deleting a node pool gives your budgets up to 15 minutes; an upgrade waits on them instead.

Cancel or roll back

  • Cancel upgrade stops an upgrade you started or scheduled, until its control plane starts moving: nothing on the cluster has changed by then. One you started from an offer goes back to being that offer, with the same end to its grace period.
  • An upgrade our team started, such as one after a grace period, cannot be cancelled from the console: contact support.
  • A patch can be rolled back by support within 72 hours of the upgrade completing, the same in-place way. The Upgrade history shows until when.
  • A minor cannot be rolled back. If something breaks after one, contact support: they can put the cluster's state back from the snapshot taken before the upgrade, which loses every change made through the cluster's API since. See State backups.

Follow an upgrade

  • Overview: while a version is offered, a banner names it, such as Kubernetes 1.36.5 is available, with the date to upgrade by: Upgrade any time before October 30, 2026. After that, we will upgrade this cluster during its maintenance window. It counts down the days and hours left, and carries a Security update tag for a security release. Once the upgrade is scheduled, it gives the time and counts down to it.
  • Upgrading to Kubernetes 1.36.5: while an upgrade runs, the same card shows its steps: preparing the new version on every node, the snapshot, the control plane as one step, and each worker with its state.
  • Upgrade history: every upgrade, newest first, with its versions and what changed, its kind, its result, who started it (your workspace, support or the platform) and when.
  • Kubernetes: the list of clusters marks each one with an upgrade available, scheduled or running, and Upgrades there lists every cluster of the workspace with its version, the upgrade offered, the date to choose by and its maintenance window, with Upgrade now and Schedule.
Worker stateMeans
WaitingNothing has changed on it yet
PreparingIt is receiving the new version
ReadyIt has the new version and waits for its turn
Moving podsIt is being drained, in a minor upgrade; when a budget holds the drain, the pods it waits for are listed, with since when
UpgradingIt is restarting on the new version
CheckingIt runs the new version, and its system pods are checked before the next worker starts
DoneIt runs the new version
FailedIt could not be upgraded
Rolled backIt went back to the version it ran

The workspace's owners and admins are emailed when a version is offered to the cluster, when an upgrade is scheduled, when it starts, and when it completes, fails or is rolled back.

From the API and MCP

GET /v1/kubernetes/clusters/{id}/upgrades returns the exact version the cluster runs, its availableUpgrades, the maintenanceWindow in use, the active upgrade or offer, with each worker's state and what changes, and the last 50 in history. It needs kubernetes:read. To upgrade, POST the version to the same path, with scheduledFor, a time with its offset, to schedule it; leave scheduledFor out to start now. This needs kubernetes:update:

bash
curl -X POST "https://api.sahabti.com/v1/kubernetes/clusters/$CLUSTER_ID/upgrades" \
  -H "x-api-key: $SAHABTI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"version":"1.36.5","scheduledFor":"2026-10-20T23:00:00Z"}'

For an upgrade that is waiting, an offer or one you scheduled, PUT /v1/kubernetes/clusters/{id}/upgrades/{upgradeId}/schedule with scheduledFor sets or moves its time, DELETE on the same path clears it (an offer goes back to waiting with the same end to its grace period; your own scheduled upgrade is cancelled), and POST /v1/kubernetes/clusters/{id}/upgrades/{upgradeId}/start-now starts it now. None of them works on an upgrade our team or a fleet run scheduled. POST /v1/kubernetes/clusters/{id}/upgrades/{upgradeId}/cancel cancels one. A version the cluster cannot move to gets 400 K8S_UPGRADE_VERSION_INVALID, a time in the past, more than 30 days ahead or after the grace period 400 K8S_UPGRADE_SCHEDULE_INVALID, another open upgrade or offer 409 K8S_UPGRADE_IN_PROGRESS, a minor that Insights findings still block 409 K8S_UPGRADE_BLOCKED, a cluster that is not ready 409 K8S_CLUSTER_BUSY, and a cancel once the control plane is moving 409 K8S_UPGRADE_NOT_CANCELLABLE. Upgrade requests are limited to 10 a minute per cluster.

PATCH /v1/kubernetes/clusters/{id}/settings sets the window as maintenanceWindow, with days from mon to sun, a start time, a length in durationHours from 2 to 8 and a timeZone; null goes back to the default:

json
{
  "maintenanceWindow": {
    "days": ["fri", "sat"],
    "start": "02:00",
    "durationHours": 4,
    "timeZone": "Asia/Amman"
  }
}

The cluster itself, from GET /v1/kubernetes/clusters/{id}, has kubernetesVersion, the exact version (version stays the minor), availableUpgrades, upgrade, the upgrade or offer open on it, and nextMaintenanceWindow, its window open now or next, in UTC.

In MCP, list_kubernetes_cluster_upgrades reads the same as the GET, start_kubernetes_cluster_upgrade starts or schedules an upgrade, schedule_kubernetes_cluster_upgrade and start_kubernetes_cluster_upgrade_now move or start a waiting one; they need kubernetes:update and ask you to confirm first when your client supports it, and update_kubernetes_cluster_settings sets the window. get_kubernetes_cluster returns version, kubernetesVersion, availableUpgrades and upgrade too.