Skip to content

feat: give every instance its own network interface - #224

Merged
scotwells merged 3 commits into
mainfrom
feat/112-network-interface-claims
Aug 13, 2026
Merged

feat: give every instance its own network interface#224
scotwells merged 3 commits into
mainfrom
feat/112-network-interface-claims

Conversation

@scotwells

Copy link
Copy Markdown
Contributor

An instance asks for a network interface the way a pod asks for storage. It says what it needs, and gets back the addresses required to bring one up.

What a consumer writes

A workload names a kind of address, and every replica gets one of its own:

networkInterfaces:
  - network:
      name: default
    ipFamilies:
      - IPv6
      - IPv4
    reclaimPolicy: Retain
    addresses:
      - class: public-unicast-ipv4

Nothing here names a subnet, a prefix length, a location, or an address. A consumer names a kind of address and the platform decides the rest.

What they get back

Today an instance prints an address column that is always blank. This fills it in, and with more than one address:

status:
  networkInterfaces:
    - name: eth0
      addresses:
        - family: IPv6
          address: 2001:db8:a001::/96
          primary: true
        - family: IPv4
          address: 10.128.0.2/32
      externalAddresses:
        - family: IPv4
          address: 198.51.100.11

An address a workload keeps

An address is claimed for a slot rather than for the instance filling it, so replacing, rescheduling, and redeploying keep the address. Surviving a scale-down takes Retain.

Event Delete Retain
Instance replaced or rescheduled same addresses same
Scale down then back up new addresses same addresses
Workload deleted then recreated new addresses same addresses

What stops being a problem

Every instance now gets its own addresses. Today one allocation is shared across a whole deployment, so instances cannot be told apart by address.

One instance waiting on an address no longer holds back its siblings — an exhausted pool stalls the instance that hit it, not the deployment.

And when an address cannot be had, the instance says why: an exhausted pool, a family the network does not carry, a project that cannot be resolved. An instance stuck behind an address it never got is a new way to be stuck, and it needs to be legible.

Not on yet

This ships behind the NetworkingIntegration feature gate, which stays off. Nothing changes for anyone until it is turned on.

Readiness waits on the address existing, not on the data plane carrying it — the part that reports traffic is a separate change, and waiting for it today would hold every instance forever.

Related

scotwells and others added 3 commits August 13, 2026 14:54
Ask the network layer for an interface the way a pod asks for storage: an
instance declares what it needs and gets back an object carrying the addresses
required to bring up a NIC.

A workload's network interface gains the fields a consumer needs to say what
kind of address it wants — families in priority order, a reclaim policy, and a
class per additional address — and none that name a subnet, prefix length, or
location. Instance status grows from a single address to the full picture, so
the address column that has always printed blank finally has an answer in it.

Provisioning changes shape. One network binding and one shared subnet claim per
deployment become one NetworkInterfaceClaim per instance per interface, named
from the slot rather than the instance filling it, so a replacement finds a
claim that already holds its address. The scheduling gate that held instances
back becomes per-instance: one instance waiting on an exhausted pool no longer
holds back its siblings.

The gate releases on Bound and Allocated rather than Ready. Programmed has no
data plane reporting it yet, so it stays Unknown and Ready with it; gating on
either would hold every instance forever.

Relates to #112.
The data plane can attach one interface to an instance. Accepting more would
take a declaration the platform cannot honour.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Kubernetes 0.36 and controller-runtime 0.24 bump deprecated two helpers the
repo leans on. Register API types through an apimachinery scheme builder owned
by each API package, keeping the API packages free of a controller-runtime
import, and hash instances through the surviving dump package rather than the
forwarder apimachinery now asks callers to skip.

Also reach for the existing WorkloadDeployment kind constant where a literal had
crept back in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@scotwells
scotwells force-pushed the feat/112-network-interface-claims branch from 25e9e45 to bb566b0 Compare August 13, 2026 19:56
@scotwells
scotwells requested review from ecv, privateip and savme August 13, 2026 20:20
@scotwells
scotwells marked this pull request as ready for review August 13, 2026 20:20
@scotwells
scotwells merged commit 58e8aa5 into main Aug 13, 2026
10 checks passed
@scotwells
scotwells deleted the feat/112-network-interface-claims branch August 13, 2026 21:12
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.

2 participants