v1.19.7: intermittent pod to ClusterIP (kube-apiserver) timeouts on native routing with kube-proxy-replacement=false, node-dependent
Is there an existing issue for this?
- I have searched the existing issues
This looks like it may share a root cause with #48178 (post-#47204 regression with kube-proxy-replacement=false), but that report is explicitly scoped to tunnel/overlay clusters and states the #45252 fix "resolves the regression for native-routing clusters". This report is a native-routing cluster, so it is filed separately as a distinct data point rather than as a comment there.
Version
equal or higher than v1.19.7 and lower than v1.20.0
What happened?
After upgrading a GKE cluster from Cilium 1.18.10 to 1.19.7, pods began experiencing intermittent TCP timeouts to the default/kubernetes ClusterIP. The failure is node-dependent: 2 of 4 nodes were affected, the other 2 were completely clean.
The service in question is the standard kube-apiserver ClusterIP, whose only backend is the GKE control plane endpoint, which lives outside the cluster in the node subnet:
ID Frontend Service Type Backend
76 10.72.96.1:443/TCP ClusterIP 1 => 10.72.0.46:443/TCP (active)Note the address layout, which may be relevant given #47204 changed which frontends are programmed when KPR is off. In this cluster the node subnet contains all of: node IPs (10.72.0.12, .18, .64, .72), the control plane endpoint (10.72.0.46), and the VIPs of four internal LoadBalancer services (10.72.0.49, .63, .66, .67, all externalTrafficPolicy: Cluster). Those LoadBalancer frontends do appear in cilium-dbg service list, with ID 0.
Observed failure rates from a fresh pod on each node, 8 attempts each, curl to https://kubernetes.default.svc/version with the ServiceAccount token and cluster CA:
| Node | Cilium 1.19.7 | Cilium 1.18.10 (after rollback) |
|---|---|---|
| A (10.72.0.12) | 8/8 OK | 8/8 OK |
| B (10.72.0.18) | 8/8 OK | 8/8 OK |
| C (10.72.0.64) | 2/8 OK | 8/8 OK |
| D (10.72.0.72) | 4/8 OK | 8/8 OK |
Both affected nodes returned to 100% success immediately after rolling back to 1.18.10, on the same nodes, same pods, same probe. A second post-rollback round of 10 attempts per node was also 40/40. A separate cluster running 1.16.19 with the same values was 72/72 across 9 nodes.
Real workloads were affected, not just the probe. On node D, external-secrets failed its leader-election lease against the apiserver:
Error retrieving lease lock ... Get "https://10.72.96.1:443/apis/coordination.k8s.io/v1/..."along with reconciler errors in other API-dependent controllers. These errors began ~1 minute after the Cilium agent restarted on that node and stopped when the rollback completed. There were zero such errors in the 90 minutes before the upgrade.
Two things that may help narrow it down:
- No Cilium drops were recorded at all.
cilium-dbg metrics listshowed onlyreason=Unsupported L3 protocol(7 egress / 46 ingress), nothing resembling a service or policy drop.cilium-dbg monitor --type dropwas silent while the failing traffic was being generated. - Datapath programming was identical between an affected and an unaffected node: both had 137 entries in
cilium-dbg service listand 169 incilium-dbg bpf lb list, with the apiserver frontend correctly mapped on both, and no frontend collision on 10.72.0.46.
So from Cilium's own accounting the packets are not being dropped, yet the connection does not complete, which is consistent with the forward and reply paths being split between the BPF path and the host/kube-proxy path as described in #48178.
How can we reproduce the issue?
Not reliably reduced to a minimal repro yet. Conditions present here:
- GKE with
kube-proxy-replacement=falseandcni.chainingMode=portmap(kube-proxy still handling services) - Native routing (
ipv4NativeRoutingCIDRcovering the pod CIDR only),enable-bpf-masquerade=true - A ClusterIP whose backend is outside the cluster and inside the node subnet (the GKE control plane endpoint)
- Internal
LoadBalancerservices with VIPs allocated from that same node subnet
From a fresh pod, repeatedly open new connections to the kube-apiserver ClusterIP. On affected nodes 25-75% of new connections time out. Existing long-lived connections appear unaffected, which is why workload impact lagged the upgrade by hours until pods were rescheduled.
Cilium Version
v1.19.7 (Helm chart 1.19.7). Previously working on v1.18.10.
Kernel Version
6.12.94+ (Container-Optimized OS from Google)
Kubernetes Version
v1.34.9-gke.1610001
Regression
Yes. Worked on 1.18.10 and 1.16.19, broke on 1.19.7. Given #47204 shipped in 1.19.7 and changed which service map entries are programmed when kube-proxy-replacement=false, that is the most likely candidate, as it is in #48178.
Sysdump
Not captured. The cluster was rolled back to restore service before a sysdump or a packet-level trace was taken, so I do not have the cilium monitor -v flow trace or host conntrack dump that #48178 includes. That is the main gap in this report and I want to be upfront about it: the version A/B is strong, but I have no packet-level evidence of the mechanism.
I can re-upgrade a non-production cluster to 1.19.7 to capture cilium monitor -v, host conntrack for the stuck flow, and a full sysdump if that would be useful. Happy to test a patch or a candidate build.
Relevant log output
# Cilium's view of the apiserver service on an affected node (no anomaly visible)
$ cilium-dbg bpf lb list | grep 10.72.96.1
10.72.96.1:443/TCP (0) 0.0.0.0:0 (76) (0) [ClusterIP, non-routable]
10.72.96.1:443/TCP (1) 10.72.0.46:443/TCP (76) (1)
# Drop counters on the affected node while failing traffic was being generated
$ cilium-dbg metrics list | grep drop
cilium_drop_count_total direction=EGRESS reason=Unsupported L3 protocol 7
cilium_drop_count_total direction=INGRESS reason=Unsupported L3 protocol 46Source: cilium/cilium