Skip to content

Hand over node to the estate path #659

Closed

Description

@ExtraToast

Parent

Rewrite the spec and the compiler in place, release 1.0.0, and hand over every Project

What to build

The node Project leaves fleet-infra and is delivered from the estate repository, in the order #381 sets.

Add a nodeAgents catalog to the estate's Platform document, with locked images for the MetalLB speaker, node-exporter, the GPU device plugin and DCGM, and add node to the handover ledger. Today the estate platform names none, so a render that derives Node Agents is refused with E_NO_NODE_AGENT_POLICY.

The estate-side changes are recorded in the estate repository's HANDOVER.md.

Acceptance criteria

  • The render's diff against the Project's hand-written objects in fleet-infra is clean, or each difference is explained.
  • The Project's Reconcile Units report Ready.
  • A consumer-visible value checks out: Each GPU node advertises its resource, and every node's metrics are scraped.
  • One change flips the handover ledger entry and deletes the hand-written objects, the descriptor and the drift-check entry.

Blocked by

Activity

  1. added
    type: choreMaintenance work without intended behavior change.
    area: platformPlatform, deployment, cluster, or runtime concern.
    priority: P1High; important and should be handled in the current iteration.
    status: blockedCannot move forward until an external dependency is resolved.
    on Oct 27, 2026
  2. ExtraToast commented on Oct 27, 2026

    @ExtraToast
    ContributorAuthor

    Resume here

  3. ExtraToast commented on Oct 29, 2026

    @ExtraToast
    ContributorAuthor

    #380 is closed: delivery, _canary and _estate are on the 1.0 contract (evidence in #380 (comment)).

  4. ExtraToast commented on Oct 29, 2026

    @ExtraToast
    ContributorAuthor

    Prepared, 2026-10-29: four draft PRs, two blockers in deploy-kit

    The window is in JorisJonkers-dev/estate docs/runbooks/node-handover.md (on #261's branch).

    The PRs, in merge order

    1. JorisJonkers-dev/fleet-infra#565, any time before the window. traefik-lan stops naming the pool enschede-lan and asks for its address alone. Otherwise the new controller clears the LAN ingress address, because the render's pool is named lan-edge.
    2. JorisJonkers-dev/fleet-infra#567, the orphan, before the window and after utility's. It is stacked on utility's chain (chore(main): release 0.29.0 #550 to docs: map where one Project's change reaches another, and which operators could carry each job #554), since it marks lan-dns and apps-metallb-lan-dns.
      • It marks 12 objects prune: disabled.
      • It suspends the metallb, nvidia-device-plugin and dcgm-exporter HelmReleases.
      • It sets prune: false on both MetalLB pool Kustomizations.
      • It puts helm.sh/resource-policy: keep on node-exporter's four kube-prometheus-stack objects.
    3. JorisJonkers-dev/fleet-infra#569, the removal, window step 2.
      • The manifests go, with both pool Kustomizations.
      • nodeExporter.enabled: false.
      • The nvidia-cdi RuntimeClass stays, moved under the same name.
      • Two PodMonitors scrape node-system as job="node-exporter" and job="dcgm-exporter".
    4. feat: hand the node Project over to the estate path estate#261, the flip, window step 6, then its release.
      • node moves to estate.
      • metallb.io/v1beta1 joins bootstrap.crds, and bootstrap/cluster.sh gains a stage that adopts MetalLB v0.15.3's CRDs with bgppeers' conversion webhook dropped.
      • nodeAgents memory is sized to live use: dcgm-exporter 1Gi, since it uses about 410Mi and was OOM-killed at 256Mi. The speaker and controller get 128Mi.
      • Every lock digest matches the live pods' imageID.

    Between 3 and 6, by hand:

    • stop the old controller and delete metallb-webhook-configuration, which fails closed and would refuse the render's pools;
    • run cluster.sh stage 5;
    • delete the old device plugin, so two plugins never share nvidia-gpu.sock.

    After 6, by hand:

    • delete metallb-speaker; the new speakers wait on host port 7472, so each node's gap is seconds;
    • then node-exporter (port 9100);
    • then dcgm-exporter, once gpu-metrics is Ready.

    Order against utility

    node goes after utility's window, and #261 is updated from main after JorisJonkers-dev/estate#248 merges, so the render holds lan-dns. Utility also has to have deleted adguard-ha-b and moved the router to .98 alone: the render has no pool for .97.

    The pool move needs no overlap trick. Each controller reads only its own namespace's pools, and the old webhook is deleted before the flip. The new controller finds .98 and .99 already assigned, inside its own lan-dns and lan-edge, and keeps both. Only the speakers change hands, node by node.

    Open blockers

    Render against live

    Every difference is explained in #261's body and the runbook. In short:

    • every agent is a new DaemonSet in node-system;
    • the speaker runs on the five Enschede nodes, not frankfurt-contabo-1, in native L2 mode with no excludel2 list;
    • pools are lan-edge and lan-dns, both autoAssign: false;
    • the device plugin has no config-manager sidecar or MPS;
    • dcgm-exporter uses the image's counters, a superset of the chart's;
    • node-exporter has no textfile collector or probes.

    Validated with deploy-kit 1.2.0, as toolkit.yml names it: CI's validate, every release-matrix entry, a negative E_NO_NODE_AGENT_POLICY and a local deploy-kit compose. Nothing is merged.

  5. ExtraToast commented on Oct 30, 2026

    @ExtraToast
    ContributorAuthor

    node is on the estate path, delivered by estate 0.35.0 on deploy-kit 1.5.0.

    Found in the window:

    • The new speakers started beside the old ones instead of waiting for a host port, so for about an hour both sets announced the same addresses. Nothing broke, but the runbook's assumption that they wait was wrong.
    • The speakers' memberlist runs over the nodes' Tailscale addresses, and the cordoned Pis keep suspecting each other failed. Election stays on the GPU nodes, but failover is less reliable than the local test showed.
    • On the T1000, the new gpu-metrics could not start until the old dcgm-exporter released DCGM's profiling module, so the runbook's step 10 order deadlocks there; deleting the old exporter first is the way out.
  6. removed
    status: blockedCannot move forward until an external dependency is resolved.
    on Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: platformPlatform, deployment, cluster, or runtime concern.priority: P1High; important and should be handled in the current iteration.type: choreMaintenance work without intended behavior change.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions