• 终于对探针下手了



    1. kubernetes 健康检查

    打造一个完全不出事的容器是不可能的,因此需要对容器进行健康检查,以 check 容器是否处于可用状态。

    健康检查可分为进程级健康检查和业务级健康检查两种:

    • 进程级健康检查即检查容器进程是否存活,kubelet 定期通过 docker daemon 获取所有 docker 进程的运行情况,如果发现某个容器未正常运行,则重启该容器。

    • 业务级健康检查是更细粒度的健康检查,试想容器进程处于死锁状态,此时容器是不可用的,但是容器进程是运行的,kubelet 不会重启该容器。针对这种情况 kubernetes 设计了 probe 探针来检查容器是否可用。

    probe 又分两种:活性探针(liveness probe)和业务探针(readiness probe)。

    1.1 liveness probe

    以 livenss probe 为例,在启动容器时执行一段死锁代码如下:

    #coding:utf8
    import threading
    import time
    
    num = 0
    lock = threading.Lock()
    
    def func(n):
        lock.acquire()
        print n
        if(n == 5):
            print "deadLock"
            raise Exception('deadLock')
        lock.release()
    
    if __name__ == "__main__":
        t4 = threading.Thread(target=func, args=(5,))
        t1 = threading.Thread(target=func, args=(8,))
        t2 = threading.Thread(target=func, args=(4,))
        t3 = threading.Thread(target=func, args=(2,))
    
        t4.start()
        t1.start()
        t2.start()
        t3.start()
    

    启动包含该死锁代码的容器:

    $ docker run -it centos_python2:v1 python2 /home/deadLock.py
    5
    deadLock here
    Exception in thread Thread-1:
    Traceback (most recent call last):
      File "/usr/lib64/python2.7/threading.py", line 805, in __bootstrap_inner
        self.run()
      File "/usr/lib64/python2.7/threading.py", line 758, in run
        self.__target(*self.__args, **self.__kwargs)
      File "/home/deadLock.py", line 13, in func
        raise Exception('Error: deadLock ')
    Exception: Error: deadLock
    

    此时容器停留在死锁状态,这时候容器是无法正常工作的!

    kubernetes 的 liveness probe 通过三种方式对应用进行健康检查:

    1. HTTP GET
    2. Container Exec
    3. TCP Socket

    这里仅介绍第二种方式 Container Exec(详细信息看 这里),它通过在容器中检查执行命令的退出码来检查容器应用是否正常,如退出码为 0 则认为容器应用工作正常。如下所示:

    [root@chunqiu ~ ]# kubectl exec -it httpd /bin/bash -n ci
    bash-5.0$ /usr/bin/genapik8s --is-alive
    bash-5.0$ echo $?
    0
    
    bash-5.0$ /usr/bin/genapik8s --is-alive2
    unknown option: --is-alive2
    bash-5.0$ echo $?
    3
    

    这里展示了一个容器应用正常工作的容器,使用 genapik8s 检查容器是否可用。对应的 helm chat 如下:

    livenessProbe:
        exec:
          command:
          - /usr/bin/genapik8s
          - --is-alive
        initialDelaySeconds: 15
        periodSeconds: 5
        successThreshold: 1
        failureThreshold: 3
    

    其中,initialDelaySeconds 表示容器启动到执行健康检查的延迟时间,延迟时间的设计是为了容器进程有时间完成必要的初始化工作,而不是在还未启动好之前就被 kubelet 重启了。

    同理,将 livenessProbe 应用在前面死锁的容器,容器中执行命令的退出码不为 0,使得 kubelet 发现到该容器无法正常工作,进而重启该容器。

    1.2 readiness probe

    如果某些容器应用只是暂时性出了问题,而不想 kubelet 对其重启该怎么办呢?kubernetes 提供了 readiness probe 来解决这类问题。类似于 liveness probe,readiness probe 会在容器中执行检查操作,如果检查失败 kubelet 不会重启容器,而是将容器所属的 pod 从 endpoint 列表中删除,这样访问 pod 的请求就会被路由到其它 pod 上。

    根据这一特性,可以构造“相同”副本的 pod,一个为 active,一个为 standby。它们都通过 service 建立连接,service 会将请求路由到 active 的 pod,而不会路由到 standby 的 pod。

    这里仅以单一副本举例,不深入讨论 active 和 standby pod 的情况。构造带 readiness probe 的 pod:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: readinesstester
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: readinessprobe
      template:
        metadata:
          labels:
            app: readinessprobe
        spec:
          containers:
          - name: httpd
            image: docker-httpd:0.2.4
            readinessProbe:
              exec:
                command:
                - cat
                - /tmp/healthy
              initialDelaySeconds: 5
              periodSeconds: 5
    

    container 内包含一个 readinessProbe 探针,它会执行命令 cat /tmp/healthy 检查容器是否健康。容器中 healthy 是不存在的,执行会失败。创建 service 如下:

    apiVersion: v1
    kind: Service
    metadata:
      name: readinessservice
    spec:
      selector:
        app: readinessprobe
      ports:
      - protocol: TCP
        port: 8080
        targetPort: 80
    

    检查 pod 状态:

    [root@chunqiu readinessProbe ]# kubectl get pods -o wide
    NAME                               READY   STATUS             RESTARTS   AGE     IP              NODE
    readinesstester-85bbbd7947-dzsm6   0/1     Running            0          3h34m   10.10.44.173    chunqiu-node-2
    
    [root@chunqiu readinessProbe ]# kubectl describe pods readinesstester-85bbbd7947-dzsm6
    ...
    Status:               Running
    Controlled By:  ReplicaSet/readinesstester-85bbbd7947
    Containers:
      httpd:
        ...
        State:          Running
          Started:      Sun, 30 May 2021 11:57:21 +0800
        Ready:          False
        Restart Count:  0
        Readiness:      exec [cat /tmp/healthy] delay=5s timeout=1s period=5s #success=1 #failure=3
    Events:
      Type     Reason     Age                       From     Message
      ----     ------     ----                      ----     -------
      Warning  Unhealthy  3m13s (x2460 over 3h28m)  kubelet  Readiness probe failed: cat: /tmp/healthy: No such file or directory
    

    这里仅列出需要重点关注的信息。从 pod 状态来看, pod 并未 ready,不过 pod 并未被重启,且 pod 是 running 的。进一步查看 service 对应的 pod endpoint 是否存在:

    [root@chunqiu readinessProbe ]# kubectl describe service readinessservice
    Name:              readinessservice
    Namespace:         default
    Labels:            <none>
    Annotations:       <none>
    Selector:          app=readinessprobe
    Type:              ClusterIP
    IP:                10.254.194.117
    Port:              <unset>  8080/TCP
    TargetPort:        80/TCP
    Endpoints:
    Session Affinity:  None
    Events:            <none>
    

    可以看到未 ready 的 pod endpoints 并未放到 service 中,虽然 pod 有自己的 ip。

    2. Deployment 和 replicaSet

    这一节我们这么部署 pod 和 service 看看会发生什么。

    首先创建不带 readinessProbe 的 pod:

    [root@chunqiu readinessProbe ]# kubectl get pods -o wide
    NAME                              READY   STATUS     RESTARTS   AGE     IP              NODE
    readinesstester-cd586b86d-b4n7t   1/1     Running    0          26s     10.10.44.179    chunqiu-node-2
    
    [root@chunqiu readinessProbe ]# kubectl describe service readinessservice
    Name:              readinessservice
    Namespace:         default
    Labels:            <none>
    Annotations:       <none>
    Selector:          app=readinessprobe
    Type:              ClusterIP
    IP:                10.254.194.117
    Port:              <unset>  8080/TCP
    TargetPort:        80/TCP
    Endpoints:         10.10.44.179:80
    Session Affinity:  None
    Events:            <none>
    

    很正常,接着将 readinessProbe 加到 pod 内,重新配置 pod,查看 pod 状态:

    [root@chunqiu readinessProbe ]# kubectl get pods -o wide
    NAME                               READY   STATUS             RESTARTS   AGE     IP              NODE
    readinesstester-85bbbd7947-xj9gv   0/1     Running            0          29s     10.10.44.161    chunqiu-node-2
    readinesstester-cd586b86d-b4n7t    1/1     Running            0          3m51s   10.10.44.179    chunqiu-node-2
    

    发现有两个名为 readinesstester... 的 pod 存在,且状态还不一致,这是为什么呢?

    自上而下通过 Deployment 和 replicatSet 查看 pod 干了什么:

    [root@chunqiu readinessProbe ]# kubectl get deployments.apps
    NAME              READY   UP-TO-DATE   AVAILABLE   AGE
    readinesstester   1/1     1            1           5m39s
    
    [root@chunqiu readinessProbe ]# kubectl describe deployments.apps readinesstester
    ...
    Events:
      Type    Reason             Age    From                   Message
      ----    ------             ----   ----                   -------
      Normal  ScalingReplicaSet  5m48s  deployment-controller  Scaled up replica set readinesstester-cd586b86d to 1
      Normal  ScalingReplicaSet  2m26s  deployment-controller  Scaled up replica set readinesstester-85bbbd7947 to 1
    

    根据 Events 可以看到 deployment-controller scale up 一个 replicaSet readinesstester-85bbbd7947,由这个 replicaSet 接管新的带 readinessProbe pod 的创建:

    [root@chunqiu readinessProbe ]# kubectl get replicasets.apps
    NAME                         DESIRED   CURRENT   READY   AGE
    readinesstester-85bbbd7947   1         1         0       9m13s
    readinesstester-cd586b86d    1         1         1       12m
    
    [root@chunqiu readinessProbe ]# kubectl describe replicasets.apps readinesstester-85bbbd7947
    Name:           readinesstester-85bbbd7947
    Replicas:       1 current / 1 desired
    Pods Status:    1 Running / 0 Waiting / 0 Succeeded / 0 Failed
    Events:
      Type    Reason            Age    From                   Message
      ----    ------            ----   ----                   -------
      Normal  SuccessfulCreate  9m24s  replicaset-controller  Created pod: readinesstester-85bbbd7947-xj9gv
    ...
    

    scale up 的 replicaSet 创建出 Pod,该 pod 的状态并未 ready,导致 deployment 的滚动更新策略一直卡在等待新 replicaSet 创建完成这里,因此会出现两个并行的 pod。从这个示例也可以看出 Deployment 是为了应用的更新而设计的。

    芝兰生于空谷,不以无人而不芳。
  • 相关阅读:
    默认值设置
    关于设置 存储 内部存储空间只显示图片不显示视频的解决方法
    sd卡的监听
    android 设置时间12/24小时制
    详解BMP木马
    C#中类和接口的设计思想(本人认为比较好的思想,欢迎大家讨论指点)
    从XML中读取数据到内存的实例
    如何在代码中通过命令行创建SQL SERVER 数据库
    Visual Studio 2005 新特性 之 可空类型
    install shield11.5 如何制作卸载程序
  • 原文地址:https://www.cnblogs.com/xingzheanan/p/14828311.html
Copyright © 2020-2023  润新知