Kubernetes v1.36: Migrate Off ingress-nginx Before You Read the Rest
Here's the thing about ingress-nginx: it's everywhere, it's boring, and it works. That's exactly why this is hard. The CNCF moved it to end-of-life in March 2026. The sig-network team is no longer cutting releases. There will be no security patches. And if you've been running it quietly in the background — which most of us have — it's been accumulating unpatched CVEs since then with nobody upstream doing anything about it. The project repository still exists. The community hasn't vanished overnight. But the organised maintenance is gone, and that means your ingress layer is now in the same category as anything else you'd describe as "unsupported dependency." That's not a comfortable place for traffic handling.
Look, I know migration from ingress-nginx sounds like a weekend you don't have. It's not usually a single Helm value change. But the risk calculus has shifted fundamentally. Before March 2026, a known CVE in ingress-nginx meant "there'll be a patch release in a few days." After March 2026, it means "you're carrying this forever unless you move." That's a different situation, and it deserves a different response than "we'll get to it."
The good news — and there's genuinely good news in v1.36 — is that once you've dealt with the ingress situation, this is a solid release. User Namespaces goes GA. SELinux volume mounting goes GA. DRA device taints graduate to beta. If you're running multi-tenant clusters or SELinux-enforcing nodes, there are real operational wins here. But sort the ingress-nginx situation first.
Quick takeaways¶
- ingress-nginx is end-of-life. No more releases, no security patches. If you're running it, you need a migration plan today.
- User Namespaces goes GA —
hostUsers: falseis now production-ready. Container root no longer means node root. - SELinux volume mounting goes GA — pod startup times on SELinux-enforcing nodes should improve significantly.
- DRA device taints/tolerations reach beta — the taint/toleration model now extends to GPUs, FPGAs, and custom accelerators.
externalIPson Services is deprecated — if you're using this field, start planning your migration.
The ingress-nginx retirement — what you need to do¶
ingress-nginx was the de facto standard Kubernetes ingress controller for years. It was maintained by sig-network under the CNCF umbrella, it was battle-tested at scale, and it handled the vast majority of Kubernetes ingress traffic in the wild. The retirement decision came down to maintainer bandwidth, not technical inadequacy — the team simply couldn't sustain it long-term, and the Kubernetes project is deliberately moving toward Gateway API as the future of ingress anyway.
The community archive means the code is still there, PRs can still technically be raised, but there's no coordinated release process, no CVE triage process, and no patch release cadence. If a critical vulnerability surfaces tomorrow, you're on your own.
CVE exposure is accumulating right now
Every day you run ingress-nginx after March 2026 is a day you're carrying unpatched vulnerabilities with no upstream fix coming. This isn't "we should migrate eventually" — it's "we are now self-responsible for a security boundary with no support." Treat it accordingly.
So, what are your options?
Ingress-NGINX fork (maintained by F5/NGINX). This is the closest thing to a drop-in replacement. F5 and the NGINX team have forked the project and are actively maintaining it. The configuration model is compatible, the annotations are largely the same, and for most teams this is the lowest-friction migration path. If you want to move fast and minimise risk to application teams, start here.
Gateway API. This is the direction Kubernetes is actually moving. Gateway API is expressive, role-oriented, and designed for the multi-tenant world where ingress configuration needs to be split between infra and application teams. It's more work to migrate to — the resource model is genuinely different from Ingress objects — but it's the right long-term investment. If you've got the runway, this is the path worth taking.
Cilium Gateway or Envoy Gateway. Good choices if you're already running Cilium as your CNI or are committed to an Envoy-based stack. Cilium's Gateway API implementation is mature, and if you're already paying the operational overhead of running Cilium, getting ingress from the same component simplifies your stack.
Apply this: GitOps makes migration less painful
If you're on GitOps, the migration is probably less painful than you're imagining. Your ingress manifests are already in Git. Depending on which path you take, it might be as straightforward as swapping out a Helm chart reference and updating version values in your values files. The application-level Ingress objects may need updating if you're moving to Gateway API's HTTPRoute model, but that's a bounded change you can roll out incrementally.
User Namespaces — finally GA¶
User Namespaces have been in the works for a long time, and they're now production-ready in v1.36. Here's what they actually do, in plain terms.
Without user namespaces, if a process inside a container runs as root (UID 0), it's also running as root on the underlying node's kernel. Container boundaries do a lot of good work, but if there's a container escape — through a kernel vulnerability, a misconfigured capability, anything — you've got a root process on the node. That's bad.
With user namespaces enabled, the container's root user (UID 0 inside the container) maps to an unprivileged user ID on the host. So even if a process escapes the container, it lands on the node as an unprivileged user. It's not root. The blast radius of a container escape drops significantly.
spec:
hostUsers: false # enable user namespaces
containers:
- name: app
image: myapp:latest
securityContext:
runAsNonRoot: true
Test before rolling out broadly
Not every workload supports user namespaces cleanly. Some filesystem operations make assumptions about UID mappings that break under user namespaces. Workloads that need to bind privileged ports, interact with host resources, or use certain volume types may behave unexpectedly. Roll this out incrementally — stateless low-risk workloads first.
SELinux volume mounting GA¶
This one's a performance win, and if you're running SELinux-enforcing nodes, you've probably felt the pain it fixes without necessarily knowing that's what it was.
Previously, when Kubernetes mounted a volume on a SELinux-enforcing node, it had to recursively relabel every single file in that volume to match the container's SELinux context. Think about what that means for a large persistent volume — maybe tens of thousands of files. Kubernetes would walk every one of them at pod startup time, applying labels. On a busy node with large volumes, this could add minutes to pod startup. Minutes.
Now, with mount-time labelling going GA, Kubernetes applies the SELinux label at the mount level rather than file-by-file. The volume gets the right context in one operation, and your pods start fast.
Free performance improvement — no config change needed
If you're running SELinux-enforcing nodes and your pods were slow to start, this is probably why, and now it's fixed. No config changes needed; this behaviour is on by default in v1.36. For teams that have been tuning pod startup budgets around this limitation, you can revisit those numbers.
DRA device taints/tolerations (beta)¶
Dynamic Resource Allocation is Kubernetes' newer model for allocating specialised hardware — GPUs, FPGAs, custom accelerators, network cards with specific capabilities. It's a more expressive replacement for the older device plugin model.
In v1.36, device taints and tolerations reach beta. The mental model is deliberately the same as node taints and tolerations — if you already understand how to taint a node and write a toleration for it, you understand this. The difference is you're now applying that model to individual devices rather than whole nodes.
In practice: you can mark a GPU as "reserved for training jobs" with a device taint, and only pods that declare the matching toleration will be allowed to schedule onto it. This gives you much finer-grained control over expensive or specialised hardware. No more relying purely on resource requests and limits to manage contention — you can express scheduling intent directly at the device level.
Apply this if you manage GPU workloads
Beta means this is ready for broader testing, but the API can still change before it stabilises. If you're managing GPU workloads at any scale, it's worth getting familiar with DRA device taints now — the model is cleaner than device plugins and this is where the ecosystem is heading.
What to ignore for now (alpha features)¶
Two things in v1.36 that look interesting but aren't ready for production: Pod-level Resource Managers and Memory QoS tiered protection.
Pod-level Resource Managers extends the kubelet's topology, CPU, and memory managers to pod-level specs — useful for latency-sensitive workloads that need NUMA-aware or cache-aligned resource allocation. It's alpha. The API will change, the behaviour will change, don't build anything critical on it yet.
Memory QoS tiered protection adds new observability metrics and tiered memory protection for cgroups v2 nodes. Also alpha, also in flux. Keep an eye on both of these across the next couple of releases — they're solving real problems — but give them time to stabilise.
The externalIPs deprecation¶
Short callout, because it'll bite you quietly: the externalIPs field on Services is deprecated in v1.36.
ExternalIPs let you assign a specific external IP address directly to a Service, bypassing the LoadBalancer type entirely. It's a blunt instrument that was used in bare-metal and on-premises setups where you didn't have a cloud load balancer to provision. If you're using it — check your Service manifests — start planning a migration to LoadBalancer type or, if you're moving toward Gateway API anyway, Gateway routes. It's not removed yet, but deprecated means the clock is running.
Frequently asked questions¶
Do I need to be on v1.36 to migrate off ingress-nginx?
No. The ingress-nginx retirement is independent of the Kubernetes release. You can migrate to the F5/NGINX fork or to Gateway API on v1.34 or v1.35 today. Don't let the Kubernetes upgrade timeline delay your ingress migration — the CVE exposure exists right now, on whatever version you're running.
How do I know if user namespaces will break my workloads?
The honest answer is: test it. There's no reliable static analysis that tells you whether a given workload will have issues with UID remapping. The most common failure modes are workloads that write files to shared volumes and expect specific UID ownership, and workloads that use privileged capabilities in ways that assume host-level UID mappings. Start with stateless, low-risk workloads in a test environment, observe any filesystem permission errors or capability failures, and expand from there.
We're on EKS or GKE — will they handle the ingress-nginx migration for us?
Managed Kubernetes providers won't migrate your ingress controller for you — ingress-nginx is something you installed and manage, not something the provider runs on your behalf. What they will do is continue to support the Kubernetes versions that ingress-nginx runs on, and they offer alternatives (AWS Load Balancer Controller on EKS, Google Cloud's ingress on GKE) that are actively maintained. The migration decision and execution is yours.
What's the safest upgrade path from v1.34 or v1.35?
One minor version at a time. Kubernetes doesn't support skipping minor versions in upgrades, so v1.34 → v1.35 → v1.36. For each step: review the release notes for deprecated APIs, check your manifests against the deprecation warnings, upgrade a non-prod cluster first, validate workloads, then roll forward. If you're using managed Kubernetes, your provider's upgrade tooling handles the control plane; you still need to manage node pool upgrades and validate your workloads at each step.
Is Gateway API ready to replace ingress-nginx in production today?
Yes, for most use cases. Gateway API has been GA since Kubernetes 1.24 and the major ingress controller implementations (Cilium, Envoy, NGINX) all support it. The migration effort is real — HTTPRoute is a different resource model from Ingress — but the destination is stable and actively maintained. If you're greenfield, start with Gateway API. If you're migrating, consider the F5/NGINX fork as an intermediate step to buy time.
What you get in v1.36¶
- ingress-nginx retirement forces a decision — and the alternatives (F5 fork, Gateway API, Cilium) are all in good shape
- User Namespaces GA — a meaningful security improvement for multi-tenant clusters, ready for production use
- SELinux volume mounting GA — pod startup performance on SELinux-enforcing nodes, fixed properly at the mount level
- DRA device taints/tolerations in beta — fine-grained GPU and accelerator scheduling, ready for broader testing
- 70 enhancements total — 18 stable, 25 beta, 25 alpha — a genuinely substantial release once you've dealt with the ingress situation
Further reading¶
- Kubernetes v1.36 Release — full release announcement with the complete changelog
- ingress-nginx Retirement — the official announcement explaining the decision and timeline
- User Namespaces GA — deep dive on the feature, caveats, and how to enable it safely