实例生命周期
实例在任何时刻都恰好处于八种状态之一。它处于哪种状态决定了你关心的三件事:你能否连上它、它是否在向你计费,以及有哪些操作可用。
状态机
正常路径是 creating → running → stopping → stopped → starting → running。拆除过程始终是 destroying → destroyed,除了 destroyed 本身,可以从任何状态开始——包括实例仍在创建、启动或停止的时候。虚线箭头表示主机没有完成所要求的操作时,平台把实例放回它原来的状态;下文会讲到。
请求当前状态不允许的迁移——启动一个已经在运行的实例、停止一个还在创建中的实例——会被拒绝,实例保持原状。
每一种状态
| 状态 | 过渡态 | 计费 | 含义 |
|---|---|---|---|
creating | 是 | 无 | 切片已经预留,你的工作负载正在首次启动。 |
starting | 是 | 无 | 已停止的实例正在同一台机器上、用同一块磁盘恢复。 |
running | 否 | GPU,按秒 | 工作负载已就绪。SSH、JupyterLab 和你发布的端口都可以访问。 |
stopping | 是 | 无 | 容器正在关闭。你的磁盘会被保留。 |
stopped | 否 | 磁盘,按 GB 每小时 | 没有任何东西在执行。磁盘保留,GPU 槽位也一样,除非平台将其释放——参见停止与销毁。 |
destroying | 是 | 无 | 容器和磁盘正在被拆除。 |
destroyed | 否 | 无 | 终态。磁盘已经没了,报价回到市场。 |
error | 否 | 无 | 工作负载无法启动、运行中失败,或者自行结束了。见下文。 |
过渡态是平台正在主动推进的那四种状态;控制台会用脉动的徽章显示它们,并在推进期间更频繁地刷新。它们会自行结束——没有什么需要重试的,不过你可以不等它结束,直接销毁实例。
非过渡态是稳定的。实例会一直停在 running、stopped、destroyed 或 error,直到你、计费系统或主机自己的上报让它动起来。
每次迁移由什么引起
| 迁移 | 触发条件 |
|---|---|
→ creating | 你执行部署:带上一份报价、一个模板和一个磁盘大小调用 POST /v1/instances。 |
creating/starting → running | 工作负载上报自己已就绪。GPU 计量从这里开始,而不是从部署时开始。 |
creating → error | 工作负载无法启动。 |
running → stopping | 你停止了它,或者你的余额到了 $0。你自己的停止会保留 GPU——除非一笔支付争议冻结了组织的付款,那时它会像 $0 时的那次停止一样释放它们。释放只在机器支持的情况下发生。 |
stopping → stopped | 关闭已完成。磁盘计量从这里开始。 |
stopping → running | 主机在 30 分钟内没有确认停止。容器仍在运行,所以 GPU 计量重新开启,停止操作会一直重试。它的 error_code 为 stop_timed_out。 |
stopped → starting | 你启动了它。要求余额够支付组织所运行的一切一小时的费用,包括这个实例。GPU 已被释放的实例必须取回同样的 GPU:只要其中任何一块正在使用,启动就会以 409 CAPACITY_UNAVAILABLE 被拒绝,实例保持 stopped。 |
starting → stopped | 主机拒绝了恢复、无法连接,或者没有在 30 分钟内确认(start_timed_out)。对 GPU 已被释放的实例来说,拒绝通常意味着另一位租户现在正在用它们(gpus_unavailable)。实例回到已停止,磁盘还在,你可以再次启动它。 |
stopped → error | 机器报告已停止实例的容器不见了——它在停止期间退出或丢失,磁盘也随之而去(workload_gone)。已经没有可以启动的东西了。 |
running → error | 工作负载失败、主机丢失了它,或者一个任务自行运行完毕(workload_completed)。GPU 会被释放。 |
error → running 或 stopped | 平台发现工作负载其实是健康的——在运行,或连同磁盘被保留着——于是把实例放回相应的状态。 |
除 destroyed 外的任何状态 → destroying | 你销毁了它。余额持续低位足够久之后,自动销毁会对已停止和出错的实例做同样的事。 |
destroying → destroyed | 拆除已完成。磁盘被删除,报价被释放。 |
其中两个触发条件不是你发起的。当组织的余额归零时,运行中的实例会被自动停止,已停止实例的 GPU 会在机器支持的情况下被释放。如果余额随后在零或以下持续 24 小时,并且已到 −$5 或更低,已停止和出错的实例会被销毁。运行中的实例永远不会被直接销毁——它们会先被停止。一笔未结的支付争议也会释放已停止实例的 GPU,即使余额为正也一样。这些都在 自动停止与自动销毁 中讲到。
部署和启动都要求余额够支付组织全部消耗一小时的费用——每个运行中、启动中或创建中实例的 GPU 和磁盘,每个已停止实例的磁盘,再加上你正在部署或启动的这个实例的 GPU 和磁盘——而不只是大于零。停止和销毁则从不要求——无论余额是多少,你随时都能把东西关掉。
计费跟随状态
费用按实例实际所处状态的费率结算,而且每一次状态变化都会在生效之前先结清此前欠下的部分。GPU 计量只在 running 时运行。磁盘计量只在 stopped 时运行。四种过渡态、error 和 destroyed 都是免费的。
这就是为什么一次花两分钟才启动起来的部署不会为这两分钟计费,也是为什么已停止的实例仍然每分钟在你的账本里产生一条扣费。
“error”是什么意思
error 意味着工作负载没有在运行,平台也没有为你保留它:镜像拉取失败、容器拒绝启动、主机在启动过程中停止上报、工作负载在运行中失败或丢失、一个任务自行运行完毕,或者一个已停止实例的容器从它的机器上消失了。具体是哪一种,实例页面会在出了什么问题下说明,API 会在实例的 error_code 和 error_message 里给出。参见实例为何失败。
由此有四个结论:
- 不会向你计费。 在
error状态下计量是关闭的,实例停在那里不会累计任何费用。 - 不会重试。 没有自动重新启动。除了销毁,唯一的出路是恢复:如果平台后来发现工作负载在运行,或连同磁盘被保留着,它会把实例移回
running或stopped。 - 它可能被自动清理。 从未运行过就出错的实例,或者已知其工作负载已经结束的实例,会在进入
error大约一小时后被自动销毁,磁盘也一起删除。运行过、而工作负载可能仍被保留的实例不会——它会等平台弄清楚发生了什么,或者等你处理。 - 销毁是你唯一能做的操作。 你无法启动、停止或修复一个出错的实例。销毁它,排除原因,然后重新部署。
启动失败的常见原因出在模板上而不是硬件上:一个不存在的镜像名或标签,或者一个凭据填错的私有镜像仓库。如果 ssh 或 jupyter 模板用的镜像不是基于 Superheat 基础镜像构建的,同样启动不起来,因为这两种模式依赖基础镜像的 entrypoint。
运行完毕的任务——命令会退出的 args 模式模板——会以 error_code workload_completed 进入 error。它的 GPU 会立即释放,也不计费;拿到你需要的东西之后销毁它。
从未到达过 running 的实例没有日志可读,所以要从模板而不是从实例入手排查。故障排查 逐一讲了具体的失败情形。
它不产生费用。一旦平台看到它的工作负载已经结束——失败、丢失或运行完毕——它的 GPU 会立即回到市场。工作负载还没到达主机就失败的部署,会一直占着切片,直到实例被销毁——由你销毁,或者大约一小时后被自动销毁。无论哪种情况,在被销毁之前,它都计入组织 25 个实例的上限。
你在哪里看到状态
实例 页面会列出除已销毁实例之外的一切。通过 API,GET /v1/instances?include_destroyed=true 可以把它们带回来。
每个实例页面会以徽章显示当前状态,只展示当前状态允许的操作——已停止的实例上是启动,运行中的实例上是停止,除 destroyed 外的每种状态上都有销毁——并在工作负载就绪之后,在它的 连接 标签页显示连接信息。API 会在实例的 allowed_actions 里返回同样的列表。