华为云CLI批量改资源翻车后的回滚
事情失控和回滚过程
9 月 18 日我值夜班,变更脚本跑在堡垒机 s7n.xlarge.2(4 vCPU / 8 GiB),Ubuntu 22.04.4 LTS。环境我当时重新核过一遍,huaweicloud-cli 3.1.96、jq 1.6、Python 3.11.9,区域固定 cn-north-4,目标是 34 台 ECS 和 19 个 EIP 的映射对齐。脚本默认参数是 --workers 8 --interval 0 --retry 1,这个并发是我前一天自己提上去的,单次从 4 分 52 秒压到 4 分 11 秒,省了 41 秒,后面证明这 41 秒不值。
这个方案我一开始是拒绝的。
20:05 我把同事分支 feature/eip-reconcile 合到主分支,冲突文件就一个 state-prod.json,但冲突块有 11 行。我手工解冲突时把 7 条映射抄错了,典型一条是把 server_id=9f21d6... 配成了 publicip_id=6aa2bd...,正确应该是 3d7b4a...。20:11 跑 ./reconcile_eip.sh prod --workers 8 --interval 0,终端不是单一错误,是 400、409、429 交替刷。20:13 到 20:15 两分钟里日志里一共打了 126 行异常,最快一秒 9 条,基本看不出先后关系。
$ huaweicloud --version
huaweicloud-cli 3.1.96
$ ./reconcile_eip.sh prod --workers 8 --interval 0
[20:11:08] detach eip 3d7b4a.. from ecs 9f21d6..
[20:11:09] attach eip 6aa2bd.. to ecs 9f21d6..
ServiceResponseException:
status_code: 400
request_id: 2f7a9bb6c0d9470ab7c2a9f97f1e11a4
error_code: ECS.0005
error_msg: The server status does not satisfy the operation requirements.
ServiceResponseException:
status_code: 409
request_id: e137f0f5f4de4a5f90b8fd9a8ef26f61
error_code: EIP.0105
error_msg: The public IP is in use.
ServiceResponseException:
status_code: 429
request_id: 1b6d4d2f8f594de2a1c0d3f8a6d77e3c
error_code: APIG.3002
error_msg: Request throttled due to too many requests.
我当时手心是凉的。
20:14 Prometheus 上网关 5xx 从 0.3% 抬到 18.7%,支付回调和短信网关同时告警。Nginx 的 /api/pay/callback 在 20:13 到 20:35 统计到 183 次 502,P95 从 42ms 拉到 1.9s,峰值 2.6s。业务群直接问“公网是不是被你动了”,我没有回避,直接认了是我这边变更引发,先停自动流程再说。
20:19 我做过一次失败的抢救,我以为把 7 条映射改回去重跑就会自动修。那次我直接 vim state-prod.json,改完执行 ./reconcile_eip.sh prod --workers 12 --retry 3。这里我又犯了一个低级错误,workers 还从 8 提到了 12,想靠速度把窗口缩短。脚本老逻辑是“无条件 detach,再 attach”,不是幂等;第二次运行把两台已经恢复正确的 ECS 再次解绑,20:19:41 到 20:20:41 这一分钟里,APIG.3002 新增 61 次,CTS 里同一个 AK 的调用速率冲到 23 req/s。我在 20:20:47 按了 Ctrl+C,进程 PID 28741 退出码 130。
# 老逻辑关键段,问题就在这里
for pair in state:
detach(pair.server_id) # 不看当前绑定
attach(pair.server_id, pair.publicip_id)
20:22 我先做冻结,crontab -l > /tmp/cron.bak 后把每 5 分钟执行的一行注释,仓库里加 .ops-freeze,CI 的 deploy job 手动 disable。三步做完 2 分钟出头。然后去 CTS 用 request_id 反查,确认调用人是堡垒机 AK,源 IP 10.23.6.14,不是外部账号误操作,这一步把方向定住了,不然会在权限和网络上白查半小时。
# 拉取实时状态,不再信任本地 state
huaweicloud ECS ListServersDetails --region cn-north-4 --limit 100 > ecs-live.json
huaweicloud VPC ListPublicips --region cn-north-4 --limit 200 > eip-live.json
python3 diff_state.py --state state-prod.json --ecs ecs-live.json --eip eip-live.json --out patch.json
python3 apply_patch.py --file patch.json --region cn-north-4 --workers 1 --interval 2 --retry 6 --retry-backoff 8
diff_state.py 我当场补了两个参数校验,不传 region 就直接退出码 17,资源数量和目标不一致就退出码 19。patch.json 最后只生成 7 条修复,按顺序串行打。第 4 条又撞 ECS.0005,我查实例详情是 REBOOT,那台机在系统盘扩容后的重启窗口。我把重试从 --retry 1 改成 --retry 6 --retry-backoff 8,实际重试 4 次,睡眠 8+16+32+40 秒,共等了 96 秒,第 5 次 attach 成功。21:02 全部映射回正,从 20:14 告警出现到恢复 48 分钟。那晚我临时新建 3 个按量 EIP 做冒烟和切流,规格 5M 共享带宽,账单是 1.74 元;短信补发 230 条,多 0.46 元。
返工后我改了什么和还没做完的事
返工我没再写“改了一下”,每一条都落成代码。状态文件拆成 desired-state.json 和 live-state.json,仓库只存前者;后者每次执行前现拉,且脚本里加了只读校验,发现 live 文件有 Git 变更就终止,退出码 23,报错写死 LIVE_STATE_MUTATED。状态文件挪到 OBS 桶 ops-state-cn-north-4,版本控制打开,生命周期 30 天。我查了 9 月账单,这部分 0.18 元。
{
"version": 3,
"region": "cn-north-4",
"generated_at": "2026-09-18T21:10:44+08:00",
"resources": 34,
"max_change": 2,
"sha256": "9f4c8d..."
}
入口也改了,从一把梭变两阶段。plan 只出计划,不做真实解绑;apply 必须带审批哈希,哈希不匹配直接退出码 31。命令从 ./reconcile_eip.sh prod 变成:
python3 reconcile.py plan --desired desired-state.json --region cn-north-4 --max-change 2 --out plan-20260918.json
python3 reconcile.py apply --plan plan-20260918.json --approve 6b7d9f --workers 1 --interval 2
我还把幂等补齐了。apply 前会先查 live 绑定,current_publicip_id == target_publicip_id 就记一条 SKIP_ALREADY_MATCHED,不会再 detach。单次计划里如果 detach_count > 2 直接失败,错误文本固定成 EIP_CHANGE_GUARD: planned detach 3 exceeds max_change 2。这个报错是给值班看的,避免他们把 guard 误解成接口抖动。
并发从 8 降到 1,平均执行时长从 4 分 12 秒涨到 5 分 03 秒,慢了 51 秒,但过去三周跑了 9 次,没有再出现误解绑。CI 里我补了两个 gate:资源数量不等于 34 拒绝合并,sha256 不匹配拒绝部署;这两个 gate 分别在 9 月 26 日和 10 月 2 日拦过一次错误提交,没再进生产。
还没解决的是互斥锁,现在两个人同时在堡垒机执行还是会打架;我下周准备把锁放到 DCS Redis,用 SET ops:eip:lock $HOSTNAME:$PID NX PX 600000,再加 fencing token,锁过期后旧进程继续写的问题我还没验证完。
- 点赞
- 收藏
- 关注作者
评论(0)