一、问题背景

近期遇到一个特别奇怪的事就是关于 K8s Pod 无法启动的问题,因为平时通过 Jenkins 打包成 Docker 后,再自动触发已经建好的 Pipline 就可以部署到 Kubernates 平台,但这次打包后发现部署应用到 Kubernates 时 Pod 总无法创建成功,然后 Pod 自动重新部署。

二、原因排查

排查问题的路径有:

  • 通过查看 Kubernates 容器组中事件排查 Pod 无法起来的原因,类似于下面这张图
    在这里插入图片描述
  • 通过查看应用的最后打印日志排查问题;在这要说一句,在通过Pod 打印的日志排查问题是,有时应用日志刷的时快时慢,看不到最后打印的日志信息(Pod 重启后会将上一次日志清掉)需要有耐心,不可太急躁,觉得实在太慢可以将 Pod 资源限制的 CPU 调大些;

可能存在的问题:

  1. Pod 无法起来时应该最先想到的是配置文件是否正常拉取,配置是否正确,少配置项、配置格式错误或编码错误等等;

  2. 应用程序本身是否编写正确,例如包冲突导致应用无法启动;

  3. 应用程序依赖组件是否正常,例如 RabbitMQ、Mongodb、Reids、数据库、第三方应用等等等;

  4. 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。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐