images / images (push) Successful in 18m34s
EgressService (reweave.levk.dev/v1alpha1, named after a LoadBalancer Service of class reweave.levk.dev/node-address) makes every pod the Service selects (by pod IP, never readiness) leave the cluster from the Service's address, or not at all. spec.emit is explicit: Holder (the only mode so far) tunnels members' packets to the node holding the address, which emits them. The holder (S1's: the one node with the address on an interface) is the status' sole writer: host, address, and a 512-port block per node in 61000-65535 (above the default ephemeral range), stable across churn. A member's node SNATs it to address:its-block before it leaves, so the holder forwards it unchanged and routes replies back by port alone: ip rules (to address, ipproto tcp/udp, dport block) ahead of the local table, which moves from 0 to 100, since the address is local on the holder. Members' packets travel both ways in reweave-eg, an ipip tunnel between weave bridges (NPC drops new routed packets into weave), with accept_local and loose rp_filter on that device only. Members' new connections are classed at the tail of nat PREROUTING, after kube-proxy's DNAT has ended the nat walk for Services: the pod network, multicast and the nodes' addresses are not outside. Marked packets follow a per-member rule to the holder's table (or to an unreachable one), are SNATed into the tunnel, and a FORWARD guard drops anything else a member sends outside (other protocols, other ways out). The tunnel is accepted only from the nodes' bridges, a holder accepts from it only the blocks' ports, and TCP MSS is clamped into it. Fail closed throughout: until the holder has published the status, without a block, with no single holder, or for a pod two EgressServices select, a member's outside traffic is dropped. The CNI plugin asks weave-npc to admit every pod (unix socket /run/weave-npc/egress.sock, conflist "egressAdmission": true, now rewritten when it differs) after IPAM and before the pod has an interface, so a member's first packet already leaves from the address; no answer, no pod. weave-npc applies nothing about egress from caches that are not synced (unless the API is absent): a restart never strips members' rules. reweave/test/egress/run.sh checks the design's assertions against a live cluster; both end-to-end scripts now re-evaluate each check on every retry (it was expanded once, before the loop). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UHXzGrsxfkGk8LmwrBbHNZ