k8s系列之七Health Check

本文介绍了Kubernetes如何通过Liveness和Readiness探测实现更智能的容器健康检查,包括默认的重启策略、自定义探测规则以及在ScaleUp和RollingUpdate中的应用,特别强调了maxSurge和maxUnavailable参数在滚动更新中的作用。
摘要由CSDN通过智能技术生成

强大的自愈能力是Kubernetes这类容器编排引擎的⼀个重要特性。自愈的默认实现方式是自动重启发生故障的容器。除此之外,用户还可以利用Liveness和Readiness探测机制设置更精细的健康检查,进而实现:
(1)零停机部署。
(2)避免部署无效的镜像。
(3)更加安全的滚动升级。

1.1 默认的健康检查

默认情况下,每个容器启动时都会执行一个进程,由Dockerfile中的CMD或ENTRYPOINT指定。如果进程退出时的返回码不为0,则认为容器发生了故障,K8S会根据重启策略(restartPolicy)重启容器。
vi healthcheck.yaml

apiVersion: v1
kind: Pod
metadata:
  name: healthcheck-demo
  labels:
    test: healthcheck
spec:
  restartPolicy: OnFailure
  containers:
    - name: healthcheck
      image: busybox
      imagePullPolicy: IfNotPresent
      args:
      - /bin/sh
      - -c
      - sleep 10; exit 1

Pod的restartPolicy设置为OnFailure,默认为Always。sleep10;exit1模拟容器启动10秒后发生故障。
执行kubectlapply创建Pod,命名为healthcheck。

[root@k8s-master ~]# kubectl get pod healthcheck-demo
NAME               READY   STATUS             RESTARTS   AGE
healthcheck-demo   0/1     CrashLoopBackOff   3          101s

可看到容器当前已经重启了3次。
在上面的例子中,容器进程返回值非零,必须等到进程退出后的返回值是非零才会触发重启策略,不能直接监测容器是否是健康。

K8S中有没有更好的机制能够实现智能一点的健康检查呢?答案就是使用Liveness与Readinesss。

1.2 Liveness探测

Liveness的参数:

initialDelaySeconds:容器启动后第一次执行探测是需要等待多少秒,看运行的服务而定。
periodSeconds:执行探测的频率,默认是10秒,最小1秒。
timeoutSeconds:探测超时时间,默认1秒,最小1秒。
successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功,默认是1,对于liveness必须是1,最小值是1。
failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败。默认是3。最小值是1.

vi liveness-demo.yml

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

这里启动pod后会创建文件夹 /tmp/healthy,30秒后删除,在我们的设置中,如果 /tmp/healthy 存在,则认为容器处于正常状态,否则认为发生故障。

需要注意的就是livenessProbe部分的定义了:

(1)探测方法:通过cat命令查看/tmp/healthy是否存在;如果返回值为0,则探测成功;否则,探测失败;

(2)initialDelaySeconds: 10 => 容器启动10秒之后开始执行liveness探测;

(3)periodSeconds: 5 => 每5秒执行一次liveness探测;如果连续执行3次探测都失败,那么就会杀掉并重启容器;

下面快速地验证一下:

[root@k8s-master ~]# kubectl describe pod liveness-demo
deployment.apps/httpd configured
  Normal   Pulling    71s (x4 over 4m29s)  kubelet, k8s-node2  Pulling image "busybox"
  Normal   Pulled     44s (x4 over 4m27s)  kubelet, k8s-node2  Successfully pulled image "busybox"
  Normal   Created    44s (x4 over 4m27s)  kubelet, k8s-node2  Created container liveness
  Normal   Started    44s (x4 over 4m27s)  kubelet, k8s-node2  Started container liveness
  Warning  BackOff    2s (x7 over 2m49s)   kubelet, k8s-node2  Back-off restarting failed container
[root@k8s-master ~]# kubectl get pod liveness-demo
NAME            READY   STATUS    RESTARTS   AGE
liveness-demo   1/1     Running   4          5m46s

1.3 Readiness探测

用户通过Liveness探测可以告诉Kubernetes什么时候通过重启容器实现自愈;Readiness探测则是告诉Kubernetes什么时候可以将容器加入到Service负载均衡池中,对外提供服务。

vi readiness-demo.yml

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: readiness
  name: readiness-demo
spec:
  containers:
  - name: readiness
    image: busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf/tmp/healthy; sleep 10
    readinessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 10
      periodSeconds: 5

这个配置文件只是将前面例⼦中的liveness替换为了readiness。

[root@k8s-master ~]# kubectl get pod readiness-demo
NAME             READY   STATUS    RESTARTS   AGE
readiness-demo   1/1     Running   1          107s
Events:
  Type     Reason     Age                  From                Message
  ----     ------     ----                 ----                -------
  Normal   Scheduled  <unknown>            default-scheduler   Successfully assigned default/readiness-demo to k8s-node2
  Normal   Pulling    61s (x3 over 3m13s)  kubelet, k8s-node2  Pulling image "busybox"
  Normal   Pulled     44s (x3 over 2m51s)  kubelet, k8s-node2  Successfully pulled image "busybox"
  Normal   Created    44s (x3 over 2m51s)  kubelet, k8s-node2  Created container readiness
  Normal   Started    44s (x3 over 2m51s)  kubelet, k8s-node2  Started container readiness
  Warning  BackOff    4s (x2 over 73s)     kubelet, k8s-node2  Back-off restarting failed container
  Warning  Unhealthy  4s                   kubelet, k8s-node2  Readiness probe failed: OCI runtime exec failed: exec failed: unable to sta

(1)刚被创建时,其READY状态为不可用;
(2)15秒(initialDelaySeconds + periodSeconds = 10 + 5 = 15)之后,第一次进行Readiness探测成功,其READY状态变为可用。
(3)30秒之后,/tmp/healthy被删除,连续3次Readiness探测均失败后,其READY状态又变为了不可用。

与Liveness的对比

Liveness与Readiness都是K8S的Health Check机制,Liveness探测是重启容器,而Readiness探测则是将容器设置为不可用,不让其再接受Service转发的请求。
Liveness与Readiness是独立执行的,二者无依赖,可以单独使用也可以同时使用。

1.4 Health Check在Scale Up中的应用

对于多副本应用,当执行ScaleUp操作时,新副本会作为backend被添加到Service的负载均衡中,与已有副本⼀起处理客户的请求。考虑到应用启动通常都需要⼀个准备阶段,比如加载缓存数据、连接数据库等,从容器启动到真正能够提供服务是需要⼀段时间的。我们可以通过Readiness探测判断容器是否就绪,避免将请求发送到还没有准备好的backend。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels:
      run: web
  template:
    metadata:
      labels:
        run: web
    spec:
      containers:
      - name: web
        image: myhttpd
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /healthy
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5

---
apiVersion: v1
kind: Service
metadata:
  name: web-svc
spec:
  selector:
    run: web
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080

重点关注readinessProbe部分。这里我们使用了不同于exec的另⼀种探测方法httpGet。
Kubernetes对于该方法探测成功的判断条件是http请求的返回代码在200〜400之间。
上⾯配置的作用是:
(1)容器启动10秒之后开始探测。
(2)如果http://[container_ip]:8080/healthy返回代码不是200〜 400,表示容器没有就绪,不接收Serviceweb-svc的请求。
(3)每隔5秒探测⼀次。
(4)直到返回代码为200〜400,表明容器已经就绪,然后将其加入
到web-svc的负载均衡中,开始处理客户请求。
(5)探测会继续以5秒的间隔执行,如果连续发生3次失败,容器又
会从负载均衡中移除,直到下次探测成功重新加入。

1.5 Health Check在Rolling Update中的应用

假设现在有一个正常运行的多副本应用,我们要对其进行滚动更新即Rolling Update,K8S会逐步用新Pod替换旧Pod,结果就有可能发生这样的一个场景:
(1)正常情况下新副本需要10秒钟完成准备工作,在此之前无法响应业务请求。
(2)当所有旧副本被替换之后,而新的Pod由于人为配置错误一直无法启动,因此整个应用将无法处理请求,无法对外提供服务,后果很严重!

如果正确配置了HealthCheck,新副本只有通过了Readiness探测才会被添加到Service;如果没有通过探测,现有副本不会被全部替换,业务仍然正常进行。

因此,Readiness探测还提供了用于避免滚动更新中出现这种情况的一些解决办法,比如maxSurge和maxUnavailable两个参数,用来控制副本替换的数量。

继续以上面的YAML配置文件为例,重点关注strategy部分:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  strategy:
    rollingupdate:
      maxSurge: 25%
      maxUnavailable: 25%
  replicas: 3
  selector:
    matchLabels:
      run: web
  template:
    metadata:
      labels:
        run: web
    spec:
      containers:
      - name: web
        image: myhttpd
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /healthy
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5

---
apiVersion: v1
kind: Service
metadata:
  name: web-svc
spec:
  selector:
    run: web
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080

(1)maxSurge:25%=>控制滚动更新过程中副本总数超过预期(这里预期是10个副本replicas:10)的上限,可以是数值也可以是百分比,然后向上取整。这里写的百分比,默认值是25%;
如果预期副本数为10,那么副本总数的最大值为RoundUp(10+1025%)=13个。
(2)maxUnavailable:25%=>控制滚动更新过程中不可用的副本(这里预期是10个副本replicas:10)占预期的最大比例,可以是数值也可以是百分比,然后向下取整,同样地默认值也是25%;
如果预期副本总数为10,那么可用的副本数至少要为10-roundDown(10
25%)=10-2=8个。
综上看来,maxSurge的值越大,初始创建的新副本数量就越多;maxUnavaliable值越大,初始销毁的旧副本数量就越多;

  • 19
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值