Kubernetes中长连接零中断下线需通过PreStop钩子主动拒新流量并等待连接释放:PreStop在SIGTERM前同步执行,须配合足够terminationGracePeriodSeconds及Nginx/注册中心动态摘流。

在Kubernetes中实现长连接业务(如WebSocket、gRPC流)的零中断下线,必须确保Pod终止前主动拒绝新流量并等待存量连接自然释放,否则用户会感知到连接被强制断开。
理解PreStop钩子的执行时机与约束
PreStop钩子在kubelet发起Pod删除流程后、发送SIGTERM信号之前同步执行,属于容器生命周期的最后一个阻塞阶段。它不是异步回调,Kubernetes会严格等待该钩子完成或超时才继续后续步骤。
terminationGracePeriodSeconds默认为30秒,但PreStop执行时间包含在此窗口内——若钩子耗时25秒,应用只剩5秒响应SIGTERM;若钩子卡死或未退出,整个Pod终止流程将被阻塞直至宽限期结束。
注意:PreStop不会在容器崩溃时触发,只响应API删除、滚动更新、驱逐等管理事件。
配置exec类型PreStop钩子(推荐)
第一步:在容器spec.lifecycle.preStop下定义exec指令,例如执行curl调用应用内置关闭端点:
preStop: exec: command: ["/bin/sh", "-c", "curl -X POST http://localhost:8080/shutdown --connect-timeout 5 --max-time 10 || true"]
第二步:确保应用监听的shutdown端点具备两个能力:立即停止接收新请求(如关闭HTTP Server的监听端口),同时不中断已有长连接;返回200后开始等待连接自然断开。
第三步:将terminationGracePeriodSeconds显式设为60秒,为PreStop+SIGTERM阶段留足缓冲:【必须大于PreStop预期耗时+应用优雅关闭耗时之和】
这一步操作起来很简单,直接把字段加到容器定义里就行,但漏掉宽限期调整会导致钩子来不及执行就被强杀。
配合Nginx主动摘除上游节点
方法一:通过Nginx Plus API动态下线
在PreStop中先调用Nginx Plus的upstream conf API,将当前Pod从upstream组中移除:curl -X PATCH -d '{"weight":0}' http://nginx-plus-api/upstreams/myapp/servers/10.244.1.5:8080。Nginx会立刻停止向该节点转发新请求,但保活已有连接。
方法二:使用Consul或Nacos等注册中心标记下线状态
PreStop中调用服务注册中心API,将本实例健康状态置为false,Nginx upstream通过health check自动剔除该节点。此方式需Nginx配置health_check并启用consul或nacos resolver。
注意:单纯改Nginx配置文件再reload不可行——reload是异步操作,无法保证在SIGTERM前完成,且可能因配置错误导致Nginx进程崩溃。
验证PreStop是否生效
① 执行kubectl delete pod 后立即查看Pod事件:kubectl describe pod ,观察是否有PreStopHook相关日志。
② 进入Pod容器内部,手动运行PreStop命令(如curl shutdown端点),确认返回200且无报错。
③ 在应用日志中搜索关键词“shutting down”或“graceful exit”,确认PreStop触发后应用确实进入了清理流程而非直接收到SIGTERM。
④ 模拟长连接场景:用wscat建立WebSocket连接,在delete pod后观察该连接是否持续存在至少10秒以上,且新连接被拒绝。
如果第④步失败,大概率是Nginx未及时摘除节点或应用shutdown端点未真正停止accept新连接。











