服务停了,机器还在计费,域名还在解析,三个月后有人在账单里发现一台没人认识的实例。停机只是退役的第一步,真正消耗时间的是收尾。收尾的难处不在技术,而在于没有任何一个动作会自己结束:数据不敢删、域名不敢停、实例不敢关,每一件都需要一个明确的判断,以及一个人签字。
1. 收尾清单的四类:数据、网络、资源、账目
| 类别 | 收尾对象 | 最容易漏的 |
|---|---|---|
| 数据 | 数据库、对象存储、备份、冷归档、快照 | 备份副本与快照,常被当成"数据"以外的东西 |
| 网络 | 域名、证书、DNS 记录、反代规则、外部回调 | 第三方后台里配置的回调地址 |
| 资源 | 实例、编排对象、负载均衡、专线、固定 IP | 预留的弹性 IP 与配额占位 |
| 账目 | 计费项、订阅、许可证、支持合同 | 按年付费的订阅,到期前不出现在月度账里 |
四类里最常被跳过的是账目:运维按实例清单清理,财务按账期核对,两边用的是不同的表,于是"实例没了但订阅还在"会稳定地重复出现。收尾清单的价值也正在这里——它把两个视角合到同一张表上,让"完成了"这件事有唯一的判据。
先做一次残留扫描,把"以为已经没了"变成一张清单。扫描的价值不只是发现问题,更在于产出可留证的输出:把命令与结果一起存档,"清理前状态"才有据可查。退役收尾里最常见的争论是"这个是不是我们留下的",有存档就不必争论。
// 网络面: 域名是否还在解析
dig +short A APP_DOMAIN
dig +short MX APP_DOMAIN
// 证书面: 是否还有对外可见的有效证书
echo | openssl s_client -connect APP_HOST:443 -servername APP_DOMAIN 2>/dev/null \
| openssl x509 -noout -dates -subject
// 资源面: 按标签或资源组列出仍在运行的实例与计费项
2. 数据处置的四种去向
"服务停了但数据不能删"是最常见的长期占用。要先把留存义务和习惯性保留分开:前者有明确依据(合同、审计要求、法规),后者只是"万一以后要用"。
| 去向 | 适用 | 成本结构 | 前提 |
|---|---|---|---|
| 归档冷存 | 有留存义务但不再访问 | 存储按量计费,取回有延迟与费用 | 能说清留存期限与责任人 |
| 迁移合并 | 仍被业务需要 | 一次性迁移 + 双写期成本 | 有明确的新归属系统 |
| 按规删除 | 无义务、无用途、含个人信息 | 删除动作与证明成本 | 有删除范围与审批记录 |
| 原样冻结 | 短期可能要回看 | 维持原成本,最贵 | 必须有到期时间 |
四种去向里,"原样冻结"最容易被默认选中,因为它不需要任何人做决定——代价是它把退役的成本无限期留了下来。另一个常见缺口是把归档当成终点:冷存不等于可恢复。归档存好之后至少要做一次取回演练,否则留存义务只是名义上被履行了——真有需要时才发现归档缺了索引、密钥已经轮换、恢复脚本依赖一个已经不存在的环境。
留存义务要落成一张登记表,而不是口头共识:
// 留存登记(数据集与去向逐行登记)
数据集: APP_DB.orders
去向: 归档冷存
依据: 合同条款或审计要求编号
期限: 到期日
责任人: 角色,不写姓名
取回方式: 恢复演练是否做过
3. 域名、证书与外部集成的清理
这三件最容易漏,也最容易造成事故:域名一停,可能连带停掉别人正在用的一个回调,或者一个正在发信的邮件域。
| 对象 | 处置判断 | 弃用前的确认 |
|---|---|---|
| 域名 | 续费保留 / 到期释放 | 谁在用、是否作为邮件域、是否在外部白名单里 |
| 证书 | 随域名停止续签 | 是否被其它系统共用(多域名证书) |
| DNS 记录 | 逐条删除 | 泛解析是否覆盖了内部用途 |
| 外部回调 | 在对方后台注销 | 是否仍有第三方在推送 |
// 域名与记录清理前的核对,逐条留证
dig +short A APP_DOMAIN
dig +short MX APP_DOMAIN
dig +short CNAME WWW_DOMAIN
dig +short TXT _dmarc.APP_DOMAIN
// 以上输出连同日期一起存档,作为"清理前状态"的证据
MX 记录与邮件域是最容易忽略的一项;TXT 里的 SPF/DMARC 记录在服务停止后,往往仍被其它发送方依赖。
域名保留的成本通常很低,低到让人倾向"先留着"。但保留会掩盖依赖:只要域名还在解析,外部系统就不会暴露它对它的依赖。判断依据应当是"有没有周期性调用者",而不是"有没有人明确说要"。清理顺序则应当由外向内:先确认外部没有依赖,再动解析记录。
// 依赖确认: 退役前还有谁在调用
awk '{print $1}' ACCESS_LOG | sort | uniq -c | sort -rn | head
grep -c "APP_DOMAIN" ACCESS_LOG
// 命中为 0 且覆盖一个完整业务周期(含月度批处理)之后,再考虑释放域名
4. 关闭顺序、权限注销与"先停一半"
关闭顺序有硬约束:先停流量、再停实例、最后停账单。顺序颠倒会出现两种典型状态——"还在计费但已经不可访问",或者"已经不可访问但仍被外部调用"。
| 阶段 | 动作 | 验收信号 |
|---|---|---|
| 1 停流量 | 反代或负载均衡下线,域名指向变更 | 外部请求不再到达,返回预期错误 |
| 2 停实例 | 停机、缩容、释放固定 IP | 监控中该对象的指标消失 |
| 3 停账单 | 取消计费项、清理预留与配额 | 下一账期不再出现该资源项 |
权限与密钥要与实例同步注销:人走了账号还在,是退役后最典型的残余风险。清单包括服务账号、API Key、CI 凭据、数据库账号、对象存储授权、监控面板共享链接。这一项的检查方法也很直接——按凭据的归属对象反查,凡是还能访问已退役系统资源的凭据,都应当是待注销项,而不必依赖谁还记得它存在。
监控与告警也要清——一个已经没人在意的服务的告警,会稳定生成假报警,长期消耗值班注意力:
| 类别 | 残留表现 | 清理方式 |
|---|---|---|
| 告警 | 每天固定时点的"服务不可达" | 删除规则与其通知路由 |
| 面板 | 图表持续无数据 | 下线面板或标记为归档 |
| 日志采集 | 仍在上报但无人查询 | 停采集,已存日志按留存策略处理 |
| 值班手册 | 仍列出已退役服务的处置步骤 | 从手册移除,避免误导 |
"先停一半"是最危险的中间态:服务已经没人用,但域名还在、实例还在、权限还在、告警还在——它既没有人负责,也没有被判死。因此每个退役动作都应当有最长期限,超期即进入强制清理。
它的另一个变体是"停流量但保留实例作为回退"。这种安排看起来稳妥,实际会让实例从"有 owner"变成"没 owner":没人再部署、没人再打补丁、也没人再验证它是否还能启动。真要保留回退能力,该保留的是可重建的镜像与配置,而不是一台持续运行、无人照看的实例。
// 退役验收清单(逐项签字)
1 数据去向已登记,含期限与责任人
2 域名、证书、DNS 已按判断处置并留证
3 外部集成已在对方后台注销
4 实例、负载均衡、固定 IP 已释放
5 服务账号、API Key、CI 凭据已吊销
6 告警、面板、日志采集已停
7 计费项与订阅已取消
8 文档与值班手册已更新
签字: 业务方 + 运维 + 安全(按组织实际角色划分)
5. 排错与边界
5.1 排错
| 现象 | 机制 | 处理 |
|---|---|---|
| 服务停了但账单没降 | 计费项与实例生命周期不同步 | 按账目清单逐项核对,不只核对实例 |
| 域名停了别家系统报错 | 域名被外部回调或白名单依赖 | 清理前做依赖确认,宁可先保留 |
| 数据长期"不敢删" | 没人确认留存义务是否存在 | 把"是否有义务"变成一次可查的核对 |
| 告警持续假报 | 监控对象未随服务一起退役 | 验收清单加入告警清理项 |
| 半年后又发现同一台机器 | 缺少按标签的定期扫描 | 用资源标签扫描代替靠记忆 |
5.2 边界
| 场景 | 结论 |
|---|---|
| 内部临时环境 | 收尾压缩为一次核对,不做留存登记 |
| 无外部依赖、无域名 | 网络面清理可以省略 |
| 资源成本可忽略 | 不必为省钱做收尾,但权限与密钥仍要注销 |
| 系统会被同团队重建 | 保留镜像与配置模板,其余照常清理 |
边界里"内部临时环境"最容易被滥用:只要有人称它是临时的,整个收尾就被跳过。判断依据应当是它有没有外部可见性——对外域名、对外接口、真实业务数据。三者都没有,才可以压缩成一次核对。
度量看四个数:退役周期(决定日到净账日)、残余资源数、误报数(退役后由该系统产生的告警数)、未清理账号数。其中误报数最容易被当成噪声忽略,但它恰好反映退役是否真的做完了:一个没人负责却仍在告警的服务,越晚清理,对被值班挤占的注意力就越具体。退役周期这个数同时反映技术动作与决策速度——周期长达数月的退役,通常不是卡在技术,而是卡在没人愿意签字。
// 退役台账(每个系统一行,季度更新)
系统: APP
决定日 → 净账日: 退役周期
残余: 资源数 / 账号数 / 域名与证书
误报: 退役后新增告警条数
6. 自测
- 为什么"原样冻结"是最容易发生的默认选择?
- 关闭顺序颠倒会造成哪两类现象?
- 域名清理前为什么必须先确认外部依赖?
- 数据"不敢删"通常缺的是哪一个确定动作?
- 验收清单里为什么告警清理要单独列一项?
- 资源成本可忽略时,退役里最不能省的是哪一部分?