一次pod无法ready的问题定位

原先可以正常部署的项目,在新的部署中突然提示pod无法ready,本文记录定位思路及解决方式。

问题现象

查看pod事件,发现pod在启动时readiness探活一直失败,进而导致pod一直在重启。

定位思路

  1. 简单排查无法定位原因,将pod的部署manifest文件中,探活端口关闭,以便登录pod定位。注释代码如下:
readinessProbe:
  tcpSocket:
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 10
  1. 登录pod手动启动服务

手动启动服务,启动后使用netstat命令查看网络状态,如下:

netstat1.png

发现存在一个SYN_SENT状态的连接,说明到此IP的网络连接存在问题(关于SYN_SENT状态可自行Google)。

发现服务在停留大约2min后,可正常启动,正常启动后再次查看netstat输出,如下:

netstat1.png

服务在正常启动后,SYN_SENT状态的连接消失,基本可判定是该网络连接直接阻塞了服务启动。

  1. 阅读代码定位

首先全局搜索,发现并没有直接调用此IP的代码。接着在main函数的关键路径添加打印日志,发现main函数第一句打印信息的执行大约在2min后,与SYN_SENT时间基本一致。Go语言中,在main函数前执行的只有init函数。服务代码并没有直接实现的init函数,所以基本可判定是依赖的第三方包中init函数引发的问题。

由于没有很好的根据IP地址反向查找域名的方法,所以只能继续通过全局搜索func init()关键字来排查。对于每个搜索结果检查是否存在连接网络的行为。好在搜索结果不过,最终发现确实某个第三方库的init函数中会向某域名发起连接,ping域名得到的IP与SYN_SENT状态IP一致:

ping.png

  1. 经验

整个的定位过程中也走过一些弯路,比如开始试图通过pprof去发现一些有用的线索,但并未成功。通过trace得到的网络IO图也没发现此网络调用。

当开发可能被外部依赖的第三方库时,init函数中尽量避免网络IO等操作,以防使用者所处网络环境不通导致业务问题。