当 Spot 实例被回收时如何优雅迁移容器
解读
国内公有云(阿里云抢占式、腾讯云竞价、华为云竞享)的 Spot 实例在五分钟级别的回收通知期内,需要把运行中的 Docker 容器零中断或秒级中断地迁移到另一台节点,同时保证数据不丢、网络会话不断、CI/CD 链路不阻塞。面试官想验证你对“容器生命周期 + 云原生弹性 + 低成本架构”三者的综合落地能力,而不仅仅是“docker run”级别的操作。
知识点
- Spot 回收信号:阿里云**元数据 http://100.100.100.200/latest/meta-data/spot/termination-time**、腾讯云**metadata/spot/termination-time**,均提前 2-5 分钟推送。
- 容器运行时事件:Docker Engine 的containerd、runc 在收到 SIGTERM 后默认 10 s 宽限期,需与 kubelet 或自研编排对齐。
- 镜像分层与缓存:多阶段构建 + 本地 registry 缓存可让新节点 30 秒内拉起镜像。
- 有状态卷:云盘多可用区快照、NAS 共享存储、FUSE 分布式盘(如 JuiceFS)实现秒级挂载。
- 网络漂移:Cilium BGP+AnycIP 或阿里云 Terway ENI 弹性网卡可在新节点继续持有原 IP。
- 编排层:Docker Swarm 的drain、Kubernetes 的PodDisruptionBudget + eviction API 是官方标准做法。
- 业务层:应用需实现优雅关闭钩子(spring-boot-graceful-shutdown、nginx quit、go http.Server.Shutdown)与健康检查端点。
- 成本控制:Spot + 按需混部,HPA 基于 QPS 与价格双维度伸缩,防止迁移后成本反跳。
答案
-
监听回收信号
在每台 Spot 实例部署daemonset 级别的 termination-handler 容器,每 2 秒轮询云厂商元数据接口;一旦拿到非空 termination-time,立即向本机 Docker daemon 与上层编排发送drain 事件。 -
冻结调度
若使用 Docker Swarm,执行
docker node update --availability drain <node-id>
若使用 Kubernetes,调用
kubectl drain <node> --pod-selector=app=xxx --grace-period=120 --timeout=110s --delete-emptydir-data
确保新 Pod 只漂到非待回收节点。 -
触发容器优雅退出
在 Dockerfile 中定义
STOPSIGNAL SIGTERM
并配置
HEALTHCHECK --interval=5s --retries=3 CMD curl -f http://localhost:8080/health || exit 1
应用代码监听 SIGTERM,完成正在处理的请求排空、数据库连接池关闭、分布式锁释放后再退出,保证事务级一致性。 -
快照与数据迁移
对有状态服务,提前使用云盘快照或NAS 共享卷;在收到回收信号后调用云 API 创建一致性快照,并在目标节点原子挂载同盘;若使用 Docker 卷插件(如 rexray/ebs),只需volume ID 漂移,无需复制数据。 -
镜像预热
在集群内搭建Harbor 本地缓存并开启P2P 预热(Dragonfly、Kraken);目标节点已提前docker pull 最新镜像层,容器启动耗时 <10 秒。 -
网络会话保持
对外流量经SLB + 弹性网卡 ENI;容器漂移后 ENI 随 Pod 重新绑定,IP 不变,长连接由SLB 优雅断开;对内 RPC 使用服务网格(Istio)+ 重试超时策略,消费者侧无感知。 -
验证与回滚
迁移完成后,通过Prometheus 指标验证p99 延迟无抖动、错误率 <0.1%;若超时未完成,自动回滚到同规格按需实例,并触发钉钉/飞书告警,人工介入。
拓展思考
- 如果业务是GPU 训练任务,Spot 回收会导致显存数据丢失,可考虑checkpoint 到 CPFS 并行文件系统,训练框架(PyTorch Lightning、TensorFlow Checkpoint)每 5 分钟自动保存,从最近 epoch 恢复,把浪费的 GPU 时长控制在 5% 以内。
- 在混合云边缘机房没有云厂商元数据接口时,可自研heartbeat + 租约机制:节点每 30 秒向 etcd 续租,租约过期即触发 drain,实现与云厂商解耦的 Spot 模拟。
- 成本极致优化场景,可引入Spot 实例多样性池(x86/ARM、不同规格族),结合Docker buildx 多架构镜像,让调度器优先选择低价 ARM Spot,迁移时架构无感,进一步降低 30% 计算费用。