agent: addresses annotation replaces IPAM allocation
Build flock Image / build (push) Successful in 5m27s
Build flock Image / build (push) Successful in 5m27s
When flock.fritzlab.net/addresses provides a v6 or v4, the IP becomes the pod's primary IP for that family — bound to eth0, default route off it, on-link host route via setHostRoute, and a per-pod /128 or /32 in BGP. IPAM no longer allocates a private IP alongside it. The pod ends up with exactly the operator-supplied addresses on eth0 (plus any extras beyond the first-of-family, which keep the pre-existing layered behavior). This is the fix the original addresses-annotation work missed: bug #1 allocated a private IP next to the public one (so VPN-routed clients could land on the private path on Plex). Promoting addresses-supplied IPs into the IPAM-style routing slot keeps the public IP as the only primary IP visible from outside. Three pieces: - annotations.go: reject pods whose addresses/anycast IP family is disabled (ipv6/ipv4 annotation or NodeConfig default). Both annotation types rely on the family being enabled for return-path routing. - handlers.go: peel first v6 + first v4 from Addresses into res.IP6/IP4; suppress IPAM for those families; skip IPAM call entirely if both families are addresses-supplied. - anycast_linux.go: extend renderBird to advertise any IPAM IP that's outside the node's BGP aggregate as a per-pod /32 or /128. This is what makes 142.202.202.166 reachable when host004's pod CIDR is 172.25.214.0/24 — the addresses-promoted IP isn't covered by the aggregate. Tests: 7 new annotation tests covering the conflict cases (ipv4=false + addresses-v4, NodeConfig default + addresses-v4, etc.) plus 5 unit tests for the splitAddressesPrimary helper. README updated with the addresses-replaces-IPAM behavior, the addresses-vs-anycast comparison, the conflict rule, and a Plex-style example. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -176,12 +176,48 @@ optional; leave them off to inherit the per-node defaults.
|
||||
| `flock.fritzlab.net/cidr4` | CIDRs | Restrict IPv4 allocation to a sub-range of the node's `cidr4`. Comma-separated. |
|
||||
| `flock.fritzlab.net/ip-algo` | list | Embed identity into the IPv6 IID. Subset of `namespace,pod,image`, in order, comma-separated. |
|
||||
| `flock.fritzlab.net/anycast` | IPs | Bind these IPs on the pod's `lo`; advertise via BGP while pod is `Ready`. Mixed v6+v4 ok. |
|
||||
| `flock.fritzlab.net/addresses` | IPs | Bind these IPs on the pod's `eth0`. The first v6 and first v4 **replace** IPAM allocation for that family — the addresses IP becomes the pod's primary IP. Mixed v6+v4 ok. Single-replica only in practice. |
|
||||
|
||||
Bool values must be the literal strings `"true"` or `"false"`
|
||||
(case-insensitive, surrounding whitespace tolerated). Other values —
|
||||
`1`, `0`, `yes`, `no` — are rejected so a typo can't silently flip
|
||||
behaviour.
|
||||
|
||||
### `addresses` vs `anycast`
|
||||
|
||||
Both annotations bind operator-supplied IPs onto a pod and have flock
|
||||
advertise `/128` (or `/32`) per-pod over BGP. The differences are
|
||||
where the IP lands and what it's for:
|
||||
|
||||
| | `anycast` | `addresses` |
|
||||
|----------------------------|----------------------------------------------------|-------------------------------------------------------------------|
|
||||
| Bound on | pod `lo` | pod `eth0` |
|
||||
| Multi-replica? | yes — every Ready replica advertises the same IP and the upstream router ECMPs across them | no — the same IP on multiple replicas is operator error |
|
||||
| Replaces IPAM? | no — pod still has an IPAM-allocated unicast IP | **yes** — the first v6 + first v4 in the list become the pod's primary IPs in place of an IPAM allocation |
|
||||
| Workload visibility | only the IPAM IP is on the primary interface | the public IP is `eth0`'s primary address — workloads that read their own NIC see it (e.g. Plex's remote-access detection) |
|
||||
|
||||
Use `anycast` for shared services with many replicas (DNS, ingress).
|
||||
Use `addresses` when one specific pod needs a known public IP that the
|
||||
workload itself must see on its primary interface.
|
||||
|
||||
### Conflict detection
|
||||
|
||||
`addresses` and `anycast` reject pods that supply an IP whose family is
|
||||
disabled. If the resolved `WantV4` is false (via the pod's `ipv4`
|
||||
annotation or the NodeConfig default) and any addresses- or
|
||||
anycast-supplied IP is IPv4, the CNI ADD fails with an explicit error.
|
||||
Same for v6. Both annotation types put IPs on a pod interface and rely
|
||||
on the family being enabled for return-path routing — silently accepting
|
||||
the IP would leave a non-functional pod.
|
||||
|
||||
### Outside-aggregate advertisement
|
||||
|
||||
When an `addresses` IP replaces IPAM (becomes the pod's primary IP) the
|
||||
IP is typically **outside** the node's BGP aggregate (e.g. a public
|
||||
`/32` on a node whose pod CIDR is private). flock notices this during
|
||||
BGP rendering and advertises the IP individually as a per-pod `/32` or
|
||||
`/128` so the upstream router has a route to it.
|
||||
|
||||
### Example pods
|
||||
|
||||
Default dual-stack — no annotations needed:
|
||||
@@ -239,6 +275,29 @@ spec:
|
||||
failureThreshold: 1
|
||||
```
|
||||
|
||||
Workload with a known public IP — single-replica pod whose application
|
||||
inspects its own primary interface (Plex's remote-access flow). The
|
||||
addresses become the pod's primary IPs in place of any IPAM allocation;
|
||||
the pod's `eth0` ends up with exactly the supplied addresses, and BGP
|
||||
advertises them as a `/128` and `/32`:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: plex
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
flock.fritzlab.net/addresses: "2001:db8:c606::166, 192.0.2.166"
|
||||
spec:
|
||||
containers:
|
||||
- name: plex
|
||||
image: plexinc/pms-docker
|
||||
```
|
||||
|
||||
## Use cases
|
||||
|
||||
**Highly-available DNS.** Run N CoreDNS replicas, each annotated with
|
||||
|
||||
Reference in New Issue
Block a user