Kubernetes Pod终止时出现ECONNREFUSED错误的排查求助
问题分析与解决方案
核心问题
搜索逻辑服务(search-api)在Pod缩容/滚动更新时,API网关调用频繁出现ECONNREFUSED错误,即使添加了preStop: sleep 60仍无法彻底解决,滚动更新时错误更频发。
可能的根因
- Endpoint更新与Pod终止存在时间差:Kubernetes从Service的Endpoint列表移除Pod,和Pod实际停止接受请求的窗口没完全对齐,哪怕加了preStop延迟,仍可能有流量打到已标记为Terminating的Pod
- Readiness探针未主动摘除流量:当前readiness probe仅检查/healthz,但Pod进入Terminating状态后,Kubernetes自动移除就绪状态的动作有延迟,网关可能还持有旧连接
- 网关DNS缓存与连接复用问题:即便加了
connection: close,网关侧DNS缓存可能保留旧Pod IP,或HTTP客户端连接池未及时清理失效连接 - 滚动更新策略细节不合理:
maxUnavailable: 0虽保证可用性,但maxSurge:2可能导致新Pod未就绪时旧Pod已开始终止,引发流量分发异常
针对性解决方案
1. 优化Readiness探针与Pod终止逻辑
在preStop钩子中先主动让readiness probe失败,彻底从Service Endpoint移除后再延迟终止。修改Deployment的相关配置:
containers: # ... 保留原有其他配置 lifecycle: preStop: exec: command: - sh - -c - "touch /tmp/terminating && sleep 60" # 创建标记文件触发就绪探针失败 readinessProbe: exec: # 替换原httpGet探针,结合健康检查与终止标记判断 command: - sh - -c - "test ! -f /tmp/terminating && curl -f http://localhost:8080/healthz" initialDelaySeconds: 15 periodSeconds: 5
这样Pod启动终止流程时,立刻让就绪探针失败,Kubernetes会快速将其从Endpoint列表剔除,sleep60秒再真正终止,确保流量完全切走。
2. 调整Pod生命周期时间配置
延长终止宽限期,给足Endpoint更新的时间;同时拉长新Pod的就绪等待时间,确保稳定后再接收流量:
spec: minReadySeconds: 10 # 原5秒,延长至10秒确保新Pod稳定 terminationGracePeriodSeconds: 120 # 原90秒,延长至120秒覆盖preStop的60秒
3. 优化API网关的HTTP客户端配置
禁用长连接、清理DNS缓存、添加重试机制,避免失效连接和旧IP带来的问题。修改axios配置:
const http = require('http'); const https = require('https'); const axios = require('axios'); const axiosRetry = require('axios-retry'); // 创建axios实例,禁用长连接 const axiosInstance = axios.create({ headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'X-Request-Id': request_id }, httpAgent: new http.Agent({ keepAlive: false, maxSockets: 100, timeout: 5000 }), httpsAgent: new https.Agent({ keepAlive: false, maxSockets: 100, timeout: 5000 }), timeout: 5000 }); // 针对连接错误添加重试 axiosRetry(axiosInstance, { retries: 2, retryDelay: (count) => count * 100, retryCondition: (err) => err.code === 'ECONNREFUSED' || err.code === 'ETIMEDOUT' }); // 调用接口时使用该实例 await axiosInstance.post('http://search-api:80/logic/endpoint', payload);
4. 调整滚动更新策略
降低每次更新的Pod数量,确保新Pod完全就绪后再终止旧Pod:
strategy: rollingUpdate: maxSurge: 1 # 原2,改为每次仅新增1个Pod maxUnavailable: 0 type: RollingUpdate
5. 启用GKE连接排空功能
借助GKE的BackendConfig实现连接排空,确保Pod终止前处理完现有连接,不再接收新流量:
首先创建BackendConfig资源:
apiVersion: cloud.google.com/v1 kind: BackendConfig metadata: name: search-api-backend-config spec: connectionDraining: drainingTimeoutSec: 60
然后给search-api的Deployment添加注解:
metadata: annotations: cloud.google.com/backend-config: '{"default": "search-api-backend-config"}'
验证步骤
- 应用所有配置后,执行滚动更新:
kubectl rollout restart deployment search-api - 监控网关错误日志,观察
ECONNREFUSED错误是否消失 - 缩容Pod时,检查Endpoint列表:
kubectl get endpoints search-api,确认Terminating状态的Pod被及时移除 - 查看Pod事件:
kubectl describe pod <pod-name>,确认preStop触发后readiness probe立即失败
内容的提问来源于stack exchange,提问作者Wazbat
相关产品推荐
相关产品推荐

