尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

从“流水线 600 秒超时”到跨境 EIP 根因:香港 ACK 滚动发布故障技术复盘

从“流水线 600 秒超时”到跨境 EIP 根因:香港 ACK 滚动发布故障技术复盘 Engineering Case Study · RCA · Postmortem · Kubernetes · ACK · EIP · Cross-border Network脱敏说明本文隐藏真实服务名、节点 IP、EIP、实例 ID、集群 ID、镜像地址和人员信息保留 Kubernetes、微信支付、ACK、EIP 等技术要素及完整故障逻辑。一、背景看起来是流水线超时实际不是流水线问题一次测试环境滚动发布中流水线更新镜像后持续等待 Deployment 就绪状态长期停留在replicas2 / readyReplicas1 / availableReplicas1最终超过 600 秒后失败。第一眼很容易怀疑发布插件、kubectl 或流水线本身卡住。实际排查证明镜像已经成功更新新 Pod 也确实被创建真正的问题是新 Pod 一直无法完成应用启动并进入 Ready。图 1滚动发布与外部依赖的故障现场二、Symptoms流水线为什么一直是 2 / 1Kubernetes 现场的关键状态是旧 Pod 正常新 Pod 处于0/1、CrashLoopBackOffDeployment 最终出现ProgressDeadlineExceeded。图 2为什么滚动发布长期保持 replicas2 / readyReplicas1测试环境的期望副本数其实只有 1。滚动更新时Kubernetes 会临时同时保留旧 Pod 和新 Pod只有新 Pod Ready 后才删除旧 Pod。因此“2 / 1”说明 Kubernetes 正在保护已有可用副本而不是流水线没有执行。关键认知replicas2 / readyReplicas1在滚动发布期间并不等于“多出来一个副本”而是“旧版本仍健康新版本尚未接管”。三、Investigation从 Probe 失败追到 Spring 启动新 Pod 的事件首先给出明确方向Liveness Probe 访问应用端口时收到connection refused。容器被 kubelet 反复终止和重启退出码表现为 137。Liveness probe failed: dial tcp pod-ip:8083: connect: connection refused Container failed liveness probe, will be restarted继续进入应用日志后关键异常出现在微信支付配置初始化阶段Spring 创建支付配置 Bean 时同步调用微信支付平台证书接口该请求发生Connect timed out/Network unreachable随后 Bean 初始化异常应用端口始终没有成功监听。Bean public Config createWechatPayConfig() { return new RSAAutoCertificateConfig.Builder() // ... .build(); // 构建阶段同步获取平台证书 }这一步非常关键Probe 失败不是最初原因只是应用没有启动成功后的表现。四、完整故障链图 3从普通 EIP 到流水线超时的完整因果链五、Root Cause为什么只有新节点失败新 Pod 被调度到最近新增的一台香港工作节点。对照正常节点后发现两台节点都可以访问阿里云、百度等外部服务但只有新节点访问微信支付中国内地目标地址时持续超时。进一步排查安全组、节点网络和出口 IP 后云厂商最终确认新节点绑定的是普通香港 EIP其到中国内地目标公网 IP 的跨境链路质量异常链路追踪中间多跳无响应。更换为 BGP 多线精品 EIP 后微信支付接口立即恢复可达流水线重新执行成功。最终根因新增香港节点的普通 EIP 跨境访问中国内地微信支付服务器时链路不稳定。六、已排除的假设图 4排障过程中如何逐层排除错误方向假设证据结论kubectl 的 --dry-runtrue 导致没发布Deployment 镜像已更新新 Pod 已创建排除流水线插件卡死流水线只是在等待 Deployment 就绪排除安全组配置不同正常节点和异常节点使用相同安全组排除安全组差异整个节点无法联网节点能正常访问其他互联网目标排除全面断网微信支付通用 IP 白名单故障是 TCP timeout/network unreachable而非 HTTP 业务拒绝不是主因镜像发布失败新 Pod 已执行到 Spring 初始化阶段排除镜像未部署跨境出口链路更换精品线路 EIP 后接口与发布同时恢复确认七、Resolution更换精品线路 EIP 为什么能解决此次异常出口对部分境外目标可用但到中国内地微信支付地址链路不稳定。更换为 BGP 多线精品 EIP 后目标接口恢复连接随后新 Pod 正常启动并通过探针Deployment 滚动更新完成流水线成功。验证项结果安全组保持不变问题随 EIP 线路变更消失业务代码未因本次网络修复而修改换出口后即可启动微信支付平台证书接口恢复可连接新 Pod成功启动并 ReadyDeployment滚动更新完成流水线重新执行成功这是非常强的闭环证据只改变出口线路故障链整体消失。八、5 Whys为什么一个网络问题能拖垮整次发布图 55 Whys 根因分析九、直接根因与放大因素必须分开层级问题说明直接根因普通香港 EIP → 中国内地目标的跨境链路异常导致微信支付平台证书请求超时应用放大因素Spring Bean 初始化同步依赖外部微信接口外部网络异常直接阻止应用启动K8s 放大因素缺少更合适的 startupProbe 分层应用未完成启动时 Liveness 已开始判定存活平台治理问题新增节点没有外部依赖 Preflight节点加入集群后才通过发布暴露出口问题网络架构问题每个节点出口能力存在差异同一集群 Pod 因落到不同节点而表现不同如果只把问题总结成“换 EIP”是不够的因为下一次可能换成短信、地图、对象存储或其他跨境外部依赖。更完整的复盘必须同时处理根因和放大器。十、架构反思 1支付证书不应该决定整个服务能不能启动当前启动方式把微信支付证书获取放在 Spring Bean 初始化阶段。一旦外部接口不可达整个应用 Context 创建失败HTTP 端口无法监听。更合理的方向是支付组件延迟初始化、有限重试、后台刷新或启动后异步加载。即使支付暂时不可用订单查询、商家管理等不依赖支付的功能也应该能够启动支付能力通过健康状态单独降级。外部依赖应该影响能力可用性尽量不要影响进程可启动性。十一、架构反思 2startupProbe、livenessProbe、readinessProbe 应各司其职本次应用还没监听端口时Liveness 连续失败并触发重启。对于启动阶段需要较长初始化的 Java 服务应使用startupProbe给启动阶段单独的容忍窗口。startupProbe: httpGet: path: /health port: 8083 periodSeconds: 5 failureThreshold: 60 livenessProbe: httpGet: path: /health/live port: 8083 readinessProbe: httpGet: path: /health/ready port: 8083以上仅作为架构示例实际阈值应依据服务真实启动时间设置。核心原则是startup 判断“是否还在启动”liveness 判断“是否需要重启”readiness 判断“是否可以接流量”。十二、架构反思 3节点加入集群前必须做出口一致性检查一个 ACK 节点能加入 Kubernetes不代表它具备运行所有业务的网络条件。新增节点至少应该检查 DNS、关键端口、出口 IP 和核心第三方依赖。节点 Preflight 建议 1. DNS 解析 2. HTTPS 443 连通性 3. 微信支付平台 4. 对象存储 5. 短信 / 邮件 6. 重要配送 / 地图接口 7. 当前出口公网 IP 8. 与已有健康节点做对比如果关键依赖不通过应在节点进入业务调度前阻断或打 taint而不是等到滚动发布时才发现。十三、建议的目标架构图 6网络、应用启动和 Probe 的目标架构香港集群如果长期需要访问中国内地服务建议统一治理出口而不是让每台节点随机绑定不同普通 EIP。可选方向包括精品线路 EIP、统一 NAT/SNAT 出口以及在确有需要时评估全球加速。统一出口还有一个额外好处第三方看到的来源 IP 更稳定网络质量、白名单和审计都更容易管理。十四、后续优化清单优先级事项目的P0香港关键工作节点统一使用经过验证的跨境出口直接避免同类网络故障P0新增节点执行外部依赖 Preflight节点上线前发现网络问题P0微信支付证书初始化从 Spring 启动关键路径解耦外部网络异常不再阻止整个服务启动P0异常日志中的 Authorization 等敏感头脱敏避免凭据泄露P1Deployment 增加 startupProbe防止启动阶段被 Liveness 过早杀死P1记录 Pod 节点、出口 IP 和关键依赖耗时提升跨节点问题可观测性P1建立发布失败 Runbook统一排查顺序P2评估统一 NAT / GA 出口治理降低节点间出口差异十五、可复用的 Kubernetes 发布超时 Runbook1. 查看 Deployment / rollout 2. 对比新旧 Pod 3. describe 异常 Pod 看 Event 4. 查看当前与 --previous 日志 5. 判断 Probe 失败是原因还是结果 6. 对比异常节点与健康节点 - 安全组 - 路由 / NAT / EIP - DNS - 外部依赖 - 出口公网 IP 7. 做最小变量验证 - 本次只更换 EIP 后重新发布十六、Lessons Learned1. 流水线超时通常只是症状。真正故障往往在 Deployment、Pod、应用启动或外部依赖。2. 滚动更新的 2/1 状态是重要线索。它说明旧版本仍可用、新版本没有 Ready。3. 同一集群不同节点不一定拥有相同网络能力。安全组相同也不代表公网出口质量一致。4. 外部 API 不应该成为应用进程启动的硬依赖。特别是支付、短信、地图等公网服务。5. Probe 是保护机制也可能放大启动问题。Probe 设计必须符合应用真实生命周期。6. 最有价值的验证是单变量闭环。本次更换 EIP 后无需改业务代码整个发布链立即恢复显著增强了根因结论的可信度。十七、总结这次故障表面上只是一次“流水线一直 2/1、最终 600 秒超时”但完整链路跨越了云网络、Kubernetes 滚动更新、Spring Boot 生命周期、微信支付 SDK 和健康探针。最终直接根因是香港普通 EIP 到中国内地微信支付目标的跨境链路异常而更值得改进的工程问题是系统没有在节点上线前验证外部依赖、应用启动又同步绑定外部网络、Probe 也没有为启动阶段提供清晰隔离。一句话总结发布超时不是根因CrashLoopBackOff 也不是根因真正的根因必须沿着“流水线 → Deployment → Pod → 应用启动 → 节点网络 → 外部依赖”一路追到底。
返回列表