当 Spot 实例被回收时如何优雅迁移容器

解读

国内公有云(阿里云抢占式、腾讯云竞价、华为云竞享)的 Spot 实例在五分钟级别的回收通知期内,需要把运行中的 Docker 容器零中断或秒级中断地迁移到另一台节点,同时保证数据不丢、网络会话不断、CI/CD 链路不阻塞。面试官想验证你对“容器生命周期 + 云原生弹性 + 低成本架构”三者的综合落地能力,而不仅仅是“docker run”级别的操作。

知识点

  1. Spot 回收信号:阿里云**元数据 http://100.100.100.200/latest/meta-data/spot/termination-time**、腾讯云**metadata/spot/termination-time**,均提前 2-5 分钟推送。
  2. 容器运行时事件:Docker Engine 的containerdrunc 在收到 SIGTERM 后默认 10 s 宽限期,需与 kubelet 或自研编排对齐。
  3. 镜像分层与缓存:多阶段构建 + 本地 registry 缓存可让新节点 30 秒内拉起镜像。
  4. 有状态卷:云盘多可用区快照NAS 共享存储FUSE 分布式盘(如 JuiceFS)实现秒级挂载。
  5. 网络漂移:Cilium BGP+AnycIP阿里云 Terway ENI 弹性网卡可在新节点继续持有原 IP。
  6. 编排层:Docker Swarm 的drain、Kubernetes 的PodDisruptionBudget + eviction API 是官方标准做法。
  7. 业务层:应用需实现优雅关闭钩子(spring-boot-graceful-shutdown、nginx quit、go http.Server.Shutdown)与健康检查端点
  8. 成本控制:Spot + 按需混部,HPA 基于 QPS 与价格双维度伸缩,防止迁移后成本反跳。

答案

  1. 监听回收信号
    在每台 Spot 实例部署daemonset 级别的 termination-handler 容器,每 2 秒轮询云厂商元数据接口;一旦拿到非空 termination-time,立即向本机 Docker daemon 与上层编排发送drain 事件

  2. 冻结调度
    若使用 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 只漂到非待回收节点

  3. 触发容器优雅退出
    在 Dockerfile 中定义
    STOPSIGNAL SIGTERM
    并配置
    HEALTHCHECK --interval=5s --retries=3 CMD curl -f http://localhost:8080/health || exit 1
    应用代码监听 SIGTERM,完成正在处理的请求排空数据库连接池关闭分布式锁释放后再退出,保证事务级一致性

  4. 快照与数据迁移
    对有状态服务,提前使用云盘快照NAS 共享卷;在收到回收信号后调用云 API 创建一致性快照,并在目标节点原子挂载同盘;若使用 Docker 卷插件(如 rexray/ebs),只需volume ID 漂移,无需复制数据。

  5. 镜像预热
    在集群内搭建Harbor 本地缓存并开启P2P 预热(Dragonfly、Kraken);目标节点已提前docker pull 最新镜像层,容器启动耗时 <10 秒

  6. 网络会话保持
    对外流量经SLB + 弹性网卡 ENI;容器漂移后 ENI 随 Pod 重新绑定,IP 不变,长连接由SLB 优雅断开;对内 RPC 使用服务网格(Istio)+ 重试超时策略,消费者侧无感知。

  7. 验证与回滚
    迁移完成后,通过Prometheus 指标验证p99 延迟无抖动错误率 <0.1%;若超时未完成,自动回滚到同规格按需实例,并触发钉钉/飞书告警,人工介入。

拓展思考

  1. 如果业务是GPU 训练任务,Spot 回收会导致显存数据丢失,可考虑checkpoint 到 CPFS 并行文件系统,训练框架(PyTorch Lightning、TensorFlow Checkpoint)每 5 分钟自动保存,从最近 epoch 恢复,把浪费的 GPU 时长控制在 5% 以内。
  2. 混合云边缘机房没有云厂商元数据接口时,可自研heartbeat + 租约机制:节点每 30 秒向 etcd 续租,租约过期即触发 drain,实现与云厂商解耦的 Spot 模拟
  3. 成本极致优化场景,可引入Spot 实例多样性池(x86/ARM、不同规格族),结合Docker buildx 多架构镜像,让调度器优先选择低价 ARM Spot,迁移时架构无感,进一步降低 30% 计算费用