05 Pod健康检查

现在在Pod的整个生命周期中,能影响到Pod的就只剩下健康检查这一部分了。在k8s集群当中,我们可以通过配置liveness probe(存活探针)readiness probe(可读性探针)来影响容器的生命周期。

  • kubelet通过liveness probe来确定你的应用程序是否正在运行,通俗点讲就是是否还活着。一般来说,如果你的程序一旦崩溃了,kubernetes就会立刻知道这个程序已经终止了,然后就会重启这个程序。而我们的liveness probe的目的就是来捕获到当前应用程序还没有终止,还没有崩溃,如果出现了这些情况,那么就重启处于该状态下的容器,使应用程序在存在bug的情况下依然能够继续运行下去。

  • kubelet使用readiness probe来确定容器是否已经就绪就可以接收流量过来了。这个探针通俗点讲就是说是否准备好了,现在可以开始工作了。只有当Pod中的容器都处于就绪状态的时候kubelet才会认定该Pod处于就绪状态,因为一个Pod下面可能会有多个容器。当然Pod如果处于非就绪状态,那么我们就会将它从Service的Endpoints列表中移除出来,这样我们的流量就不会被路由到这个Pod里面来了。

和前面的钩子函数一样的,我们这两个探针支持下面的几种配置方式:

  • exec: 执行一段命令
  • http:检测某个http请求
  • tcpSocket:使用此配置,kubectl将尝试在指定端口上打开容器的套接字。如果可以建立连接,容器被认为是健康的,如果不能就认为是失败的。实际上就是检查端口。

我们先来给大家演示下存活探针的使用方法,首先我们用exec执行命令的方式来检测容器的存活,如下:(liveness-exec.yaml)

apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec
spec:
  containers:
    - name: liveness
      image: busybox
      args:
        - /bin/sh
        - -c
        - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
      livenessProbe:
        exec:
          command:
            - cat
            - /tmp/healthy
        initialDelaySeconds: 5
        periodSeconds: 5

我们这里需要用到一个新的属性:livenessProbe,下面通过exec执行一段命令:

  • periodSeconds: 表示让kubelet每隔5s执行一次存活探针,也就是每5s执行一次上面的cat /tmp/healthy命令,如果命令执行成功了,将返回0,那么kubelet就会认为当前这个容器是存活的,如果返回的是非0值,那么kubelet就会把该容器杀掉然后重启它。periodSeconds的值默认是10s,最小1s。
  • initialDelaySeconds: 表示在第一次执行探针的时候要等待5s,这样能够确保我们的容器能够有足够的时间启动起来。大家可以想象一下,如果你的第一次执行探针等候的时间太短,是不是很有可能容器还没正常启动起来,所以存活探针很可能始终都是失败的,这样就会无休止的重启下去。

我们在容器启动的时候,执行了如下命令:
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"
意思是说在容器最开始的30s内创建一个/tmp/healthy文件,在这30s内执行cat /tmp/healthy命令都会返回一个成功的返回码。30s后,我们删除这个文件,现在执行cat /tmp/healthy是不是就会失败(默认检测失败3次才认为失败),所以这个时候就会重启容器了。

以下是过程

.......
.......
.......
Conditions:
  Type              Status
  Initialized       True
  Ready             False
  ContainersReady   False
  PodScheduled      True
Volumes:
  default-token-557h9:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-557h9
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age        From               Message
  ----    ------     ----       ----               -------
  Normal  Scheduled  <unknown>  default-scheduler  Successfully assigned default/liveness-exec to node02
  Normal  Pulling    2s         kubelet, node02    Pulling image "busybox"

##################################################################
.......
.......
.......
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-557h9:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-557h9
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age        From               Message
  ----    ------     ----       ----               -------
  Normal  Scheduled  <unknown>  default-scheduler  Successfully assigned default/liveness-exec to node02
  Normal  Pulling    10s        kubelet, node02    Pulling image "busybox"
  Normal  Pulled     4s         kubelet, node02    Successfully pulled image "busybox"
  Normal  Created    4s         kubelet, node02    Created container liveness
  Normal  Started    4s         kubelet, node02    Started container liveness
##################################################################
.......
.......
.......
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-557h9:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-557h9
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age        From               Message
  ----    ------     ----       ----               -------
  Normal  Scheduled  <unknown>  default-scheduler  Successfully assigned default/liveness-exec to node02
  Normal  Pulling    16s        kubelet, node02    Pulling image "busybox"
  Normal  Pulled     10s        kubelet, node02    Successfully pulled image "busybox"
  Normal  Created    10s        kubelet, node02    Created container liveness
  Normal  Started    10s        kubelet, node02    Started container liveness

##################################################################
.......
.......
.......
Volumes:
  default-token-557h9:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-557h9
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type     Reason     Age                From               Message
  ----     ------     ----               ----               -------
  Normal   Scheduled  <unknown>          default-scheduler  Successfully assigned default/liveness-exec to node02
  Normal   Pulling    64s                kubelet, node02    Pulling image "busybox"
  Normal   Pulled     58s                kubelet, node02    Successfully pulled image "busybox"
  Normal   Created    58s                kubelet, node02    Created container liveness
  Normal   Started    58s                kubelet, node02    Started container liveness
  Warning  Unhealthy  14s (x3 over 24s)  kubelet, node02    Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
  Normal   Killing    14s                kubelet, node02    Container liveness failed liveness probe, will be restarted

我们可以观察到容器是正常启动的,在隔一会,比如60s后,再查看下Pod的Event,在最下面有一条信息显示liveness probe失败了,容器将要重启。然后可以查看到Pod的RESTARTS值加1了:(我这里已经加到5了)

[root@node01 ~]# kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
hook-demo1                      1/1     Running   0          25d
init-demo                       1/1     Running   0          25d
liveness-exec                   1/1     Running   5          7m20s
nginx-deploy-745bd74b44-4k2np   1/1     Running   0          26d
nginx-deploy-745bd74b44-jr7wv   1/1     Running   0          26d
nginx-deploy-745bd74b44-ngkrg   1/1     Running   0          26d
nginx-deploy-745bd74b44-plgkw   1/1     Running   0          26d

同样的,根据 periodSeconds 属性我们可以知道 kubelet 需要每隔3秒执行一次 liveness Probe,该探针将向容器中的 server 的 8080 端口发送一个 HTTP GET 请求。如果 server 的 /healthz 路径的 handler 返回一个成功的返回码,kubelet 就会认定该容器是活着的并且很健康,如果返回失败的返回码,kubelet 将杀掉该容器并重启它。initialDelaySeconds 指定kubelet 在该执行第一次探测之前需要等待3秒钟。

apiVersion: v1
kind: Pod
metada: 
  name: liveness-http
spec:
  containers:
    - name: liveness
      image: cnych/liveness
      args:
        - /server
      livenessProbe:
        httpGet:
          path: /healthz
          port: 8080
          httpHeaders:
            - name: X-Custom-Header
              value: Awesome
        initialDelaySeconds: 3
        periodSeconds: 3

除了上面的 exec 和 httpGet 两种检测方式之外,还可以通过 tcpSocket 方式来检测端口是否正常,大家可以按照上面的方式结合kubectl explain命令自己来验证下这种方式。

另外前面我们提到了探针里面有一个initialDelaySeconds的属性,可以来配置第一次执行探针的等待时间,对于启动非常慢的应用这个参数非常有用,比如 Jenkins、Gitlab 这类应用,但是如何设置一个合适的初始延迟时间呢?这个就和应用具体的环境有关系了,所以这个值往往不是通用的,这样的话可能就会导致一个问题,我们的资源清单在别的环境下可能就会健康检查失败了,为解决这个问题,在 Kubernetes v1.16 版本官方特地新增了一个startupProbe(启动探针),该探针将推迟所有其他探针直到 Pod 完成启动为止,使用方法和存活探针一样:

startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  failureThreshold: 30  # 尽量设置大点
  periodSeconds: 10

比如上面这里的配置表示我们的慢速容器最多可以有5分钟(30个检查 * 10秒= 300s)来完成启动。

有的时候,应用程序可能暂时无法对外提供服务,例如,应用程序可能需要在启动期间加载大量数据或配置文件。在这种情况下,您不想杀死应用程序,也不想对外提供服务。那么这个时候我们就可以使用readiness probe来检测和减轻这些情况。 Pod 中的容器可以报告自己还没有准备,不能处理 Kubernetes 服务发送过来的流量。readiness probe的配置跟liveness probe基本上一致的。唯一的不同是使用readinessProbe而不是livenessProbe。两者如果同时使用的话就可以确保流量不会到达还未准备好的容器,准备好过后,如果应用程序出现了错误,则会重新启动容器。对于就绪探针我们会在后面 Service 的章节和大家继续介绍。

另外除了上面的initialDelaySeconds和periodSeconds属性外,探针还可以配置如下几个参数:

  • timeoutSeconds:探测超时时间,默认1秒,最小1秒。
  • successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功。默认是 1,但是如果是liveness则必须是 1。最小值是 1。
  • failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败。默认是 3,最小值是 1。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容