近期遇到一个特别奇怪的事就是关于 K8s Pod 无法启动的问题,因为平时通过 Jenkins
打包成 Docker 后,再自动触发已经建好的 Pipline
就可以部署到 Kubernates 平台,但这次打包后发现部署应用到 Kubernates 时 Pod 总无法创建成功,然后 Pod 自动重新部署。
排查问题的路径有:
可能存在的问题:
Pod 无法起来时应该最先想到的是配置文件是否正常拉取,配置是否正确,少配置项、配置格式错误或编码错误等等;
应用程序本身是否编写正确,例如包冲突导致应用无法启动;
应用程序依赖组件是否正常,例如 RabbitMQ、Mongodb、Reids、数据库、第三方应用等等等;
Pod 内存不足(因为加上了资源限制),类似于下面的容器配置定义:
"resources": {
"limits": {
"cpu": "1",
"memory": "1Gi"
},
"requests": {
"cpu": "500m",
"memory": "500Mi"
}
}
5. 检查 liveness
的健康检查探针配置参数,因为这个探针配置也会影响到 Pod 的启动,如下配置,大概意思是 liveness
探针使用 HTTP
协议,地址 /actuator/health
+ port=8080
,Pod 创建 300s
后开始检测,超时是 1s
,每 10s
执行一次探测,连续失败3
次即失败,失败后成功1
次即成功;这里说一嘴 readiness
探针,和liveness
类似,两者的主要区别在于 liveness
主要用来确定何时重启容器,默认成功;readiness
主要来确定容器是否已经就绪,默认失败,不可相互替代。而是相互协作的关系。
"livenessProbe": {
"httpGet": {
"path": "/actuator/health",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 300,
"timeoutSeconds": 1,
"periodSeconds": 10,
"successThreshold": 1,
"failureThreshold": 3
},
"readinessProbe": {
"httpGet": {
"path": "/actuator/health",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 60,
"timeoutSeconds": 1,
"periodSeconds": 10,
"successThreshold": 1,
"failureThreshold": 3
}
一条一条对着上述可能存在的问题排查,发现通过将 Pod
资源限制加至 cpu=2,memory=4Gi
时应用偶尔能够正常启动,但还存在不能启动的情况,然后在本机通过 VisualVM 工具监测到应用启动后 heap 内存用了不到 500M
,另外通过查看 Pod 日志时,发现应用程序启动时所带的参数(如下图)得出结论,不是内存问题。
exec java -Xmx512m -XX:ParallelGCThreads=1 -XX:ConcGCThreads=1
下图为 Pod 日志,可以看出 最大堆内存为 512M。
然后应用将资源限制还原,发现 liveness
探针的 initialDelaySeconds=0
,于是修改 liveness
探针的 initialDelaySeconds=300
解决问题。
我这原因是因为第 5
条原因导致。因为应用启动时间比较长,在资源限制不变得情况下正常启动需要耗时60s,加上之前 liveness
的配置不合理,如下:
"livenessProbe": {
"httpGet": {
"path": "/actuator/health",
"port": 8080,
"scheme": "HTTP"
},
"initialDelaySeconds": 0,
"timeoutSeconds": 1,
"periodSeconds": 10,
"successThreshold": 1,
"failureThreshold": 3
},
因为 initialDelaySeconds
设置的是0,导致连续3次健康检查失败(理论是在重启 Pod 30s 后)就会自动重启 Pod。