Skip to content

docs: propose IP classes for workload address allocation - #210

Open
scotwells wants to merge 15 commits into
mainfrom
docs/ipam-integration
Open

docs: propose IP classes for workload address allocation#210
scotwells wants to merge 15 commits into
mainfrom
docs/ipam-integration

Conversation

@scotwells

Copy link
Copy Markdown
Contributor

Summary

Proposes how a consumer asks for address space when deploying a workload: they name a class of address on a network interface — public-unicast-ipv4, tenant-endpoint-ipv6 — and the platform returns one in the create response and tracks it from that moment until release. No pool, prefix length, region, or CIDR appears in a consumer manifest. Operators define what each class means once, and can change what backs it without touching anyone's workload.

The capability this unlocks is small to describe: an address a workload keeps. A published endpoint that survives a redeploy, a stable outbound address a customer can allowlist, an inventory an operator can query.

What's in the document

  • Class configuration — the fields an operator authors, including inheritance (parentClassName), how many allocations exist (allocationScope), and how far the allocator looks before handing an address out (collisionDomain).
  • Address families — why a class is single-family, and why the interface names families while the platform resolves a class per family. IPv4 and IPv6 tenant endpoints differ in parent, collision domain, and hierarchy, not just size.
  • Where the claim is made — one central allocator; claims originate at the location the workload was placed at, since that is the system that knows the location, the network, and the family. Includes the outage trade this accepts.
  • Instance addresses — every address on an instance becomes a real allocation, reversing the current arrangement where the runtime picks and the platform records afterwards. That reversal is what makes retention and quota possible.
  • A worked example — one workload, one network, two locations, dual-stack, a public address per instance: every object that exists and which control plane it lives in.

Notable for compute

  • networkInterfaces[].ipFamilies, .reclaimPolicy, and .addresses[].class are the three new fields on the workload spec.
  • An interface reports Allocated and Programmed as separate conditions, because allocation is synchronous and programming is not.
  • Retention binds to an instance's unique identity rather than its name, since instance names are composed and reused.

Status

Draft, for discussion. A What this depends on section lists what allocation alone does not provide — network routing identity, route withdrawal on instance moves, per-node endpoint state limits, subnet programming, and public-address paths — so the boundary is explicit rather than assumed.

Consumers name a class of address on a network interface -- public,
tenant, IPv4, IPv6 -- and the platform returns one in the create
response and tracks it until release. No pool, prefix length, region,
or CIDR appears in a consumer manifest.

Covers class configuration and inheritance, per-family resolution,
where claims are made in the federated topology, instance address
allocation, and a worked two-location example.
Status lives in the frontmatter rather than being repeated in the body.
Replaces the single related-doc line with a References section covering
the addressing plans this draws on and the systems holding each piece,
and links descriptively from the passages that depend on them.
Replaces allocationScope and collisionDomain, two closed enums over
network and location, with identity and uniqueWithin -- lists of opaque
scope references the allocator indexes without interpreting. The enums
needed a new value for every kind of thing that can hold an address,
which put node and site concepts inside the allocator; the reference
lists carry sites, nodes, and links unchanged.

Separates the two questions the enums had merged: identity decides
whether a claim gets a new allocation or an existing one, uniqueWithin
decides whether two allocations may hold the same address.

Reservations now produce real allocations held by the parent, so
reserved space has an owner and appears in inventory rather than being
a hole, and a reservation need not sit at the edge of its parent.

Splits retention's identity in two: the slot the allocation is
identified by, which survives replacement, and the instance holding it,
which does not -- previously one identity was asked to do both.
Flow mappings and sequences read as shorthand and hide field structure.
Every manifest now uses one key per line, with comments moved above the
fields they describe rather than trailing them.
Removes the class field that named what identifies an allocation. A
claim binds one allocation and records it, so nothing needs to re-derive
which allocation a claim should get -- the claim object is the identity,
as it is for PersistentVolumeClaim.

Retention follows: an address survives a redeploy because the claim is
named for the slot and outlives the instance, not because anything
rematches a released address. That removes the window where the address
is loose and the second identity introduced to match on. Notes the
Released state as the part of the storage model not to copy.

Container classes keep a narrower poolPer key, since provisioning one
pool per network and location is a real constraint and is not about
claims at all.
Applies the Google technical writing guidelines to the IP class proposal.

Splits multi-idea sentences so each carries one thought, and cuts the
filler and hedging around them. Converts four embedded lists that were
buried in prose -- the two pool fields, the two concurrency rules the
cascade needs, the three rules the allocator enforces, and the two
consequences of the claim outliving the instance -- into real lists.

Replaces ambiguous "it" and "that" with the noun they refer to, which
was the most frequent problem: several paragraphs opened with a pronoun
whose referent was two sentences back. Prefers active voice and a real
subject over "there is" constructions.

States the audience up front, and drops the restatement of the IPv4 and
IPv6 difference in the worked example, which the address families
section already makes.

No design changes.
Merges the two items that stated the same dependency -- a subnet's
record being written without the gateway, forwarding instance, or
route-table entry being provisioned -- into one, and drops the
restatement of why reservations produce a real allocation, which the
reservations field already covers.

Converts the remaining seven to a list, since the section is an
inventory of assumptions rather than an argument that builds.
Drops the User Stories section. Its six stories restated the five goals
almost one for one; the only capability they carried that Goals did not
-- re-backing a class by attaching a pool and draining the old one --
moves into Goals.

Collapses the storage analogy to one statement. It was made five times:
in the class field comment, in the claim name and address comments, in
the section that explains binding, and again in Alternatives. Only the
binding section needs it, and the volumeName parallel now sits beside
the field it describes.

Cuts the paragraph redefining pool and allocation, which the terminology
list above it already defines, and shortens the three Alternatives
entries that re-argued the body at full length while the other five were
one-liners.

No design changes.
Replaces "One allocator, in the middle, for everything. Not a copy per
location." The second sentence pre-announced the paragraph directly
below it, which introduces the per-location alternative and spends six
lines rejecting it. And "in the middle" gestured at a call path it
never stated.

The lead now says where an address comes from, which is what the section
is titled.
Replaces "How a claim finds its allocation. It does not look one up."
The label asked a question the next fragment answered only by negation,
and that fragment leaned on two pronouns whose referents were both in
the label rather than the sentence.

The lead now states the rule as an assertion, and the point that nothing
recomputes the pairing follows it instead of preceding it. Updates the
field comment that pointed at the old wording.
Applies the same fix to five more passages that named a topic and then
made the reader assemble the claim.

Two labels posed a question the text answered only by example or by
restating the label: what uniqueWithin means, and what a claim carries.
Both now state the rule. Drops the 'Note what a parent is' preamble and
the 'State the trade plainly' imperative, and attaches a noun to the
'This' that opened the paragraph on reversing who picks an address.
The body and Alternatives were making the same case twice. The section
on where an address comes from listed a database per location, two
sources of truth, and the loss of platform-wide inventory -- which is
the Alternatives entry almost word for word. It now keeps only the
argument Alternatives does not make: the volume that would justify
per-location allocation is not ours, because pod addresses belong to
container networking.

Class health loses the same duplication, keeping the reason in one
sentence rather than three.

Address families now opens with the asymmetry between the two families
rather than with the single-class option it rejects, since the asymmetry
is the reason for the design and the rejection follows from it.
The case against a per-location allocator rested on pod addresses
belonging to container networking. There are no pods here, so the
argument was borrowed rather than true: it described a Kubernetes CNI
deployment, not this one.

The real argument is already established twice in the document -- the
unit is the interface, and an instance assigns its containers from the
block its interface holds. So the control plane sees a few claims at
instance creation and none during steady state, which is the rate that
matters.
An address is claimed once for a slot and stays with it, so replacing,
rescheduling, or redeploying an instance allocates nothing -- the
replacement finds a claim that already holds its address. Instance churn
therefore does not become claim churn, and allocation happens only when
a slot first appears.

This is what the retention design already says; the section on where an
address comes from was arguing rate without it, first from pod
networking and then from per-interface counting. Both missed that the
mechanism keeping an address stable for a consumer is the same one
keeping churn away from the allocator.

Narrows the outage trade to match. A location cut off from the center
can still replace and reschedule instances in existing slots, which is
the path that matters during a failure; what pauses is scaling up and
deploying something new.
A claim ends when its slot does, and the document only said that for
workload deletion. A scale-down removes slots too, so under the default
Delete policy scaling back up allocates different addresses; Retain is
what makes a restored slot reclaim what it had.

This also corrects the opening example, which labelled reclaimPolicy:
Retain as what keeps addresses across redeploys. A redeploy keeps them
either way, since it never deletes the claim -- the field comment on
reclaimPolicy already said so, and the example contradicted it.

Qualifies the claim-rate argument to match: most instance churn does not
reach the allocator, but a slot returning after a scale-down does unless
its address was retained.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant