February 28, 2025·5 min read·engineeringkubernetesnetworkingnftables

What nftables changes in Kubernetes Service proxying

Native nftables changes both Service lookup and the cost of programming updates. Its migration also changes NodePort defaults and requires compatible node networking.

The number of Services in a cluster should not determine how many unrelated destinations a new connection must be checked against. The iptables implementation of kube-proxy has exactly that scaling problem. Its top-level dispatch chain tests Service addresses sequentially, so the position of a Service in the chain affects the work needed to find it.

Dan Winship's February 28 explanation of nftables mode describes a different representation. Native nftables dispatch uses a verdict map indexed by the destination address, protocol and port. The change replaces a linear search through Service rules with a roughly constant-time map lookup. It also changes how kube-proxy submits updates when endpoints change.

I like Kubernetes for its reconciliation model, and this is a useful example of why the mechanism beneath reconciliation matters. Converging declared state is less useful if each small change requires work proportional to a large collection of unrelated state. The nftables backend reduces that coupling at the node.

Changing the representation of a Service

In iptables mode, a packet traverses rules that compare its destination with individual Services. A matching rule transfers processing to the chain for that Service. The total configuration includes endpoint rules too, but Service dispatch alone grows with the number of Services. Winship scopes the resulting latency discussion to the first packet of a new connection, which is the relevant boundary for interpreting his measurements.

The nftables representation constructs a tuple and looks it up in a map. A matching map entry supplies the verdict that directs further processing. Adding a Service adds map data without requiring a longer sequence of destination comparisons for every other Service. The distinction is between the size of the stored configuration and the work needed to select an entry.

The overall configuration still grows with the number of Services and endpoints. A constant-time lookup does not imply constant memory consumption or remove the endpoint configuration. It describes the dispatch operation. That narrower claim explains the improvement without implying that cluster networking becomes independent of cluster size.

The historical version of KEP-3866 also explains why a distribution using the nftables-compatible iptables binary does not provide the same result. That binary preserves the iptables command interface. It cannot express native nftables maps through syntax that has no map operation, so changing the kernel API beneath the command does not redesign kube-proxy's rules.

This is a significant distinction for an inventory. A node can use nftables infrastructure while kube-proxy still operates in iptables mode. The backend selected by kube-proxy determines the Service representation discussed here.

Endpoint churn has a separate cost

Packet dispatch is only one source of scaling pressure. Kube-proxy must also update the node configuration as Services and endpoints change. The February article describes earlier improvements beginning in Kubernetes 1.26 that avoid rewriting many unchanged iptables rules. Those improvements reduce the constant cost, but the iptables-restore interface still requires updates whose size grows with the Service count.

Native nftables permits incremental changes. Kube-proxy can submit work proportional to the Services and endpoints changed since the last synchronization. Each nftables user can also have a private table, avoiding the global lock contention associated with iptables users.

These improvements address different operational symptoms. Faster dispatch reduces connection setup overhead. Smaller updates reduce the work of bringing the node's forwarding configuration into agreement with API state. A cluster can care about endpoint churn even when its steady-state connection latency is acceptable.

The KEP says the new mode retains kube-proxy's Service and EndpointSlice monitoring code. It changes the local processing of that information without introducing a new Kubernetes API type or new cloud-provider calls. The feature therefore improves the node implementation while preserving the source of desired Service state.

I find that scope appealing. It improves an established contract without asking application authors to replace their Service objects. The migration burden belongs primarily to the people responsible for node networking and its integrations.

Opting in includes different behavior

Nftables mode began as alpha in Kubernetes 1.29 and is beta at this publication. The February guidance expects general availability in 1.33, but explicitly says that iptables will remain the default for compatibility. A planned graduation is not an announcement that the default has changed.

For Kubernetes 1.31 and later, the article gives a command-line selection for the backend. The following is the relevant argument to an existing kube-proxy invocation, not a complete node deployment command.

--proxy-mode nftables

The corresponding field in an existing kube-proxy configuration is similarly small. The surrounding configuration still needs to match the installation.

mode: nftables

The behavioral differences are more substantial than the configuration edit. In nftables mode, NodePorts default to the node's primary addresses. Iptables mode exposes them on a broader set of local addresses, including the localhost behavior discussed in the article. A client using 127.0.0.1 to reach a NodePort therefore relies on behavior that does not carry over.

The project deliberately uses the opt-in backend to change defaults that would be disruptive to existing iptables users. This means that preserving Service definitions does not establish that every existing access path is preserved. Node address selection is part of the migration contract.

The published prerequisites include a Linux kernel of at least 5.13. Winship also warns about host installations of the nft command older than 1.0.0, because early tool bugs can cause interference between nftables users. Network plugins and monitoring software require separate attention where they inspect or manipulate kube-proxy's existing rules.

Switching modes preserves a local boundary

The guidance allows an existing cluster to switch by changing configuration and restarting kube-proxy pods. A node reboot is unnecessary. When a supported kube-proxy starts in the new mode, it cleans up the old backend's rules, and the reverse switch cleans up nftables rules.

The KEP explains why different nodes can run different proxy modes during a rollout. Kubernetes Service proxying does not require a node to understand the implementation on another node. That supports a node-by-node transition, while also keeping the cleanup requirement local to the node whose implementation changes.

Rolling back to a much older kube-proxy requires more care because an implementation that predates nftables cannot know how to remove its rules. The KEP explicitly distinguishes this from switching modes with a version that understands both implementations. Leaving stale forwarding rules behind would preserve interception after the process responsible for those rules has changed.

The same proposal records the maintenance cost of adding another supported backend. Replacing older backends is outside its immediate scope. As of this publication, the concrete result is an opt-in Service implementation with incremental updates and map-based dispatch, accompanied by explicit compatibility differences that affect how node traffic reaches the same Services.