现象
推理宿主重启后,推理引擎容器未自动拉起(Exited 255),同机其余容器(穿透 sidecar、代码仓、代理、数据库、组网)全部正常 Up。穿透通道虽在,但后端不通,对外服务实际中断。
因果链
宿主重启
└─ 冷盘(机械盘,起转慢)未在 device-timeout(10s)内就绪
└─ fstab 带 nofail → systemd 放行启动,不再补挂
└─ 挂载点保持为空目录 → 模型软链悬空(断链)
└─ dockerd 开机恢复容器时 bind 挂载失败:
mkdir <挂载源>: file exists(daemon 级错误)
└─ 容器 Exited 255,RestartCount 0
(restart: unless-stopped 不重试 daemon 级挂载失败)
└─ 其余不挂该路径的容器全部正常 → 只有推理栈倒下
- R01 挂载从未发生,不是挂载失败:挂载单元本次启动 journal 零记录、状态 inactive(dead),而设备当时已可见——盘在,挂载没被触发。nofail 的语义是“超时即放弃且不补”,不是“稍后重试”。
- R02 悬空软链是放大器:dockerd 把断链当作“路径已存在(文件)”处理,报 file exists 而不是“目标不存在”,误导性强。以后见此报错先查链的落点,不查链本身。
- R03 restart 策略救不了这类错:unless-stopped 只对容器运行时退出有效;daemon 在创建阶段就失败的,计数器都不涨。开机自愈必须保证“挂载先行”,不能指望重启策略。
决策与依据
- 采用 automount + noauto(方案 A):noauto 让开机不阻塞等待慢盘;automount 让首次访问(dockerd 建容器时)当场触发挂载。比“放宽 device-timeout”(方案 B)稳——B 只是把竞态窗口调大,慢盘照样可能超时,而 A 消除了竞态本身。
- 根 compose 单文件收敛:此前双根入口(两引擎各一)互斥、靠人工保证一次只起一条,已是第二次为此 confusion 付出代价。现单根文件 include 当前引擎链 + sidecar,引擎切换只改一行 include。根入口双侧不互相同步,各侧独立维护。
- 本次不手动拉容器:保持 Exited 现场,用一次真实重启验证“自动拉起”是否成立;手动起只能证明“能起”,证明不了“开机自愈”。
重启后验收判据
- automount 单元为 active (waiting),挂载点有内容,软链恢复。
- 推理容器为 Up(非 Exited),健康端点返回正常。
- 若仍 Exited 255:取容器 Error 字段 + 当次启动的挂载单元 journal,再定位。
遗留(非阻塞):命名数据卷缺 external 声明有 WARN 噪音,服务恢复后补。
后续:穿透通道开机未建连(同日,重启验证时发现)
重启后推理容器自动拉起成功(healthy),但公网域名不通。穿透 sidecar 容器显示 Up,实为 entrypoint 壳活着、内部进程早已退出——“容器 Up ≠ 进程活”,排障先看进程日志,不看容器状态。
开机瞬间嵌入式 DNS 未就绪 → 穿透客户端首次登录失败
└─ 客户端默认 loginFailExit=true → 失败一次即彻底退出、零重试
└─ 容器壳仍 Up → 隧道从开机起就没建起来,且无任何自愈
- 修复:穿透客户端配置加
loginFailExit = false(必须放在全局段,误放入代理段会报 unknown field 起不来——已实踩一次),重建 sidecar 后登录成功、隧道建立,公网健康端点返回正常(模型列表端点 401 系鉴权墙,正常)。只动 sidecar,推理容器未动。 - R04 开机时序类配置都要按“首次必败”来设:开机瞬间 DNS/网络/磁盘任一没就绪都正常,任何“失败即退出”的默认项在开机场景下都是坑。decouple 拉起 + 无限重试才是正解。