FORGE_DEFAULT_FLEET_KIND survives it, and seeds the first Fleet on a console
that has none — read once, at first start, and nowhere else.
What a Fleet carries
config holds the keys that differ between two Fleets of the same kind — the slurm REST
endpoint, the KubeRay namespace. A key no setting reads is logged as a warning rather than
ignored: a misspelled override is a setting an operator believes is in effect and is not.
A capability is a promise, not a preference. A Fleet without
serve is not a Fleet that
serves badly — a deployment naming it is refused.Creating one
Fleets → New fleet. Pick the backend and what the Fleet is for; the delivery follows the backend unless you change it. Or through the API:FORGE_DEFAULT_FLEET_KIND,
so a zero-config deployment never has to make this call.
Registering a machine
Onlynode Fleets have machines to register — kuberay and slurm get theirs from the
cluster manager, and local is the console’s own host.
Mint a join token on the Fleet page — Add a machine. It is single-use, expires in 24 hours, and is stored
only as a hash. The page shows one line to paste on the machine:
FORGE_NODE_STATE_DIR. The credential is returned once. Losing it means asking for
another token and joining again as a new node, which is correct: a machine that lost its
identity is not the same machine to a control plane reconciling containers against it.
The node reports its own inventory at join — card name, count, driver, container runtime,
and whether it can see the storage root. The console maps the card name onto a hardware
series. A card the registry does not know is named in the join output so an administrator
can add it; until then, jobs that pin a series are not placed there.
An address is not an identity
A node is identified by the id the console issued, never byhost:port. A machine that
moves stays the same machine. The consequence is that two records may legitimately answer
at one address, so joining where another live node already answers is a warning rather
than a refusal — printed by forgelet join, because the usual cause is a re-join that
left the old record behind, and then the console counts one machine’s cards twice.
Liveness
Onelast_seen_at, read against three thresholds, because the cost of being wrong differs
by what the machine is for:
These are three consequences, not three states. A node is declared
gone on the most
generous of its Fleet’s capabilities; the tighter rules answer per capability. “Do not
send traffic there now” and “do not place anything there at all” are different claims, and
a Fleet that declares all three would otherwise stop taking training work after 45 seconds
of silence.
Nothing about being gone kills anything. An unreachable node is not a dead job: observe
returns no signal for its jobs, reconciliation skips them, and state converges from the
real container when the machine comes back.
A shared-mount node that reports losing the storage root is cordoned, and un-cordoned
when the mount returns. An operator’s own cordon is never lifted by a heartbeat — that one
is a decision, and a heartbeat is an observation.
Drain, cordon, remove
None of them kills anything; that is the point.
cordoned is for a machine that is coming
back, draining for one that is leaving.
Removing an active node is refused. Its identity is what makes its containers
reconcilable, so drain first and let the work finish. force=true exists for a machine
that is already gone; it is recorded in the audit log as forced, because what it leaves
behind is a container nothing can reconcile.
A Fleet is deletable only with no nodes and no live deployment pinned to it. A deployment
never changes Fleet, so deleting the Fleet under it would leave a row whose backend
resolves to nothing: unobservable, unstoppable, and still holding cards.
Choosing a Fleet
A deployment is the exception because its address outlives the decision and never moves,
and nothing on a Fleet record says which department owns the machines or what data may
touch them. The platform declines to answer a question it cannot answer.
Placement refuses at admission with a reason — capability, visibility, or inventory fit.
A job that no Fleet can hold is told so while the submitter is still looking at the
response, not hours later at the top of a queue.
Inventory fit is a check, not a reservation. The allocator remains authoritative for
which cards a job actually gets; this only stops a request for hardware the Fleet has
never had from queueing forever.
Visibility
Aproject Fleet is invisible outside its project, and a job naming one is refused as
not found rather than forbidden — a private Fleet’s name does not leak through an
error message.