Kubernetes 1.20.5 fixes stale UDP NodePort connection tracking
Kubernetes 1.20.5 corrects when kube-proxy clears UDP connection tracking entries. Installing valid rules was insufficient while an earlier flow entry could keep traffic from reaching a Service.
A UDP NodePort could stop forwarding traffic even after kube-proxy installed the correct iptables rules. An earlier packet could create a connection tracking entry before the Service was ready. That entry then prevented subsequent traffic from following the newly installed forwarding configuration. Kubernetes 1.20.5 corrects the order of operations that allowed the stale state to survive.
The 1.20.5 release, published on 18 March, includes this kube-proxy fix. Its implementation and regression test explain why the timing matters. Clearing old state while adding a NodePort was insufficient if packets arrived before forwarding rules or usable endpoints existed.
I find this kind of bug especially relevant to Kubernetes' reconciliation model. A controller can install the right desired configuration while older runtime state continues to produce the wrong result. Correct reconciliation needs to include the state that actually determines what happens to the next packet.
The failing sequence
The pull request describes two problems in the old cleanup behavior. kube-proxy cleared UDP NodePort connection tracking entries before programming iptables rules. It also associated the cleanup with adding the NodePort without accounting for whether the Service had endpoints.
Consider a packet arriving during that interval. The NodePort exists as a destination, but the forwarding configuration is not yet ready to send traffic to a backend. Connection tracking can record a flow under those conditions. Installing the desired iptables rules afterwards does not itself remove the entry that the packet already created.
The author reports a diagnostic distinction in the investigation. A parallel connection through the ClusterIP worked, showing that the Pods and Service could handle traffic through that route. Traffic through the NodePort failed despite correctly installed iptables entries. The reported NodePort entry was marked unreplied, which helped identify the stale flow as the cause.
This is a narrower failure than saying that Kubernetes Services were broken. It concerns UDP NodePort handling in the iptables proxier. The evidence separates the availability of the application endpoint from the state associated with the particular NodePort path.
Cleanup moves after rule installation
The patch collects NodePorts requiring cleanup while kube-proxy processes Service and endpoint updates. In particular, it considers a UDP Service stale when its endpoints change from zero to a nonzero count. That transition provides a useful point to remove flow state created while no backend was available.
Actual cleanup now runs in the housekeeping portion of the rule synchronization function, after iptables programming. The code clears the collected Service IP entries and then clears the collected UDP NodePort entries. By that point, new traffic has the forwarding rules needed to reach the available endpoints.
The order closes the earlier interval between cleanup and rule installation. Clearing an entry before the rules exist permits another packet to recreate the problematic state immediately. Deferring the deletion until after rule programming changes the conditions under which the next packet encounters the Service.
Endpoint availability is equally important. Creating a Service object does not imply that a usable endpoint already exists. Performing the cleanup only at Service creation misses state accumulated before the endpoints arrive. The patch explicitly connects cleanup to that later transition.
None of this changes the application's UDP protocol or requires an application-level retry policy. The repaired behavior is in kube-proxy's management of node networking state. The application can remain healthy throughout the failure while the NodePort path fails to forward its packets.
The regression test follows endpoint arrival
The added test creates a UDP Service with a NodePort and initially supplies no endpoints. After synchronizing proxy rules, it requires that kube-proxy has executed no connection tracking cleanup commands. This establishes that Service creation alone is no longer the relevant trigger.
The test then adds an endpoint and synchronizes again. It expects two cleanup commands, covering the ClusterIP and the NodePort. Their arguments identify the Service destination IP in one case and the UDP destination port in the other.
Those assertions matter because the two routes can behave differently during the original failure. Verifying only ClusterIP cleanup would not establish that stale NodePort entries had been handled. The test explicitly checks the additional port-based operation introduced by the fix.
The test uses a fake command executor, so it verifies kube-proxy's chosen operations without claiming to reproduce every kernel networking condition. The investigation described in the pull request supplies the packet-path evidence. Together, the code and test make the intended correction more specific than the short maintenance note.
What this patch contributes
The 1.20.5 changelog includes other maintenance work, including accounting for Pod overhead in ResourceQuota and reducing spurious Secret or ConfigMap list errors in kubelet logs. These fixes concern different parts of the system. The NodePort correction is useful because it exposes a precise dependency between rule installation and stale-state removal.
My confidence in reconciliation comes from implementations that handle these dependencies explicitly. Here the relevant desired state includes a Service with available endpoints, and the corrective action includes removing UDP flow entries that can contradict the installed rules. Kubernetes 1.20.5 aligns that cleanup with the point at which the forwarding configuration can handle subsequent traffic.