安装成功了,端口却早已被别人占用
一句话总结
预检(preflight)是在安装之前,只读地判定客户主机是否满足要求,并把结果留成报告和退出码,供下一步的自动化(而不是人)来读取。
为什么需要它
客户现场的安装窗口通常只有一次。周四晚上 22 点基础设施团队开门,到午夜就关。在这种场合,安装脚本以“完成”结束这件事,几乎什么也保证不了。文件虽然复制到了位置,但代理打算使用的端口可能已经被内部代理占用,一启动就会挂掉;客户交来的证书也可能在安装三周前就已过期。这两件事都得在安装之后翻日志才能知道,但在安装之前只要 5 分钟就能知道。
FDE 交付给客户的不是代码,而是能正常运行的结果。所以在安装步骤前面,单独设一个步骤来问“这台主机上,安装成功的条件是否具备”。如果把这一步做成人工的检查清单,每次都会有人漏掉。做成脚本并把结果留成文件,就能拿出依据对客户说:“阻止安装的是这两项,其余都是警告。”
工作原理
检查器以需求规格为输入,每项检查给出 pass、warn、fail 之一以及观测值。观测值很重要。只写着“端口失败”的报告无法反驳,也无法验证。只有同时给出 observed: in_use,以及所测的路径、剩余 MiB 和 notAfter 时刻,客户负责人才能亲眼再确认一遍。
退出码借用监控插件的惯例就容易解释。Monitoring Plugins 开发指南使用 0 OK、1 Warning、2 Critical、3 Unknown,并把 3 限定为参数错误或检查器自身无法运行的情形。值得注意的是,其中写明:名称解析失败或套接字超时之类的上层错误不要升级为 Unknown。主机名解析不了不是“不知道”,而是阻止安装的事实。
每一项检查都有常见的陷阱。
- 端口。要看端口是否空闲,就实际 bind 一下。但不加选项直接 bind 的话,刚刚结束的连接以 TIME_WAIT 状态残留的端口也会显示为正在使用。Python 的 socket 文档在
create_server()的说明中写道,为了能立刻重新使用处于 TIME_WAIT 的地址,在 POSIX 上会开启SO_REUSEADDR。在实验镜像上实测,有监听套接字的端口即使开启这个选项也是 EADDRINUSE,而只剩 TIME_WAIT 的端口必须开启这个选项才能 bind。没有开启的检查器会把完全正常的安装挡住。 - 磁盘。shutil.disk_usage 以字节给出 total、used、free。实测中 free 等于 statvfs 的
f_bavail(非特权用户可使用的块数)乘以片段大小的值。对于尚不存在的安装路径,不要去创建,而是测量存在的最近的父目录,并把所测的路径写进报告。 - 证书。Python 的 ssl 模块中没有读取 PEM 文件并取出 notAfter 的公开函数。取而代之的是
ssl.cert_time_to_seconds(),它能把"%b %d %H:%M:%S %Y %Z"格式的 notAfter 字符串转换为 epoch 秒。字符串用 openssl x509 的-enddate获取。同一文档中的-checkend在证书于给定秒数内过期时会以非 0 值退出,但如果想在报告里写出剩余天数,自己计算日期更好。 - Python 版本。把“3.12.3”和“3.9”当字符串比较,3.12 反而更小。要用整数元组比较。
- 写权限。os 文档指出,先用
os.access()检查再打开的方式,会在检查与使用之间留下空隙,建议采用 EAFP,即实际去做并捕获异常。也有像只读挂载这样权限位说明不了的原因,所以要实际创建一个临时文件并立刻删除。
명세(spec.json) ──▶ preflight.py ──▶ report.json (점검마다 status + observed)
│
└──▶ 종료 코드 0 · 1 · 2 (명세를 못 읽으면 3, 보고서 없음)
在现场相遇的样子
最常见的错误是检查器顺手修复。数据目录不存在就创建,把占用端口的进程杀掉,把过期证书换成自签名证书。那一刻,检查结果就丢掉了“这台主机原本是什么样”。而且目录的所有权、占着端口的内部代理、证书签发流程,全都是客户组织的决定。预检只揭示事实,修复则按负责人商定的流程进行。这次的客户备忘录里也写着,工作目录由基础设施团队来创建。
第二个错误是把警告和失败混在一起。剩余空间超过供应商的最低值、但少于运维团队的标准,安装是可以进行的。如果把这也升级为失败,就会白白错过安装窗口;如果完全不通知,两个月后磁盘就会写满。这就是要单独设置警告等级的原因。
实际工作中真正重要的事
- 报告必须能够重新测量。不要只写判定,要把观测值和所测对象一起留下。
- 检查器不修改主机。连写入测试的临时文件也要删除。
- 退出码是一种约定。让安装自动化把 1 读作继续,把 2 读作中止。
- 报告过期就不再是依据。安装前再运行一次,并在判定记录中留下这是哪份报告的哈希。
下一项实验要做什么
把客户备忘录转写成规格,依次实现端口、TIME_WAIT、磁盘、证书、文件、主机、写入检查。评分器每次都会用不同的端口和基准值、以及自己生成的即将到期和已过期的证书来运行你的检查器,并核对判定和观测值。最后,用客户规格做出实际判定,并留下 go / no-go 记录。