-
Notifications
You must be signed in to change notification settings - Fork 4
feat(cilium): stage homogeneous wildcard device selection for datapath activation #2697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
4e983cf
chore: claim #2610
devantler bb45a3a
feat(cilium): stage homogeneous wildcard device selection for datapatβ¦
devantler d762635
feat(cilium): gate the homogeneous-devices activation with an OnDeletβ¦
devantler 53f4b5a
docs(cilium): close the OnDelete gate's bypass paths in the activatioβ¦
devantler File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
148 changes: 148 additions & 0 deletions
148
...tzner/infrastructure/controllers/cilium/components/homogeneous-devices/kustomization.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| # Default-off staging component for platform#2029 / platform#2610. | ||
| # | ||
| # Widens Cilium's eBPF device selection from the private-NIC pin | ||
| # (`devices: "enp7s0 eth1"`, enforce-wireguard-strict-mode.yaml) to BOTH NICs | ||
| # on every node via wildcard patterns, so the BPF masquerade program that | ||
| # ebpf-host-routing (#2609) stages can attach to the PUBLIC default-route | ||
| # NICs β pod->internet egress leaves through them, and BPF masquerading only | ||
| # processes interfaces carrying Cilium's eBPF programs. Without this, enabling | ||
| # ebpf-host-routing would disable iptables masquerade while installing no BPF | ||
| # masquerade on the egress NICs: pod traffic would leave with an unroutable | ||
| # pod-CIDR source and external egress would break cluster-wide. | ||
| # | ||
| # WHY WILDCARDS (the homogeneous strategy, live-verified): upstream requires | ||
| # manually listed bandwidth-manager device names to be consistent on every | ||
| # managed node, and this fleet's NIC names are CLASS-heterogeneous β live | ||
| # inventory 2026-07-18 (`talosctl get addresses` + `kubectl get nodes`, all | ||
| # NINE nodes): | ||
| # | ||
| # static nodes (prod-control-plane-2/4/5, prod-worker-1/2/3): | ||
| # public enp1s0 (default route + public IP) / private enp7s0 (10.0.1.x) | ||
| # autoscale nodes (autoscale-cx33-*/cx43-* cattle): | ||
| # public eth0 (default route + public IP + IPv6) / private eth1 (10.0.1.x) | ||
| # | ||
| # Note this INVERTS the 2026-06-19 "workers enp7s0 / control-planes eth1" | ||
| # premise recorded in enforce-wireguard-strict-mode.yaml: the control planes | ||
| # have since been rebuilt onto enp-named machines (confirmed live: all three | ||
| # CP agents report devices=[enp7s0]), and the split is now static-vs-autoscale. | ||
| # Today's two-name pin still covers every node's PRIVATE NIC β but only by | ||
| # UNION (static->enp7s0, autoscale->eth1), each node matching exactly one name. | ||
| # | ||
| # An explicit four-name list ("enp7s0 eth1 enp1s0 eth0") would leave every | ||
| # node with two names that do not exist on it β exactly what upstream's | ||
| # bandwidth-manager consistency guidance forbids. A wildcard pattern list is | ||
| # IDENTICAL on every node and resolves per node to only the devices that | ||
| # exist (upstream documents wildcards for exactly this heterogeneous-naming | ||
| # case). "en+ eth+" matches all four current names, nothing else on these | ||
| # hosts (bond0/dummy0 and Cilium's own cilium_*/lxc* interfaces don't match | ||
| # or are auto-excluded), and also absorbs future autoscaler node-type naming | ||
| # drift (ens*/eno* would still match en+) β retiring the standing WARNING in | ||
| # the strict-mode patch about differently-named private NICs. | ||
| # | ||
| # PRIMARY-ADDRESS RISK β why this stays default-off and activation must | ||
| # prove it per node: the private-only pin exists so each node's PRIMARY | ||
| # address (VXLAN/WireGuard tunnel endpoint, cilium-health, routing β see | ||
| # enforce-wireguard-strict-mode.yaml) stays the private 10.0.1.x that the | ||
| # Talos ingress firewall admits on 4240/4250/8472. Re-admitting the public | ||
| # NICs into the device set re-admits public addresses as primary candidates. | ||
| # Upstream documents that multi-device direct-routing selection prefers the | ||
| # device holding the Kubernetes InternalIP (private here, on every node), but | ||
| # the node-address selection of the running 1.20.0-pre.4 is not documented | ||
| # precisely enough to TRUST that the primary stays private β the 2026-06-19 | ||
| # incident showed device-set changes can flip it. So: activate one node at a | ||
| # time and verify before proceeding (runbook below). Note the SPIRE | ||
| # mutual-auth dial itself is intermittently public-IP-bound REGARDLESS of | ||
| # this selection (upstream cilium/cilium#46767, random node-IP pick); that | ||
| # pre-existing defect is tracked separately and is NOT widened by this | ||
| # component as long as the primary/routing address stays private. | ||
| # | ||
| # ROLLOUT GATE (why this component ALSO sets updateStrategy OnDelete): the | ||
| # base HelmRelease's `rollOutCiliumPods: true` would start an automatic | ||
| # DaemonSet rollout the moment this component is referenced, proceeding to | ||
| # the next node as soon as each updated agent reports Ready β no pause point | ||
| # exists, so the per-node verification below would be unexecutable and a bad | ||
| # primary-address selection could reach the fleet before detection. OnDelete | ||
| # makes the roll operator-stepped: the new config only reaches a node when | ||
| # that node's cilium pod is deleted. The override lives HERE so it applies | ||
| # exactly while the widened device set is being introduced, and its removal | ||
| # (after the fleet is verified) is a strategy-only change that rolls nothing. | ||
| # | ||
| # GATE LIMITS (what OnDelete does NOT stop): a pod that restarts for any | ||
| # OTHER reason during the window (crash, eviction, node reboot) is recreated | ||
| # from the NEW template immediately, and so is the agent on any NODE the | ||
| # cluster autoscaler adds mid-window β OnDelete gates template-driven | ||
| # replacement only. The runbook therefore suspends autoscaler node creation | ||
| # for the window and treats any incidental restart as an involuntary canary | ||
| # to verify at once. | ||
| # | ||
| # ACTIVATION RUNBOOK (separate PR referencing this component; low-traffic | ||
| # window): | ||
| # 0. Suspend autoscaler node creation for the window: | ||
| # `kubectl -n kube-system scale deploy | ||
| # cluster-autoscaler-hetzner-cluster-autoscaler --replicas=0`. The | ||
| # autoscaler is ksail-provisioned (ksail.prod.yaml `autoscaler.node`), | ||
| # not Flux-managed, so the scale-down holds until step 5 restores | ||
| # `--replicas=1`. Confirm the over-provisioning CapacityBuffer headroom | ||
| # is idle enough that no scale-up would have fired. | ||
| # 1. Reference this component in ../../../kustomization.yaml `components:`. | ||
| # Under OnDelete, NO agent restarts yet β the new device set is staged | ||
| # in the agent ConfigMap only. Watch for INVOLUNTARY canaries from here | ||
| # on: any cilium pod that restarts for unrelated reasons now boots the | ||
| # widened set β run step 2's verification on it immediately. | ||
| # 2. Delete ONE node's cilium pod (`kubectl -n kube-system delete pod | ||
| # <cilium-x>`) and verify its replacement before touching the next: | ||
| # agent Ready; its log shows the widened device set (e.g. | ||
| # devices=[enp1s0 enp7s0]) and NO public primary (the node's advertised | ||
| # router/tunnel addresses stay 10.0.1.x β check the agent's | ||
| # node-address/NodeAddress log lines and `kubectl get ciliumnodes`); | ||
| # cilium-health reachability intact; no new policy-verdict DROPs or | ||
| # auth-timeout storms in Hubble/agent logs (a `dial <public-ip>:4250` | ||
| # RATE INCREASE beyond the known #46767 background is a regression). | ||
| # 3. Repeat node by node across all nine; soak. | ||
| # 4. After the soak, a follow-up PR removes the `updateStrategy` override | ||
| # from this component β restoring RollingUpdate is a strategy-only | ||
| # change (the pod template is already current), so it rolls nothing. | ||
| # 5. Restore the autoscaler (`--replicas=1`) and verify the FIRST | ||
| # autoscaler-created node after resume like a stepped node (its agent | ||
| # boots the widened set directly). | ||
| # 6. Only then does ebpf-host-routing (#2609) become referenceable; | ||
| # bandwidth-manager-bbr activation follows its own soak (see those | ||
| # components' guards). | ||
| # ROLLBACK (any point): re-comment the component reference β the template | ||
| # reverts to the private-only pin and RollingUpdate resumes, so every | ||
| # already-stepped node rolls BACK automatically. Un-stepped nodes keep the | ||
| # old config UNLESS their pod restarted during the window (the involuntary | ||
| # canaries above) β those roll back with the stepped ones. | ||
| # | ||
| # MERGE-ORDER NOTE (load-bearing): parent `patches:` are applied AFTER all | ||
| # component patches β a devices value carried by | ||
| # patches/enforce-wireguard-strict-mode.yaml could NEVER be overridden by this | ||
| # component (render-verified on #2610's delivery PR: with this component | ||
| # enabled against a patch-carried pin, the patch value still won). That is why | ||
| # the live pin lives in ../private-nic-devices/ (a component), and why THIS | ||
| # component must be listed AFTER it in the parent's `components:` β components | ||
| # apply in list order, later wins (also render-verified). Do not move either | ||
| # device selection back into a parent patch. | ||
| apiVersion: kustomize.config.k8s.io/v1alpha1 | ||
| kind: Component | ||
| patches: | ||
| - target: | ||
| group: helm.toolkit.fluxcd.io | ||
| version: v2 | ||
| kind: HelmRelease | ||
| name: cilium | ||
| namespace: kube-system | ||
| patch: | | ||
| apiVersion: helm.toolkit.fluxcd.io/v2 | ||
| kind: HelmRelease | ||
| metadata: | ||
| name: cilium | ||
| namespace: kube-system | ||
| spec: | ||
| values: | ||
| devices: "en+ eth+" | ||
| # Operator-stepped rollout gate β see ROLLOUT GATE above. Removed | ||
| # by a follow-up PR once all nodes are verified (strategy-only | ||
| # change; rolls nothing). | ||
| updateStrategy: | ||
| type: OnDelete | ||
66 changes: 66 additions & 0 deletions
66
...tzner/infrastructure/controllers/cilium/components/private-nic-devices/kustomization.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| # ALWAYS-ON component: pin the Cilium eBPF datapath to the PRIVATE-network | ||
| # NICs. This is the live production device selection β it must stay referenced | ||
| # in ../../../kustomization.yaml until homogeneous-devices/ (its staged | ||
| # successor, see below) has been activated and soaked. | ||
| # | ||
| # WHY A COMPONENT AND NOT A PATCH: the staged homogeneous-devices/ component | ||
| # must be able to OVERRIDE this value when referenced. Kustomize applies the | ||
| # parent kustomization's `patches:` AFTER all component patches (verified by | ||
| # render on #2610's delivery PR: a component could not override a `devices` | ||
| # value carried by patches/enforce-wireguard-strict-mode.yaml), while | ||
| # components themselves apply in list order β later wins. Keeping both device | ||
| # selections as components, with the staged one listed after this one, is what | ||
| # makes the flip possible as a one-line reference change. The devices key | ||
| # previously lived in the strict-mode patch; it moved here UNCHANGED, so the | ||
| # rendered HelmRelease is identical and moving it rolled no agents. | ||
| # | ||
| # WHY THE PIN (condensed from the original 2026-06-19 rationale, which lives | ||
| # in git history of patches/enforce-wireguard-strict-mode.yaml): Hetzner nodes | ||
| # are dual-homed. With devices unset, Cilium attaches to BOTH NICs and can | ||
| # take the default-route (public) NIC's IP as the node's PRIMARY address; the | ||
| # SPIRE mutual-auth control connection (agent->agent TCP 4250) then dials peer | ||
| # PUBLIC IPs, which the Talos ingress firewall only admits from the private | ||
| # node CIDR β dropped handshakes black-hole every auth-gated cross-node pod | ||
| # flow (observed live 2026-06-19). Pinning the private NICs keeps each node's | ||
| # primary address private (10.0.1.x), so 4250/4240/8472 ride the admitted | ||
| # path. (A residual upstream defect remains regardless: cilium/cilium#46767 β | ||
| # the auth dial picks a RANDOM advertised node IP, so intermittent public-IP | ||
| # dials persist even with this pin. Tracked separately.) | ||
| # | ||
| # NIC-NAME INVENTORY (live-verified 2026-07-18, `talosctl get addresses`, all | ||
| # NINE nodes β this UPDATES the stale 2026-06-19 "workers enp7s0 / | ||
| # control-planes eth1" premise; the split is static-vs-autoscale now that the | ||
| # control planes were rebuilt onto enp-named machines): | ||
| # static (prod-control-plane-2/4/5, prod-worker-1/2/3): | ||
| # public enp1s0 (default route) / private enp7s0 (10.0.1.x) | ||
| # autoscale (autoscale-cx33-*/cx43-*): public eth0 / private eth1 | ||
| # So this two-name list covers every node's private NIC only by UNION β each | ||
| # node matches exactly ONE of the two names, and the agent logs confirm e.g. | ||
| # devices=[enp7s0] on all three control planes. | ||
| # | ||
| # WARNING (unchanged): hard-codes the private-NIC names. An autoscaler worker | ||
| # on a server type whose private NIC is named differently (e.g. ens*) would | ||
| # lose Cilium networking until its name is added here β keep in sync with the | ||
| # node pool's machine type. The homogeneous-devices/ successor retires this | ||
| # hazard via wildcard patterns. | ||
| # | ||
| # PROD/HETZNER ONLY: the docker/local provider is single-NIC, so device | ||
| # autodetection is correct there. | ||
| apiVersion: kustomize.config.k8s.io/v1alpha1 | ||
| kind: Component | ||
| patches: | ||
| - target: | ||
| group: helm.toolkit.fluxcd.io | ||
| version: v2 | ||
| kind: HelmRelease | ||
| name: cilium | ||
| namespace: kube-system | ||
| patch: | | ||
| apiVersion: helm.toolkit.fluxcd.io/v2 | ||
| kind: HelmRelease | ||
| metadata: | ||
| name: cilium | ||
| namespace: kube-system | ||
| spec: | ||
| values: | ||
| devices: "enp7s0 eth1" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.