Upgrading EKS from 1.31 to 1.34: what breaks at each step.
Two dates set the pace. On November 26, 2026 AWS force-upgrades every 1.31 control plane to 1.32, which is still on extended support. On December 2, 2026 1.34 itself leaves standard support and starts billing at the extended rate: $0.60 per cluster-hour instead of $0.10, about $365 more per cluster every month.
EKS upgrades the control plane one minor version at a time, so 1.31 to 1.34 is three upgrades, and each one breaks different things. For every item below: what breaks, the vendor's own words, a command to check your cluster, and the fix.
At a glance
The items that block a hop, and the ones to watch for. Details and commands are below.
| Step | Fix before you click Update | Watch for |
|---|---|---|
| 1.31 → 1.32 |
|
|
| 1.32 → 1.33 |
|
|
| 1.33 → 1.34 |
|
|
Before you start
These apply to every hop: version skew, disruption budgets, webhooks and add-on versions. Check them before the first one and again before each of the next two.
One minor version at a time: 1.31 → 1.34 is three upgrades
Because Amazon EKS runs a highly available control plane, you can update only one minor version at a time.Amazon EKS user guide, Update existing cluster to new Kubernetes version
To update the cluster, Amazon EKS requires up to five available IP addresses from the subnets that you specified when you created your cluster.Amazon EKS user guide, Update existing cluster to new Kubernetes version
If your cluster was automatically upgraded at the end of extended support, you can’t roll back to the previous version.Amazon EKS user guide, Roll back a cluster to a previous Kubernetes version
There is no direct jump. Each hop is its own control-plane update, and once one starts you can't pause or stop it. If it goes wrong, EKS lets you roll back to the previous version within 7 days. If AWS upgrades the cluster for you at the end of extended support (the November 26 hop), you can't roll it back. Rollback also reverts only the control plane: you roll back managed node groups and add-ons yourself, before it. Every hop also needs free IP addresses in the cluster subnets.
aws eks describe-cluster --name <cluster> --query cluster.version --output textaws ec2 describe-subnets --subnet-ids $(aws eks describe-cluster --name <cluster> --query 'cluster.resourcesVpcConfig.subnetIds' --output text) --query 'Subnets[].[SubnetId,AvailableIpAddressCount]' --output text- Plan three change windows, not one. Each hop is: control plane, then nodes, then add-ons, then clients.
- Start the first hop well before November 26, or AWS starts it for you.
- Each hop is
aws eks update-cluster-version --name <cluster> --kubernetes-version 1.32(then 1.33, then 1.34).
Bring nodes to the control plane's version between hops
Before updating your control plane to a new Kubernetes version, make sure that the Kubernetes minor version of both the managed nodes and Fargate nodes in your cluster are the same as your control plane’s version.Amazon EKS user guide, Update existing cluster to new Kubernetes version
kubelet must not be newer than kube-apiserver, and may be up to three minor versions older than kube-apiserverKubernetes version skew policy
Kubernetes tolerates kubelets up to three versions behind, but EKS is stricter: managed node groups and Fargate must match the control plane before the next update. AWS recommends the same for self-managed and hybrid nodes. If you skip the node roll after 1.32, the 1.33 hop is blocked.
kubectl get nodes -o custom-columns=NODE:.metadata.name,KUBELET:.status.nodeInfo.kubeletVersion,OS:.status.nodeInfo.osImage- After each control-plane hop, update every managed node group:
aws eks update-nodegroup-version --cluster-name <cluster> --nodegroup-name <group>. - Roll self-managed nodes and Karpenter NodePools onto the new AMI.
- Delete and recreate Fargate pods so they come back on the new version.
Pod disruption budgets that allow zero evictions stall the node roll
If the Pods don't leave the node within 15 minutes and there's no force flag, the upgrade phase fails with a PodEvictionFailure error.Amazon EKS user guide, Understand each phase of node updates
Every node group update drains nodes. A PodDisruptionBudget that allows no disruptions stops the drain, for example minAvailable equal to the replica count, or a single replica with minAvailable: 1. Three hops means three node rolls.
kubectl get pdb -A -o json | jq -r '.items[] | select(.status.disruptionsAllowed == 0) | .metadata.namespace + "/" + .metadata.name' # each one blocks a drain right nowScale those workloads to at least two replicas, or loosen the budget, before the window. --force on the node group update ignores budgets: use it only as a last resort.
Webhooks that fail closed can block pods while nodes roll
failurePolicy defines how unrecognized errors and timeout errors from the admission webhook are handled. Allowed values are Ignore or Fail.Kubernetes docs, Dynamic Admission Control
During a node roll the webhook's own pods get evicted. A webhook with failurePolicy: Fail and no ready backend rejects every request it matches. That can block pod creation across the cluster, sometimes including the pods that would bring the webhook back.
kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations -o json | jq -r '.items[] | .metadata.name as $n | .webhooks[] | select(.failurePolicy == "Fail") | $n + " " + .name + " -> " + (.clientConfig.service.namespace // "url") + "/" + (.clientConfig.service.name // "")'- Give each fail-closed webhook at least two replicas, a PodDisruptionBudget and spread across nodes.
- Exclude
kube-systemwith anamespaceSelector. - Update the webhook's chart (cert-manager, Kyverno, Gatekeeper, AWS Load Balancer Controller) to a release that supports the target version before each hop.
Add-on versions have to follow every hop
Upgrade the add-ons provided by Amazon EKS, such as those included by defaultAmazon EKS user guide, Update existing cluster to new Kubernetes version
VPC CNI, CoreDNS and kube-proxy each have a default version per Kubernetes version, and kube-proxy has to stay within the version skew. Third-party add-ons publish their own support ranges: cluster-autoscaler, Karpenter, ingress controllers, CSI drivers, service meshes. EKS upgrade insights flags some of this. It doesn't check third-party charts.
for a in vpc-cni coredns kube-proxy aws-ebs-csi-driver; do echo "== $a"; aws eks describe-addon-versions --kubernetes-version 1.32 --addon-name "$a" --query 'addons[].addonVersions[?compatibilities[?defaultVersion==`true`]].addonVersion' --output text; doneaws eks list-insights --cluster-name <cluster> --filter categories=UPGRADE_READINESS- After each control-plane hop and node roll, move VPC CNI, CoreDNS and kube-proxy to the default version for the new Kubernetes version.
- Check each third-party chart's support matrix before the hop, not after.
- Pass your add-on configuration explicitly on every update. An add-on update can reset fields you set by hand, such as the IAM role on the
aws-nodeservice account.
1.31 → 1.32
The hop AWS makes for you on November 26 if you don't. One API removal and one EKS auth change are the things to fix first.
FlowSchema and PriorityLevelConfiguration v1beta3 are removed
The flowcontrol.apiserver.k8s.io/v1beta3 API version of FlowSchema and PriorityLevelConfiguration has been removed in version 1.32. If you are using these APIs, you must update your configurations to use the latest supported version before upgrading.Amazon EKS user guide, Kubernetes versions on extended support
Manifests and Helm charts that still apply flowcontrol.apiserver.k8s.io/v1beta3 fail after the hop. Objects already in the cluster survive, because the API server stores them in a newer version. What breaks is the next deploy.
kubectl get --raw /metrics | grep apiserver_requested_deprecated_apis | grep flowcontrol # a line here is a client that called v1beta3 since the API server last restartedgrep -rn 'flowcontrol.apiserver.k8s.io/v1beta3' . # run in your manifests and charts repoChange apiVersion to flowcontrol.apiserver.k8s.io/v1 in every manifest and chart. v1 has been served since 1.29 with the same fields, so you can do it today, before the hop.
Anonymous requests are only allowed on the health endpoints
Requests to any other endpoint using the system:unauthenticated user will receive a 401 Unauthorized HTTP response.Amazon EKS user guide, Kubernetes versions on extended support
From 1.32, EKS allows anonymous requests only to /healthz, /livez and /readyz. Anything that calls the API without credentials stops working, such as a probe that reads /version or a binding that grants system:unauthenticated access.
kubectl get clusterrolebindings,rolebindings -A -o json | jq -r '.items[] | select(any(.subjects[]?; .name == "system:anonymous" or .name == "system:unauthenticated")) | .kind + "/" + (.metadata.namespace // "-") + "/" + .metadata.name' # system:public-info-viewer is a default; anything else is yoursGive those callers credentials: a ServiceAccount token inside the cluster, or an IAM identity with an EKS access entry outside it.
fsGroup is now applied to ReadWriteOncePod volumes
Apply fsGroup policy for ReadWriteOncePod volumes.Kubernetes 1.32 changelog
Pods with securityContext.fsGroup that mount a ReadWriteOncePod volume get the volume's files re-owned on the first mount after the upgrade. This already happens for ReadWriteOnce. An app that relied on the old ownership can fail to read its own data, and a large volume can take a long time to mount.
kubectl get pvc -A -o json | jq -r '.items[] | select(.spec.accessModes | index("ReadWriteOncePod")) | .metadata.namespace + "/" + .metadata.name'Check that those apps tolerate the new ownership. Set fsGroupChangePolicy: OnRootMismatch to avoid a full recursive chown on every mount.
Soft eviction no longer overrides a pod's own grace period
Fixed the bug where spec.terminationGracePeriodSeconds of the pod will always be overwritten by the MaxPodGracePeriodSeconds of the soft eviction, you can enable the AllowOverwriteTerminationGracePeriodSeconds feature gate, which will restore the previous behavior.Kubernetes 1.32 changelog
Only matters if your node config sets evictionSoft and evictionMaxPodGracePeriod. Soft-evicted pods now get the shorter of their own grace period and the eviction value. Before, they always got the eviction value, so pods with a short grace period now stop faster under memory pressure.
kubectl get --raw "/api/v1/nodes/$(kubectl get nodes -o jsonpath='{.items[0].metadata.name}')/proxy/configz" | jq -c '.kubeletconfig | {evictionSoft, evictionMaxPodGracePeriod}' # repeat per node groupUsually nothing to do. If a workload needs more time to shut down, raise its terminationGracePeriodSeconds.
Last version with Amazon Linux 2 nodes: start moving now
Kubernetes version 1.32 is the last version for which Amazon EKS will release Amazon Linux 2 (AL2) AMIs.Amazon EKS user guide, Kubernetes versions on extended support
Nothing breaks at this hop, but the next one does. Use the time on 1.32 to move node groups to AL2023 or Bottlerocket, so the 1.33 hop is only a version change.
kubectl get nodes -o custom-columns=NODE:.metadata.name,KUBELET:.status.nodeInfo.kubeletVersion,OS:.status.nodeInfo.osImage --no-headers | grep 'Amazon Linux 2' | grep -v 2023 # every node listed is on Amazon Linux 2See the first item of step 2.
1.32 → 1.33
The hop with the most work: no Amazon Linux 2 AMI. The rest are smaller changes in how pods are admitted.
No Amazon Linux 2 AMI for 1.33: AL2 node groups must move first
AWS is not releasing an EKS-optimized Amazon Linux 2 AMI for Kubernetes 1.33.Amazon EKS user guide, Kubernetes versions on extended support
Managed node groups on an AL2 AMI type (AL2_x86_64, AL2_x86_64_GPU, AL2_ARM_64) can't follow the control plane to 1.33. While they stay on 1.32, the control plane can't move on to 1.34. This is usually the biggest piece of work in the whole path. AL2023 boots with nodeadm instead of bootstrap.sh, so custom user data has to be rewritten.
kubectl get nodes -o custom-columns=NODE:.metadata.name,KUBELET:.status.nodeInfo.kubeletVersion,OS:.status.nodeInfo.osImage --no-headers | grep 'Amazon Linux 2' | grep -v 2023 # every node listed is on Amazon Linux 2aws eks list-nodegroups --cluster-name <cluster> --query nodegroups --output text | tr '\t' '\n' | while read -r ng; do aws eks describe-nodegroup --cluster-name <cluster> --nodegroup-name "$ng" --query 'nodegroup.[nodegroupName,amiType]' --output text; done- Still on 1.32, create AL2023 or Bottlerocket node groups, move the workloads over, then delete the AL2 groups.
- For Karpenter, point the EC2NodeClass
amiSelectorTermsat anal2023@alias. - Rewrite user data from bootstrap.sh flags to a nodeadm
NodeConfig, and test one node before rolling the rest.
The kubelet may only request service account tokens for audiences the pod or CSI driver declares
NodeRestriction admission now validates the audience value that kubelet is requesting a service account token for is part of the pod spec volume.Kubernetes 1.32 changelog
Reverts the `ServiceAccountNodeAudienceRestriction` feature to disabled in v1.32.Kubernetes 1.32 changelog
The kube-apiserver featuregate `ServiceAccountNodeAudienceRestriction` is enabled by default in 1.33.Kubernetes 1.33 changelog
The changelog lists this under 1.32, but the gate was turned back off in 1.32.2 and is on by default from 1.33, so on EKS it bites at this hop. A CSI driver that uses workload tokens, such as the Secrets Store CSI driver, fails to mount if its CSIDriver object doesn't list the audience in tokenRequests.
kubectl get csidrivers -o json | jq -r '.items[] | .metadata.name + ": " + ((.spec.tokenRequests // []) | map(.audience) | join(","))' # a driver that uses tokens but lists no audience here will breakUpgrade the CSI driver to a release whose CSIDriver object declares its tokenRequests audiences, before the hop.
Pods with supplementalGroupsPolicy: Strict are rejected on nodes that don't support it
kubelet now rejects pods with .spec.securityContext.supplementalGroupsPolicy: Strict when scheduled to the node that does not support the feature (.status.features.supplementalGroupsPolicy: false).Kubernetes 1.33 changelog
The feature is on by default in 1.33. A pod that asks for Strict and lands on a node whose container runtime can't do it now fails on that node instead of running with merged groups.
kubectl get nodes -o custom-columns='NODE:.metadata.name,SGP:.status.features.supplementalGroupsPolicy,RUNTIME:.status.nodeInfo.containerRuntimeVersion'Keep Strict pods on nodes that report true (containerd 2.0 or later), or drop the setting until every node does.
ServiceCIDR is GA: whoever can create one can extend the Service range
Action required for Kubernetes cluster administrators and for distributions that manage the cluster Service CIDR. Kubernetes now allows users to define the cluster Service CIDR via an API object: ServiceCIDR.Kubernetes 1.33 changelog
networking.k8s.io/v1 ServiceCIDR objects are served from 1.33. Any principal with create rights on them, including a broad * ClusterRole, can add Service IP ranges that may overlap your VPC.
kubectl get clusterroles -o json | jq -r '.items[] | select(any(.rules[]?; ((.resources // []) | index("servicecidrs") or index("*")) and ((.verbs // []) | index("create") or index("*")))) | .metadata.name' | grep -v '^system:'Limit who can create ServiceCIDR objects with RBAC, or add a ValidatingAdmissionPolicy that rejects new ranges.
nodeAffinity values are now validated when pods are created
Implemented validation for NodeSelectorRequirement values in Kubernetes when creating pods.Kubernetes 1.33 changelog
New pods whose nodeAffinity uses Gt or Lt with a non-integer value, or In or NotIn with an invalid label value, are rejected. Running pods keep running, but the workload can't roll or scale.
kubectl get deploy,sts,ds -A -o json | jq -r '.items[] | (.kind + "/" + .metadata.namespace + "/" + .metadata.name) as $n | [.. | .nodeSelectorTerms? // empty | .[] | .matchExpressions[]? | select(.operator == "Gt" or .operator == "Lt") | select(.values[]? | test("^[0-9]+$") | not)] | select(length != 0) | $n'Fix the pod templates before the hop.
In-place pod resize: status.resize is gone, and memory can't shrink without a restart
The pod status.resize field is now deprecated and will no longer be set. The status of a pod resize will be exposed under two new conditions: PodResizeInProgress and PodResizePending instead.Kubernetes 1.33 changelog
Memory limits cannot be decreased unless the memory resize restart policy is set to RestartContainer. Container resizePolicy is no longer mutable.Kubernetes 1.33 changelog
Only matters if a controller or script resizes running pods. Tools that wait on status.resize never see it set, in-place memory decreases are rejected, and resizePolicy can't be changed after the pod exists.
kubectl get pods -A -o json | jq -r '.items[] | select(any(.spec.containers[]; .resizePolicy != null)) | .metadata.namespace + "/" + .metadata.name'Read the PodResizeInProgress and PodResizePending conditions instead. Set resizePolicy for memory to RestartContainer when the pod is created, if you need to lower memory in place.
The Endpoints API is deprecated
The v1 Endpoints API is now officially deprecated (though still fully supported). The API will not be removed, but all users should use the EndpointSlice API instead.Kubernetes 1.33 changelog
Nothing stops working, but clients that read Endpoints now get deprecation warnings. Endpoints also stop at 1000 addresses, so large Services already look incomplete to them.
kubectl get clusterroles -o json | jq -r '.items[] | select(any(.rules[]?; (.resources // []) | index("endpoints"))) | .metadata.name' | grep -v '^system:' # tools that still read EndpointsMove controllers, meshes and monitoring to discovery.k8s.io/v1 EndpointSlice as you update them.
The service.kubernetes.io/topology-mode annotation is deprecated
The beta annotation service.kubernetes.io/topology-mode is now considered deprecated and will not graduate to GA. It remains operational for backward compatibility.Kubernetes 1.33 changelog
It still works. It won't become GA, so plan to move off it.
kubectl get svc -A -o json | jq -r '.items[] | select(.metadata.annotations["service.kubernetes.io/topology-mode"] != null) | .metadata.namespace + "/" + .metadata.name'Replace the annotation with spec.trafficDistribution: PreferClose.
Dynamic Resource Allocation is on for the first time
The Dynamic Resource Allocation beta Kubernetes API is enabled.Amazon EKS user guide, Kubernetes versions on extended support
Nothing breaks: EKS didn't serve the DRA API before 1.33. If you don't run a DRA driver, skip this and the DRA item in step 3.
kubectl get resourceslices -o json | jq -r '.items[].spec.driver' | sort -u # empty output means no DRA driver- If you adopt DRA now, use a driver and clients on
resource.k8s.io/v1beta2:v1beta1is deprecated. - Put claims with
adminAccess: trueonly in namespaces labelledresource.k8s.io/admin-access: "true". 1.34 renames that label (step 3).
1.33 → 1.34
New AMIs with containerd 2.1, still no Amazon Linux 2, and a handful of behaviour changes in the kubelet and scheduler.
Static pods that reference API objects are rejected
Static pods that reference API objects were denied admission by the kubelet so that static pods would not be silently running even after the mirror pod creation failed.Kubernetes 1.34 changelog
Most EKS nodes run no static pods. On self-managed nodes or custom AMIs that drop manifests into the kubelet's static pod path, a static pod that uses a ConfigMap, Secret, PVC or ServiceAccount stops running once the node is on 1.34.
kubectl get pods -A -o json | jq -r '.items[] | select(.metadata.annotations["kubernetes.io/config.mirror"] != null) | select((.spec.serviceAccountName != null and .spec.serviceAccountName != "default") or ([.spec.volumes[]? | select(.configMap or .secret or .persistentVolumeClaim or .projected)] | length != 0) or ([.spec.containers[].env[]? | select(.valueFrom.configMapKeyRef or .valueFrom.secretKeyRef)] | length != 0) or ([.spec.containers[].envFrom[]?] | length != 0)) | .metadata.namespace + "/" + .metadata.name'Inline the values in the manifest (literal env, hostPath) or run the pod as a DaemonSet before the node roll.
Nodes move to containerd 2.1
Containerd updated to 2.1 in Version 1.34 for launch.Amazon EKS user guide, Kubernetes versions on standard support
The 1.34 AMIs ship containerd 2.1. Test anything that touches the runtime before the fleet rolls: user data that writes /etc/containerd/config.toml, registry mirror settings, and very old images in the Docker schema 1 format.
kubectl get nodes -o custom-columns=NODE:.metadata.name,RUNTIME:.status.nodeInfo.containerRuntimeVersionLaunch one 1.34 node from your launch template, run a representative workload on it, then roll the rest. AWS points to the containerd 2.1 release notes if something breaks.
AppArmor profiles are no longer copied into the old annotations
AppArmor profiles specified in the Pod or container SecurityContext were no longer copied to deprecated AppArmor annotations (prefix container.apparmor.security.beta.kubernetes.io/). Anything that inspected the deprecated annotations must be migrated to use the SecurityContext fields instead.Kubernetes 1.34 changelog
AppArmor is deprecated in Kubernetes 1.34.Amazon EKS user guide, Kubernetes versions on standard support
Admission policies (Kyverno, Gatekeeper) and audits that read the container.apparmor.security.beta.kubernetes.io/ annotations stop seeing profiles on pods that set them through securityContext.appArmorProfile.
kubectl get pods -A -o json | jq -r '.items[] | select(.metadata.annotations // {} | keys | any(startswith("container.apparmor.security.beta.kubernetes.io/"))) | .metadata.namespace + "/" + .metadata.name' | sort -uMove policies and manifests to the securityContext.appArmorProfile fields. AWS suggests seccomp or Pod Security Standards for new work.
Nodes labelled exclude-from-external-load-balancers=false now join load balancers
Respected the exclude-from-external-load-balancers=false label.Kubernetes 1.34 changelog
Until 1.34, any value of node.kubernetes.io/exclude-from-external-load-balancers kept a node out of cloud load balancers. Now only a value other than false does. Nodes carrying =false become load balancer targets.
kubectl get nodes -L node.kubernetes.io/exclude-from-external-load-balancers --no-headers | awk '$NF == "false"' # each node printed becomes a load balancer target at 1.34Remove the label, or set it to true where you meant to exclude the node.
Topology spread matchLabelKeys is merged into the selector by the API server
The Kubernetes API server merged selectors built from matchLabelKeys into the labelSelector of topologySpreadConstraints, aligning Pod Topology Spread behavior with Inter-Pod Affinity.Kubernetes 1.34 changelog
This is why the path goes one version at a time. EKS can't skip 1.33, but a pod created on 1.32 and never recreated is in the same position as a skipped version: its selector was never merged, and the 1.34 scheduler no longer corrects for it, so spreading can drift.
kubectl get pods -A -o json | jq -r '.items[] | select(any(.spec.topologySpreadConstraints[]?; .matchLabelKeys != null)) | .metadata.namespace + "/" + .metadata.name'Restart workloads that use matchLabelKeys after the 1.33 hop (kubectl rollout restart). Controllers that read labelSelector back should expect the extra In requirements.
The scheduler no longer clears nominatedNodeName
The scheduler no longer cleared the nominatedNodeName field for Pods. External components, such as Cluster Autoscaler and Karpenter, were responsible for managing this field when needed.Kubernetes 1.34 changelog
A stale nomination now stays on a pending pod until something else clears it, for example after the nominated node is deleted.
kubectl get pods -A -o json | jq -r '.items[] | select(.status.nominatedNodeName != null and .spec.nodeName == null) | .metadata.namespace + "/" + .metadata.name + " nominated=" + .status.nominatedNodeName'Run a Cluster Autoscaler or Karpenter release that supports 1.34 before the hop.
Downward API limits fall back to pod-level limits
if container-level limits were not set, pod-level limits were now used before falling back to node allocatable resources.Kubernetes 1.34 changelog
A container without its own limits that reads limits.cpu or limits.memory through the Downward API now sees the pod's limits instead of the node's capacity. JVM heap or GOMAXPROCS sizing built on that value changes.
kubectl get pods -A -o json | jq -r '.items[] | select(.spec.resources.limits != null) | select(any(.spec.containers[]; .resources.limits == null and any(.env[]?; .valueFrom.resourceFieldRef != null))) | .metadata.namespace + "/" + .metadata.name'Set container-level limits where the old value was intended.
VolumeAttributesClass moves to storage.k8s.io/v1
If you self-manage your CSI sidecar containers, you may need to pin to older sidecar versions on pre-1.34 clusters to maintain VAC functionality.Amazon EKS user guide, Kubernetes versions on standard support
Only matters if you change EBS volume type or IOPS through a VolumeAttributesClass. While you are on 1.32 or 1.33, newer self-managed csi-provisioner and csi-resizer sidecars expect the GA API, so volume modification can stop working partway through the path. AWS patched its managed sidecars for the beta API only until July 29, 2026.
kubectl get volumeattributesclasseskubectl get pods -A -o jsonpath='{range .items[*]}{range .spec.containers[*]}{.image}{"\n"}{end}{end}' | grep -E 'csi-(provisioner|resizer)' | sort -uKeep the sidecars on versions that speak v1beta1 until the 1.34 hop, then upgrade them and move VolumeAttributesClass manifests to storage.k8s.io/v1.
Only if you run a DRA driver: the old kubelet API, the admin label and a scheduling timeout
removed support for the v1alpha4 kubelet gRPC API (added in 1.31, superseded in 1.32). DRA drivers using the helper package from Kubernetes >= 1.32 use the v1beta1 API and continue to be supported.Kubernetes 1.34 changelog
the alpha-level resource.k8s.io/admin-access label has been updated to resource.kubernetes.io/admin-access. Admins using the alpha feature and updating from 1.33 can set both labels, upgrade, then remove resource.k8s.io/admin-accessKubernetes 1.34 changelog
- A driver built only for the v1alpha4 kubelet API isn't registered on 1.34 nodes, and its devices disappear.
- Claims with
adminAccessin a namespace that has only the old label are rejected. - Scheduling a pod with a complex claim now times out after 10 seconds (
FilterTimeout).
kubectl get resourceslices -o json | jq -r '.items[].spec.driver' | sort -u # empty output means no DRA driver: skip thiskubectl get ns -l resource.k8s.io/admin-access -L resource.kubernetes.io/admin-access- Upgrade every DRA driver to a release built on the 1.32 or newer kubelet plugin helper before the node roll.
- Add
resource.kubernetes.io/admin-access: "true"next to the old label, upgrade, then remove the old one. - Raise
FilterTimeoutin the scheduler's DynamicResources config only if pods stay Pending with a timeout.
Not listed: changes that only affect a control plane you run yourself (custom scheduler plugins, authentication config files, --runtime-config, etcd 3.6). On EKS, AWS runs those.
Check your cluster automatically.
Run kubectl upgrade-check --target 1.34 to check your cluster automatically. Free, open source and read-only. Nothing leaves your machine.
kubectl krew install upgrade-checkFrequently asked questions
Still curious? hello@runtimez.io
What breaks when upgrading EKS from 1.31 to 1.32?
Three things need fixing before the 1.32 hop: FlowSchema and PriorityLevelConfiguration objects on flowcontrol.apiserver.k8s.io/v1beta3, which is removed; clients that call the API anonymously, since anonymous requests only reach /healthz, /livez and /readyz; and fsGroup handling on ReadWriteOncePod volumes. 1.32 is also the last EKS version with Amazon Linux 2 AMIs.
What breaks when upgrading EKS from 1.32 to 1.33?
EKS publishes no Amazon Linux 2 AMIs for 1.33, so every node group has to move to AL2023 or Bottlerocket first. CSI drivers must declare the service account token audiences they use. Also watch for supplementalGroupsPolicy: Strict, stricter nodeAffinity validation, ServiceCIDR, and the deprecation of the Endpoints API in favour of EndpointSlices.
What breaks when upgrading EKS from 1.33 to 1.34?
On 1.34 the kubelet rejects static pods that reference API objects such as ConfigMaps, Secrets, PersistentVolumeClaims or ServiceAccounts. DRA drivers still on the v1alpha4 kubelet API stop working, and the new AMIs ship containerd 2.1. Also check nodes labelled exclude-from-external-load-balancers=false, which now join load balancers, plus AppArmor annotations and topology spread.
Can I upgrade EKS directly from 1.31 to 1.34?
No. Amazon EKS updates the control plane one minor version at a time, so 1.31 to 1.34 is three separate upgrades: 1.32, 1.33, then 1.34. Between hops, managed node groups and Fargate nodes must be brought to the control plane’s version, or EKS blocks the next update. Plan three change windows, not one.
Can I roll back an EKS upgrade?
Only the control plane, and only within 7 days of the upgrade. You roll back managed node groups and add-ons yourself, before the control plane. If AWS upgraded the cluster automatically at the end of extended support, as it does to 1.31 clusters on November 26, 2026, you cannot roll back at all.
Sources
Every quote above is copied from one of these. Checked October 19, 2026.
- Kubernetes 1.32 changelog
- Kubernetes 1.33 changelog
- Kubernetes 1.34 changelog
- Amazon EKS user guide, Kubernetes versions on extended support
- Amazon EKS user guide, Kubernetes versions on standard support
- Amazon EKS user guide, Update existing cluster to new Kubernetes version
- Amazon EKS user guide, Roll back a cluster to a previous Kubernetes version
- Amazon EKS user guide, Understand each phase of node updates
- Kubernetes version skew policy
- Kubernetes docs, Dynamic Admission Control
Last updated
