FORGE_DEFAULT_FLEET_KIND 是它留下的东西,只在 console 还没有任何 Fleet 时用来种出第一个——
首次启动读一次,别处不读。
一个 Fleet 记了什么
config 放的是同一种 kind 的两个 Fleet 之间会不一样的那些键——slurm 的 REST 地址、KubeRay 的
namespace。写了一个没有任何设置会读的键,会打一条 warning 而不是被无声忽略:拼错的覆盖项就是
一条运维以为生效、实际没生效的设置。
capability 是承诺,不是偏好。没有
serve 的 Fleet 不是「serve 得不好」的 Fleet——点名它的
部署会被拒。建一个
Fleets → 新建 Fleet。选后端、选它用来做什么;数据投递方式默认跟随后端,可以改。也可以走 API:FORGE_DEFAULT_FLEET_KIND 种下一个,所以
零配置部署根本不用调这个接口。
注册一台机器
只有node Fleet 需要注册机器——kuberay 和 slurm 的机器由集群管理器给,local 就是
console 自己这台。
在 Fleet 页面签出一个 join token——「添加机器」。它一次性、24 小时过期、只存哈希。页面会给出一行可以直接粘到
机器上的命令:
FORGE_NODE_STATE_DIR 下。**凭证只返回一次。**弄丢了就
只能再要一个 token、作为新节点重新加入——这是对的:一台丢了身份的机器,对一个要拿容器跟它对账的
控制面来说,就不是同一台机器了。
节点在 join 时上报自己的清单——卡名、卡数、驱动、容器运行时,以及看不看得见存储根。console 把卡名
映射到硬件系列。注册表不认识的卡会在 join 的输出里点出来,好让管理员补进去;在那之前,指定了系列
的作业不会落到这台机器上。
地址不是身份
节点的标识是 console 签发的 id,不是host:port。搬了家的机器还是同一台机器。这带来的后果是,
两条记录合法地答在同一个地址上是可能的,所以「加入时已有另一个活着的节点答在这个地址」是一条警告
而不是拒绝——由 forgelet join 打出来,因为最常见的成因是一次重新加入留下了旧记录,于是 console
把一台机器的卡数了两遍。
存活判定
一个last_seen_at,对三个阈值来读,因为判错的代价取决于这台机器是干什么的:
这是三种后果,不是三种状态。节点被判为
gone 用的是它所在 Fleet 各 capability 里最宽松的
那一个;更紧的规则按 capability 单独回答。「现在别往那儿发流量」和「根本别往那儿放东西」是两句
不同的话——否则一个声明了全部三项的 Fleet 会在静默 45 秒后连训练活儿都不接了。
被判为 gone 不会杀掉任何东西。节点失联不等于作业死亡:observe 对它上面的作业不返回信号,对账
跳过这一轮,机器回来后按真实容器状态收敛。
shared-mount 的节点上报说看不见存储根了,会被 cordon;挂载回来后自动解除。运维自己下的 cordon
永远不会被一次心跳解除——那一个是决定,而心跳是观察。
排空、cordon、移除
它们都不杀东西,这正是重点。
cordoned 给还会回来的机器,draining 给要走的机器。
移除一个 active 的节点会被拒。它的身份正是让它的容器可对账的东西,所以先排空、让活儿跑完。
force=true 是给已经没了的机器用的;它会以「强制」记进审计日志,因为它留下的是一个再也没人能
对账的容器。
一个 Fleet 只有在既没有节点、也没有部署钉在上面时才能删。部署不会换 Fleet,所以把它脚下的 Fleet
删掉,会留下一行后端解析不到任何东西的记录:观察不了、停不掉,卡还占着。
怎么挑 Fleet
部署是那个例外,因为它的地址比这个决定活得更久、而且永远不搬,而 Fleet 记录上没有任何字段说得清
这些机器归哪个部门、什么数据可以碰它们。平台拒绝回答一个它答不了的问题。
放置在准入这一刻带着理由拒绝——capability、可见性、或者装不装得下。没有任何 Fleet 能容纳的作业,
会在提交者还盯着响应的时候就被告知,而不是几个小时后排到队首才发现。
「装不装得下」是一次检查,不是一次预留。到底拿到哪几张卡,权威仍然是分配器;这里挡的只是「这个
Fleet 从来就没有过的硬件」,免得它在队列里排到天荒地老。
可见性
project 的 Fleet 在项目之外不可见,点名它的作业会被拒为不存在而不是无权限——私有 Fleet 的
名字不该从一条错误信息里漏出去。