Runtimezruntimez
runtimez / free tools / eks-1-31-to-1-34
Free guide · checked October 19, 2026

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.

StepFix before you click UpdateWatch for
1.31 → 1.32
  • FlowSchema / PriorityLevelConfiguration off v1beta3
  • Credentials for anything that calls the API anonymously
  • fsGroup on ReadWriteOncePod volumes
  • Last Amazon Linux 2 version: start moving nodes
1.32 → 1.33
  • Every node group off Amazon Linux 2
  • CSI drivers declare their token audiences
  • supplementalGroupsPolicy: Strict
  • nodeAffinity validation, ServiceCIDR, Endpoints deprecation
1.33 → 1.34
  • Static pods that use ConfigMaps or Secrets
  • DRA drivers on the old kubelet API
  • containerd 2.1 on the new AMIs
  • Load balancer label, AppArmor annotations, topology spread

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.

Every hopEKS

One minor version at a time: 1.31 → 1.34 is three upgrades

Vendor says
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
What breaks

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.

Check it
aws eks describe-cluster --name <cluster> --query cluster.version --output text
aws ec2 describe-subnets --subnet-ids $(aws eks describe-cluster --name <cluster> --query 'cluster.resourcesVpcConfig.subnetIds' --output text) --query 'Subnets[].[SubnetId,AvailableIpAddressCount]' --output text
Fix
  • 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).
Every hopEKS

Bring nodes to the control plane's version between hops

Vendor says
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-apiserver
Kubernetes version skew policy
What breaks

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.

Check it
kubectl get nodes -o custom-columns=NODE:.metadata.name,KUBELET:.status.nodeInfo.kubeletVersion,OS:.status.nodeInfo.osImage
Fix
  • 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.
Every hopEKS

Pod disruption budgets that allow zero evictions stall the node roll

Vendor says
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
What breaks

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.

Check it
kubectl get pdb -A -o json | jq -r '.items[] | select(.status.disruptionsAllowed == 0) | .metadata.namespace + "/" + .metadata.name' # each one blocks a drain right now
Fix

Scale 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.

Every hopKubernetes

Webhooks that fail closed can block pods while nodes roll

Vendor says
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
What breaks

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.

Check it
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 // "")'
Fix
  • Give each fail-closed webhook at least two replicas, a PodDisruptionBudget and spread across nodes.
  • Exclude kube-system with a namespaceSelector.
  • Update the webhook's chart (cert-manager, Kyverno, Gatekeeper, AWS Load Balancer Controller) to a release that supports the target version before each hop.
Every hopEKS

Add-on versions have to follow every hop

Vendor says
Upgrade the add-ons provided by Amazon EKS, such as those included by default
Amazon EKS user guide, Update existing cluster to new Kubernetes version
What breaks

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.

Check it
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; done
aws eks list-insights --cluster-name <cluster> --filter categories=UPGRADE_READINESS
Fix
  • 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-node service account.
Step 1

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.

HighEKS

FlowSchema and PriorityLevelConfiguration v1beta3 are removed

Vendor says
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
What breaks

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.

Check it
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 restarted
grep -rn 'flowcontrol.apiserver.k8s.io/v1beta3' . # run in your manifests and charts repo
Fix

Change 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.

MediumEKS

Anonymous requests are only allowed on the health endpoints

Vendor says
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
What breaks

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.

Check it
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 yours
Fix

Give those callers credentials: a ServiceAccount token inside the cluster, or an IAM identity with an EKS access entry outside it.

MediumKubernetes

fsGroup is now applied to ReadWriteOncePod volumes

Vendor says
Apply fsGroup policy for ReadWriteOncePod volumes.
Kubernetes 1.32 changelog
What breaks

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.

Check it
kubectl get pvc -A -o json | jq -r '.items[] | select(.spec.accessModes | index("ReadWriteOncePod")) | .metadata.namespace + "/" + .metadata.name'
Fix

Check that those apps tolerate the new ownership. Set fsGroupChangePolicy: OnRootMismatch to avoid a full recursive chown on every mount.

LowKubernetes

Soft eviction no longer overrides a pod's own grace period

Vendor says
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
What breaks

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.

Check it
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 group
Fix

Usually nothing to do. If a workload needs more time to shut down, raise its terminationGracePeriodSeconds.

InfoEKS

Last version with Amazon Linux 2 nodes: start moving now

Vendor says
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
What breaks

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.

Check it
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 2
Fix

See the first item of step 2.

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.

HighEKS

No Amazon Linux 2 AMI for 1.33: AL2 node groups must move first

Vendor says
AWS is not releasing an EKS-optimized Amazon Linux 2 AMI for Kubernetes 1.33.
Amazon EKS user guide, Kubernetes versions on extended support
What breaks

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.

Check it
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 2
aws 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
Fix
  • Still on 1.32, create AL2023 or Bottlerocket node groups, move the workloads over, then delete the AL2 groups.
  • For Karpenter, point the EC2NodeClass amiSelectorTerms at an al2023@ alias.
  • Rewrite user data from bootstrap.sh flags to a nodeadm NodeConfig, and test one node before rolling the rest.
MediumKubernetes

The kubelet may only request service account tokens for audiences the pod or CSI driver declares

Vendor says
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
What breaks

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.

Check it
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 break
Fix

Upgrade the CSI driver to a release whose CSIDriver object declares its tokenRequests audiences, before the hop.

MediumKubernetes

Pods with supplementalGroupsPolicy: Strict are rejected on nodes that don't support it

Vendor says
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
What breaks

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.

Check it
kubectl get nodes -o custom-columns='NODE:.metadata.name,SGP:.status.features.supplementalGroupsPolicy,RUNTIME:.status.nodeInfo.containerRuntimeVersion'
Fix

Keep Strict pods on nodes that report true (containerd 2.0 or later), or drop the setting until every node does.

MediumKubernetes

ServiceCIDR is GA: whoever can create one can extend the Service range

Vendor says
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
What breaks

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.

Check it
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:'
Fix

Limit who can create ServiceCIDR objects with RBAC, or add a ValidatingAdmissionPolicy that rejects new ranges.

LowKubernetes

nodeAffinity values are now validated when pods are created

Vendor says
Implemented validation for NodeSelectorRequirement values in Kubernetes when creating pods.
Kubernetes 1.33 changelog
What breaks

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.

Check it
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

Fix the pod templates before the hop.

LowKubernetes

In-place pod resize: status.resize is gone, and memory can't shrink without a restart

Vendor says
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
What breaks

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.

Check it
kubectl get pods -A -o json | jq -r '.items[] | select(any(.spec.containers[]; .resizePolicy != null)) | .metadata.namespace + "/" + .metadata.name'
Fix

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.

LowKubernetes

The Endpoints API is deprecated

Vendor says
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
What breaks

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.

Check it
kubectl get clusterroles -o json | jq -r '.items[] | select(any(.rules[]?; (.resources // []) | index("endpoints"))) | .metadata.name' | grep -v '^system:' # tools that still read Endpoints
Fix

Move controllers, meshes and monitoring to discovery.k8s.io/v1 EndpointSlice as you update them.

LowKubernetes

The service.kubernetes.io/topology-mode annotation is deprecated

Vendor says
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
What breaks

It still works. It won't become GA, so plan to move off it.

Check it
kubectl get svc -A -o json | jq -r '.items[] | select(.metadata.annotations["service.kubernetes.io/topology-mode"] != null) | .metadata.namespace + "/" + .metadata.name'
Fix

Replace the annotation with spec.trafficDistribution: PreferClose.

InfoEKS

Dynamic Resource Allocation is on for the first time

Vendor says
The Dynamic Resource Allocation beta Kubernetes API is enabled.
Amazon EKS user guide, Kubernetes versions on extended support
What breaks

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.

Check it
kubectl get resourceslices -o json | jq -r '.items[].spec.driver' | sort -u # empty output means no DRA driver
Fix
  • If you adopt DRA now, use a driver and clients on resource.k8s.io/v1beta2: v1beta1 is deprecated.
  • Put claims with adminAccess: true only in namespaces labelled resource.k8s.io/admin-access: "true". 1.34 renames that label (step 3).
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.

HighKubernetes

Static pods that reference API objects are rejected

Vendor says
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
What breaks

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.

Check it
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'
Fix

Inline the values in the manifest (literal env, hostPath) or run the pod as a DaemonSet before the node roll.

MediumEKS

Nodes move to containerd 2.1

Vendor says
Containerd updated to 2.1 in Version 1.34 for launch.
Amazon EKS user guide, Kubernetes versions on standard support
What breaks

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.

Check it
kubectl get nodes -o custom-columns=NODE:.metadata.name,RUNTIME:.status.nodeInfo.containerRuntimeVersion
Fix

Launch 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.

MediumKubernetes

AppArmor profiles are no longer copied into the old annotations

Vendor says
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
What breaks

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.

Check it
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 -u
Fix

Move policies and manifests to the securityContext.appArmorProfile fields. AWS suggests seccomp or Pod Security Standards for new work.

MediumKubernetes

Nodes labelled exclude-from-external-load-balancers=false now join load balancers

Vendor says
Respected the exclude-from-external-load-balancers=false label.
Kubernetes 1.34 changelog
What breaks

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.

Check it
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.34
Fix

Remove the label, or set it to true where you meant to exclude the node.

MediumKubernetes

Topology spread matchLabelKeys is merged into the selector by the API server

Vendor says
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
What breaks

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.

Check it
kubectl get pods -A -o json | jq -r '.items[] | select(any(.spec.topologySpreadConstraints[]?; .matchLabelKeys != null)) | .metadata.namespace + "/" + .metadata.name'
Fix

Restart workloads that use matchLabelKeys after the 1.33 hop (kubectl rollout restart). Controllers that read labelSelector back should expect the extra In requirements.

LowKubernetes

The scheduler no longer clears nominatedNodeName

Vendor says
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
What breaks

A stale nomination now stays on a pending pod until something else clears it, for example after the nominated node is deleted.

Check it
kubectl get pods -A -o json | jq -r '.items[] | select(.status.nominatedNodeName != null and .spec.nodeName == null) | .metadata.namespace + "/" + .metadata.name + " nominated=" + .status.nominatedNodeName'
Fix

Run a Cluster Autoscaler or Karpenter release that supports 1.34 before the hop.

LowKubernetes

Downward API limits fall back to pod-level limits

Vendor says
if container-level limits were not set, pod-level limits were now used before falling back to node allocatable resources.
Kubernetes 1.34 changelog
What breaks

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.

Check it
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'
Fix

Set container-level limits where the old value was intended.

LowEKS

VolumeAttributesClass moves to storage.k8s.io/v1

Vendor says
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
What breaks

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.

Check it
kubectl get volumeattributesclasses
kubectl get pods -A -o jsonpath='{range .items[*]}{range .spec.containers[*]}{.image}{"\n"}{end}{end}' | grep -E 'csi-(provisioner|resizer)' | sort -u
Fix

Keep the sidecars on versions that speak v1beta1 until the 1.34 hop, then upgrade them and move VolumeAttributesClass manifests to storage.k8s.io/v1.

MediumKubernetes

Only if you run a DRA driver: the old kubelet API, the admin label and a scheduling timeout

Vendor says
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-access
Kubernetes 1.34 changelog
What breaks
  • A driver built only for the v1alpha4 kubelet API isn't registered on 1.34 nodes, and its devices disappear.
  • Claims with adminAccess in a namespace that has only the old label are rejected.
  • Scheduling a pod with a complex claim now times out after 10 seconds (FilterTimeout).
Check it
kubectl get resourceslices -o json | jq -r '.items[].spec.driver' | sort -u # empty output means no DRA driver: skip this
kubectl get ns -l resource.k8s.io/admin-access -L resource.kubernetes.io/admin-access
Fix
  • 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 FilterTimeout in 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-check

Frequently 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.

Last updated