Kubernetes 1.31: the stabilisations that matter day to day
Table of contents
- Key takeaways
- AppArmor is no longer an annotation
- Real sidecars, at last
- DRA: still alpha, but with intent
- What's gone
- The scheduler, quieter
- An honest upgrade checklist
- Frequently asked questions
- Are Kubernetes 1.31's native sidecars stable already?
- Can I use Dynamic Resource Allocation in production with Kubernetes 1.31?
- What happens if my cluster still uses the in-tree CephFS or CephRBD drivers?
- Conclusion
- Sources
Updated: 2026-07-07
Discover Kubernetes 1.31's stabilizations: AppArmor GA, native sidecars enabled by default, and alpha DRA. A guide for cluster operators and DevOps teams.
Kubernetes 1.31 shipped on 13 August 2024 and is probably one of the calmest releases of the last two years. No flashy headline, no change that forces a manifest rewrite, no redesigned API client. And that is exactly why it deserves a careful reading: when a release does not push loud novelties, it is usually closing old debts. 1.31 closes several, and some of them change the day to day of cluster operators far more than their announcements suggest.
Key takeaways
-
AppArmor reaches GA as a first-class field in
securityContext, removing the dependency on annotations. -
Sidecars declared as
initContainerswithrestartPolicy: Alwayshave been enabled by default for two releases and behave in practice as first-class citizens, though the formal graduation to stable does not land until 1.33. -
Dynamic Resource Allocation (DRA) with structured parameters is still alpha: designing the architecture now saves rework once beta lands in 1.32 and GA in 1.34.
-
In-tree CephFS and CephRBD drivers are removed: check
storageclassbefore touching the control plane. -
The scheduler gets incremental performance work; clusters near saturation notice it most.
AppArmor is no longer an annotation
For years, applying an AppArmor profile to a pod meant a metadata annotation, a convention inherited from the past that carried every problem annotations have: no schema validation, no discovery via kubectl explain, easy to forget in a Helm chart rebase. In 1.31 AppArmor reaches GA as a first-class field inside securityContext.
apiVersion: v1
kind: Pod
metadata:
name: hardened-web
spec:
securityContext:
appArmorProfile:
type: Localhost
localhostProfile: restricted-web
containers:
- name: app
image: nginx:1.27
The change looks cosmetic, but the consequences are practical: admission webhooks can validate the profile as part of the schema, policy engines (OPA/Gatekeeper, Kyverno) get a canonical path to inspect, and compliance teams stop depending on annotations that get lost in chart rebases. For anyone already hardening nodes with AppArmor, this consolidates a layer that used to be fragile and makes it realistic to enforce a cluster-wide baseline without writing a mutating webhook.
Real sidecars, at last
The most awaited stabilisation. Until 1.29 the sidecar pattern was, quite literally, a hack: one more container in the pod, with no guarantees about start order relative to the main container, no termination order, and the classic problem where the proxy died before the application. The community answer was a mix of preStop scripts, shareProcessNamespace, and service-mesh-specific workarounds.
In 1.31, sidecars declared as initContainers with restartPolicy: Always have already been enabled by default for two releases and work exactly as promised, though their formal graduation to stable will not land until 1.33. They start before the main container, restart independently if they fail, and terminate after the main one finishes. That single change resolves three chronic pains:
-
Service meshes that blocked Jobs because the sidecar stayed alive.
-
Log collectors that lost the final bytes before shutdown.
-
Security proxies that came up late and left a window uncovered.
The operational impact is enormous for anyone running Istio, Linkerd, Vector or any sidecar-style collector. Manifests get simpler and a whole class of night-shift incidents disappears. This connects directly to the analysis of Kubernetes 1.28 and the native sidecar pattern, where the feature was alpha: that article explained the motivation; 1.31 is the definitive recipe.
DRA: still alpha, but with intent
Dynamic Resource Allocation with structured parameters is still alpha in 1.31: the API moves to v1beta1 in 1.32 and does not reach GA until 1.34. It replaces the old device-plugins model for GPUs, FPGAs, and miscellaneous accelerators with a claim-based abstraction, much like persistent volumes work. A pod declares what it needs, a driver resolves it, the scheduler reconciles.
For single-tenant setups with one GPU per node, device plugins still worked fine; but as soon as you entered sharing, GPU time-slicing, or heterogeneous pools, the old model fell short. In 1.31 it still requires explicit feature gates and is not production-ready, but anyone planning an ML or inference platform should be testing it in staging already: the jump to beta in 1.32 and to GA in 1.34 will force architectural decisions and it is better to arrive with the shape of the API already internalised.
What’s gone
The in-tree drivers for CephFS and CephRBD are removed. If anyone is still using them, migrating to the equivalent CSI drivers is a prerequisite before the upgrade. This kind of removal is the one that produces surprises: the cluster starts up fine, but old PVCs are left orphaned and nobody notices until a pod retries an attach. The safe workflow is a kubectl get storageclass reviewing provisioner, cross-referenced with live PVs, before touching the control plane.
The scheduler, quieter
Scheduler improvements in 1.31 are incremental, with no official throughput figure published by the project, but they show in two specific scenarios:
-
Large clusters with many Pending pods waiting for room.
-
Workloads with active preemption where eviction decisions used to be erratic.
Not enough to justify an upgrade on its own, but it does explain why clusters close to saturation feel smoother after updating. Anyone measuring real node cost with Kubecost or OpenCost will see the utilisation impact after the jump.
An honest upgrade checklist
Before jumping from 1.29 or 1.30 six things should be closed:
-
Clean deprecation report on the current version.
-
Recent etcd backup verified with
etcdctl snapshot status. -
Node drains that respect declared PDBs (and a check that the PDBs are actually satisfiable).
-
CSI drivers in line with current compatibility matrices.
-
Real test of any service mesh that will migrate to the new sidecar model.
-
Canary with at least one node running the new kubelet before rolling it across the rest.
The upgrade itself, via kubeadm, holds no mystery: kubeadm upgrade plan, kubeadm upgrade apply v1.31.x, and then kubelet node by node, respecting the drains. What hurts is not the command; it is having skipped the six points above. Pairing this with a GitOps strategy, such as the one described in GitOps with ArgoCD, lets you validate updated manifests against the new API before touching production.
Frequently asked questions
Are Kubernetes 1.31’s native sidecars stable already?
They run enabled by default since 1.29 and behave exactly as documented in 1.31, but the formal graduation to "stable" does not land until version 1.33. In practice, anyone using them in 1.31 can already rely on the start and termination ordering.
Can I use Dynamic Resource Allocation in production with Kubernetes 1.31?
Not without caveats: in 1.31, DRA with structured parameters is still alpha and requires enabling explicit feature gates on the API server, scheduler, and kubelet. The API moves to v1beta1 in 1.32 and reaches GA in 1.34.
What happens if my cluster still uses the in-tree CephFS or CephRBD drivers?
It stops working after the 1.31 upgrade: migrate first to the equivalent CSI drivers (ceph-csi), checking storageclass and live PVs to avoid orphaned PVCs.
Conclusion
Kubernetes 1.31 will not appear in any event keynote, and that’s fine. It is a hygiene release: it pulls AppArmor out of the annotation limbo, moves the sidecar pattern a step closer to its formal stabilisation in 1.33, and prepares the ground for DRA to move toward GA without being rushed. For anyone running clusters in production, the question is not whether it is worth upgrading, but how soon it can be done before the gap with upstream widens and every further jump starts accumulating its own technical debt.
Read also the Spanish version: Kubernetes 1.31: las estabilizaciones que importan en el día a día.