k8s探测机制之pod健康检查

一:需求来源:

首先来看一下,整个需求的来源:当把应用迁移到 Kubernetes 以后,要如何去保障应用的健康与稳定呢?其实很简单,能够从两个方面来进行加强:html

1,首先是提升应用的可观测性;
2,第二是提升应用的可恢复能力。node

从可观测性上来说,能够在三个方面来去作加强:nginx

1,首先是应用的健康状态上面,能够实时地进行观测;
2,第二个是能够获取应用的资源使用状况;
3,第三个是能够拿到应用的实时日志,进行问题的诊断与分析。web

当出现了问题以后,首先要作的事情是要下降影响的范围,进行问题的调试与诊断。最后当出现问题的时候,理想的情况是:能够经过和 K8s 集成的自愈机制进行完整的恢复。 vim

二:介绍两种探测方式:livenessProbe和ReadnessProbe

  • livenessProbe:[活跃度探测],就是根据用户自定义的规则判断容器是否健康。也叫存活指针,若是 Liveness 指针判断容器不健康,此时会经过 kubelet 杀掉相应的 pod,并根据重启策略来判断是否重启这个容器。若是默认不配置 Liveness 指针,则默认状况下认为它这个探测默认返回是成功的。api

  • ReadnessProbe:[敏捷探测],用来判断这个容器是否启动完成,即 pod 的 状态(指望值)是否 为ready。若是探测的一个结果是不成功,那么此时它会从 pod 上 Endpoint 上移除,也就是说从接入层上面会把前一个 pod 进行摘除(设置pod为不可用的状态),直到下一次判断成功,这个 pod 才会再次挂到相应的 endpoint 之上。

什么是Endpoint?
Endpoint是k8s集群中的一个资源对象,存储在etcd中,用来记录一个service对应的全部pod的访问地址。app

2,Liveness和Readness两种探测机制的使用场景:
Liveness 指针适用场景是支持那些能够从新拉起的应用,而 Readiness 指针主要应对的是启动以后没法当即对外提供服务的这些应用。curl

3,,Liveness和Readness两种探测机制的相同点和不一样点:
相同点是根据探测pod内某个应用或文件,来检查pod的健康情况,不一样点是liveness若是探测失败会重启pod,而readliness则在连续3次探测失败以后,会将pod设置为不可用的状态,并不会重启pod。tcp

4,Liveness 指针和 Readiness 指针支持三种不一样的探测方式:ide

  • 1,第一种是 httpGet。它是经过发送 http Get 请求来进行判断的,当返回码是 200-399 之间的状态码时,标识这个应用是健康的;
  • 2,第二种探测方式是 Exec。它是经过执行容器中的一个命令来判断当前的服务是不是正常的,当命令行的返回结果是 0,则标识容器是健康的;
  • 3,第三种探测方式是 tcpSocket 。它是经过探测容器的 IP 和 Port 进行 TCP 健康检查,若是这个 TCP 的连接可以正常被创建,那么标识当前这个容器是健康的。

第一种探测方式和第三种很是类似,通常经常使用的是第一和第二种的探测方式。

三,探测机制应用实例:

1,LivenessProbe:

方法1:使用exec探测方式,查看pod内某个指定的文件是否存在,若是存在则认为状态为健康的,不然会根据设置的重启重启策略重启pod。

###pod的配置文件:

[root@sqm-master yaml]# vim livenss.yaml
kind: Pod
apiVersion: v1
metadata:
  name: liveness
  labels:
    name: liveness
spec:
  restartPolicy: OnFailure    ##定义重启策略,仅在pod对象出现错误时才重启
  containers:
  - name: liveness
    image: busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/test; sleep 30; rm -rf /tmp/test; sleep 300  #建立文件,而且在30秒后将文件进行删除
    livenessProbe:      #执行活跃度探测
      exec:
        command:
        - cat              #探测/tmp目录下是有test文件,若是有则表明健康,若是没有则执行重启pod策略。
        - /tmp/test
      initialDelaySeconds: 10        #当容器运行多久以后开始探测(单位是s)
      periodSeconds: 5     #探测频率(单位s),每隔5秒探测一次。

探测机制中其余的可选字段:

  • initialDelaySeconds:容器启动后第一次执行探测是须要等待多少秒。
  • periodSeconds:执行探测的频率。默认是10秒,最小1秒。
  • timeoutSeconds:探测超时时间。默认1秒,最小1秒。
  • successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功。默认是1。对于liveness必须是1。最小值是1。
  • failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败。默认是3。最小值是1。
//运行该pod进行测试:
[root@sqm-master yaml]# kubectl  apply -f  livenss.yaml 
pod/liveness created

//监测pod的状态:
会在容器启动10秒后开始探测,且每5s探测一次。
k8s探测机制之pod健康检查
咱们能够看到pod一直在重启中,从上图看到RESTARTS
的次数已经为7次了,缘由是在启动pod时执行了该命令:

/bin/sh -c "touch /tmp/test; sleep 30; rm -rf /tmp/test; sleep 300"

在容器生命的最初30秒内有一个 /tmp/test 文件,在这30秒内 cat /tmp/test命令会返回一个成功的返回码。但30秒后, cat /tmp/test 将返回失败的返回码,会触发pod的重启策略。

//咱们来查看一下pod的Events信息:
[root@sqm-master ~]# kubectl  describe  pod liveness

k8s探测机制之pod健康检查
从上面的事件中能够发现,探测失败,将重启容器,缘由是在指定的目录下没有发现该文件。

方法2:使用httpGet探测方式,运行一个web服务,探测web网页的根目录下是否有指定的文件,也就等同于 “curl -I 容器ip地址:/healthy”。(这里的目录/,指定的是容器内提供web服务的主目录。)

//pod的yaml文件:

[root@sqm-master yaml]# vim http-livenss.yaml
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    name: mynginx
spec:
  restartPolicy: OnFailure      #定义pod重启策略
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    livenessProbe:       #定义探测机制
      httpGet:               #探测方式为httpGet
        scheme: HTTP    #指定协议
        path: /healthy       #指定路径下的文件,若是不存在,探测失败
        port: 80
      initialDelaySeconds: 10       #当容器运行多久以后开始探测(单位是s)
      periodSeconds: 5       #探测频率(单位s),每隔5秒探测一次
---
apiVersion: v1       #关联一个service对象
kind: Service
metadata:
  name: web-svc
spec:
  selector:
    name: mynginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

httpGet探测方式有以下可选的控制字段:

  • host:链接的主机名,默认链接到pod的IP。你可能想在http header中设置”Host”而不是使用IP。
  • scheme:链接使用的schema,默认HTTP。
  • path: 访问的HTTP server的path。
  • httpHeaders:自定义请求的header。HTTP运行重复的header。
  • port:访问的容器的端口名字或者端口号。端口号必须介于1和65525之间。
//运行该pod:
[root@sqm-master yaml]# kubectl  apply -f  http-livenss.yaml 
pod/web created
service/web-svc created

##查看pod运行10秒前的状况:
k8s探测机制之pod健康检查
##最开始的10秒该容器是活着的,且返回的状态码为200.
k8s探测机制之pod健康检查

###10秒后当探测机制开始探测时再次查看pod的状况:
k8s探测机制之pod健康检查

//查看的pod的events:
[root@sqm-master yaml]# kubectl describe  pod web

k8s探测机制之pod健康检查

能够看到返回的状态码为404,表示在网页的根目录下并无找到指定的文件,表示探测失败,且重启4次,状态是completed(完成的状态),说明pod是存在问题的。

2)接下来咱们继续进行检测,使其最终探测成功:
修改pod的配置文件:
[root@sqm-master yaml]# vim http-livenss.yaml
k8s探测机制之pod健康检查

//从新运行pod:
[root@sqm-master yaml]# kubectl  delete -f  http-livenss.yaml 
pod "web" deleted
service "web-svc" deleted
[root@sqm-master yaml]# kubectl apply -f  http-livenss.yaml 
pod/web created
service/web-svc created
//最终咱们查看pod的状态及Events信息:
[root@sqm-master yaml]# kubectl  get pod -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
web    1/1     Running   0          5s    10.244.1.11   node01   <none>           <none>
[root@sqm-master yaml]# kubectl  describe  pod web 
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  71s   default-scheduler  Successfully assigned default/web to node01
  Normal  Pulling    71s   kubelet, node01    Pulling image "nginx"
  Normal  Pulled     70s   kubelet, node01    Successfully pulled image "nginx"
  Normal  Created    70s   kubelet, node01    Created container nginx
  Normal  Started    70s   kubelet, node01    Started container nginx

能够看到pod的状态时正常运行的。

##测试访问网页头部信息:
[root@sqm-master yaml]# curl -I 10.244.1.11

k8s探测机制之pod健康检查
返回的状态码为200,表示这个pod的情况时健康的。

ReadnessProbe探测:

方法1:使用exec探测方式,与iveness相同,探测某个文件是否存在。
//pod的配置文件以下:

[root@sqm-master yaml]# vim readiness.yaml
kind: Pod
apiVersion: v1
metadata:
  name: readiness
  labels:
    name: readiness
spec:
  restartPolicy: OnFailure
  containers:
  - name: readiness
    image: busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/test; sleep 30; rm -rf /tmp/test; sleep 300;
    readinessProbe:   #定义readiness探测方式
      exec:
        command:
        - cat
        - /tmp/test
      initialDelaySeconds: 10
      periodSeconds: 5
//运行该pod:
[root@sqm-master yaml]# kubectl apply -f  readiness.yaml 
pod/readiness created

//检测pod的状态:
k8s探测机制之pod健康检查

//查看pod的Events:
[root@sqm-master yaml]# kubectl  describe  pod readiness

k8s探测机制之pod健康检查
能够看到找不到该文件,表示探测失败,可是readiness机制与liveness机制不一样,它并不会重启pod,而是连续探测3次失败后,则将容器设置为不可用的状态。

方法二:httpGet方式。

[root@sqm-master yaml]# vim http-readiness.yaml
apiVersion: v1
kind: Pod
metadata:
  name: web2
  labels:
    name: web2
spec:
  containers:
  - name: web2
    image: nginx
    ports:
    - containerPort: 81
    readinessProbe:
      httpGet:
        scheme: HTTP    #指定协议
        path: /healthy    #指定路径,若是不存在,则须要进行建立,不然探测失败
        port: 81
      initialDelaySeconds: 10
      periodSeconds: 5
---     
apiVersion: v1       
kind: Service
metadata:
  name: web-svc
spec:
  selector:
    name: web2
  ports:
  - protocol: TCP
    port: 81             
    targetPort: 81
//运行pod:
[root@sqm-master yaml]# kubectl apply -f  http-readiness.yaml 
pod/web2 created
service/web-svc created
//查看pod的状态:
[root@sqm-master yaml]# kubectl  get pod -o wide
NAME        READY   STATUS      RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
readiness   0/1     Completed   0          37m     10.244.2.12   node02   <none>           <none>
web         1/1     Running     0          50m     10.244.1.11   node01   <none>           <none>
web2        0/1     Running     0          2m31s   10.244.1.14   node01   <none>           <none>

k8s探测机制之pod健康检查
查看pod的Events信息,经过探测,能够知道pod是不健康的,且http访问失败。
它并不会重启,而是直接将pod设置为不可用的状态。

健康检测在滚动更新过程当中的应用:

首先咱们经过explain工具来查看更新使用的字段:

[root@sqm-master ~]#  kubectl  explain deploy.spec.strategy.rollingUpdate

k8s探测机制之pod健康检查
能够看到在滚动更新的过程当中有两个参数可用:

  • maxSurge:此参数控制滚动更新过程当中,副本总数超过预期pod数量的上限。能够是百分比,也能够是具体的值,默认为1。若是该值设置为3,则在更新的过程当中,一来则会直接增长三个pod进行更新(固然还要进行探测机制的验证是否更新成功)。该值设置得越大、升级速度越快,但会消耗更多的系统资源。
  • maxUnavailable:此参数控制滚动更新过程当中,不可用的pod的数量,注意是在原pod数量中进行减小,不会计算maxSurge值的范围。若当该值为3时,若是探测失败则在升级的过程当中会有3个pod不可用。该值设置得越大、升级速度越快,但会消耗更多的系统资源。

maxSurge和maxUnavailable的适用场景:
1,若是您但愿在保证系统可用性和稳定性的前提下尽量快地进行升级,能够将 maxUnavailable 设置为 0,同时为 maxSurge 赋予一个较大值。
2,若是系统资源比较紧张,pod 负载又比较低,为了加快升级速度,能够将 maxSurge 设置为 0,同时为 maxUnavailable 赋予一个较大值。须要注意的是,若是 maxSurge 为 0maxUnavailable 为 DESIRED,可能形成整个服务的不可用,此时 RollingUpdate 将退化成停机发布
1)首先咱们建立一个deployment资源对象:

[root@sqm-master ~]# vim app.v1.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-web
spec:
  replicas: 10              #定义副本数量为10个
  template:
    metadata:
      labels:
        name: my-web
    spec:
       containers:
        - name: my-web
          image: nginx
          args:
          - /bin/sh
          - -c
          - touch /usr/share/nginx/html/test.html; sleep 300000; #建立文件,使其在探测时保持pod为健康状态
          ports:
          - containerPort: 80
          readinessProbe:       #使用readiness机制
            exec:
              command:
              - cat
              - /usr/share/nginx/html/test.html
            initialDelaySeconds: 10
            periodSeconds: 10
//运行该pod后,查看pod数量(10个):
[root@sqm-master yaml]# kubectl  get pod -o wide
NAME                      READY   STATUS      RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
my-web-7bbd55db99-2g6tp   1/1     Running     0          2m11s   10.244.2.44   node02   <none>           <none>
my-web-7bbd55db99-2jdbz   1/1     Running     0          118s    10.244.2.45   node02   <none>           <none>
my-web-7bbd55db99-5mhcv   1/1     Running     0          2m53s   10.244.1.40   node01   <none>           <none>
my-web-7bbd55db99-77b4v   1/1     Running     0          2m      10.244.1.44   node01   <none>           <none>
my-web-7bbd55db99-h888n   1/1     Running     0          2m53s   10.244.2.41   node02   <none>           <none>
my-web-7bbd55db99-j5tgz   1/1     Running     0          2m38s   10.244.2.42   node02   <none>           <none>
my-web-7bbd55db99-kjgm2   1/1     Running     0          2m25s   10.244.1.42   node01   <none>           <none>
my-web-7bbd55db99-kkmh2   1/1     Running     0          2m38s   10.244.1.41   node01   <none>           <none>
my-web-7bbd55db99-lr896   1/1     Running     0          2m13s   10.244.1.43   node01   <none>           <none>
my-web-7bbd55db99-rpd8v   1/1     Running     0          2m23s   10.244.2.43   node02   <none>

探测成功,10个副本所有运行。

2)第一次更新:
更新nginx镜像版本,且设置滚动更新策略:

[root@sqm-master yaml]# vim app.v1.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-web
spec: 
  strategy:       #设置滚动更新策略,经过该字段下的rollingUpdate的子属性来设置
    rollingUpdate:
      maxSurge: 3                 #指定在滚动更新过程当中最多可建立3个额外的 pod
      maxUnavailable: 3     #- 指定在滚动更新过程当中最多容许3 pod 不可用
  replicas: 10              
  template:
    metadata:
      labels:
        name: my-web
    spec:
       containers:
        - name: my-web
          image: 172.16.1.30:5000/nginx:v2.0    #更新的镜像为私有仓库中的镜像nginx:v2.0
          args:
          - /bin/sh
          - -c
          - touch /usr/share/nginx/html/test.html; sleep 300000; 
          ports:
          - containerPort: 80
          readinessProbe:       
            exec:
              command:
              - cat
              - /usr/share/nginx/html/test.html
            initialDelaySeconds: 10
            periodSeconds: 10
//执行yaml文件后,查看pod数量:
[root@sqm-master yaml]# kubectl  get pod -o wide
NAME                      READY   STATUS      RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
my-web-7db8b88b94-468zv   1/1     Running     0          3m38s   10.244.2.57   node02   <none>           <none>
my-web-7db8b88b94-bvszs   1/1     Running     0          3m24s   10.244.1.60   node01   <none>           <none>
my-web-7db8b88b94-c4xvv   1/1     Running     0          3m38s   10.244.2.55   node02   <none>           <none>
my-web-7db8b88b94-d5fvc   1/1     Running     0          3m38s   10.244.1.58   node01   <none>           <none>
my-web-7db8b88b94-lw6nh   1/1     Running     0          3m21s   10.244.2.59   node02   <none>           <none>
my-web-7db8b88b94-m9gbh   1/1     Running     0          3m38s   10.244.1.57   node01   <none>           <none>
my-web-7db8b88b94-q5dqc   1/1     Running     0          3m38s   10.244.1.59   node01   <none>           <none>
my-web-7db8b88b94-tsbmm   1/1     Running     0          3m38s   10.244.2.56   node02   <none>           <none>
my-web-7db8b88b94-v5q2s   1/1     Running     0          3m21s   10.244.1.61   node01   <none>           <none>
my-web-7db8b88b94-wlgwb   1/1     Running     0          3m25s   10.244.2.58   node02   <none>           <none>
//查看pod的版本信息:
[root@sqm-master yaml]# kubectl  get deployments. -o wide
NAME     READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES                        SELECTOR
my-web   10/10   10           10          49m   my-web       172.16.1.30:5000/nginx:v2.0   name=my-web

探测成功,10个pod版本所有更新成功。

3)第二次更新:
将镜像版本更新为3.0版本,且设置滚动更新策略。(探测失败)
pod的配置文件以下:

[root@sqm-master yaml]# vim app.v1.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-web
spec:
  strategy:
    rollingUpdate:
      maxSurge: 3                  #定义更新策略,数量依然都是保持3个
      maxUnavailable: 3
  replicas: 10                       #pod数量依然是10个
  template:
    metadata:
      labels:
        name: my-web
    spec:
       containers:
        - name: my-web
          image: 172.16.1.30:5000/nginx:v3.0   #测试镜像版本更新为3.0
          args:
          - /bin/sh
          - -c
          - sleep 300000;        #不在建立指定文件,使其探测失败
          ports:
          - containerPort: 80
          readinessProbe:       
            exec:
              command:
              - cat
              - /usr/share/nginx/html/test.html
            initialDelaySeconds: 10
            periodSeconds: 5
//从新运行pod配置文件:
[root@sqm-master yaml]# kubectl apply -f  app.v1.yaml 
deployment.extensions/my-web configured
//查看pod更新后的数量:
[root@sqm-master yaml]# kubectl  get pod  -o wide
NAME                      READY   STATUS      RESTARTS   AGE    IP            NODE     NOMINATED NODE   READINESS GATES
my-web-7db8b88b94-468zv   1/1     Running     0          12m    10.244.2.57   node02   <none>           <none>
my-web-7db8b88b94-c4xvv   1/1     Running     0          12m    10.244.2.55   node02   <none>           <none>
my-web-7db8b88b94-d5fvc   1/1     Running     0          12m    10.244.1.58   node01   <none>           <none>
my-web-7db8b88b94-m9gbh   1/1     Running     0          12m    10.244.1.57   node01   <none>           <none>
my-web-7db8b88b94-q5dqc   1/1     Running     0          12m    10.244.1.59   node01   <none>           <none>
my-web-7db8b88b94-tsbmm   1/1     Running     0          12m    10.244.2.56   node02   <none>           <none>
my-web-7db8b88b94-wlgwb   1/1     Running     0          12m    10.244.2.58   node02   <none>           <none>
my-web-849cc47979-2g59w   0/1     Running     0          3m9s   10.244.1.63   node01   <none>           <none>
my-web-849cc47979-2lkb6   0/1     Running     0          3m9s   10.244.1.64   node01   <none>           <none>
my-web-849cc47979-762vb   0/1     Running     0          3m9s   10.244.1.62   node01   <none>           <none>
my-web-849cc47979-dv7x8   0/1     Running     0          3m9s   10.244.2.61   node02   <none>           <none>
my-web-849cc47979-j6nwz   0/1     Running     0          3m9s   10.244.2.60   node02   <none>           <none>
my-web-849cc47979-v5h7h   0/1     Running     0          3m9s   10.244.2.62   node02   <none>           <none>

咱们能够看到当前pod的总数量为13个,(包括maxSurge增长额外的数量)由于探测失败,则设置为将3个pod(包括额外的pod)为不可用的状态,但还剩下7个pod可用( 由于maxUnavailable设置为3个),但注意:这7个pod的版本并无更新成功,仍是上一个的版本。

//查看pod的更新后的版本信息:
[root@sqm-master yaml]# kubectl  get deployments. -o wide
NAME     READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES                        SELECTOR
my-web   7/10    6            7           58m   my-web       172.16.1.30:5000/nginx:v3.0   name=my-web

参数解释:
READY :表示用户的指望值
UP-TO-DATE:表示已更新的
AVAILABLE:表示可用的

咱们能够发现已更新的镜像版本数量为6个(包括额外的3个pod),可是为不可用的状态,可是确保可用的的pod数量为7个,可是版本并无更新。

总结:
描述在滚动更新过程当中,探测机制有什么做用?

若是在公司中须要对某个应用中的pod进行更新操做,若是没有探测机制,不管该pod是否是当你已经作好更新工做准备要进行更新的,它都会将该应用中全部的pod进行更新,这样会形成严重的后果,虽然更新后你发现pod的状态是正常的,为了达到controller manager的指望值,READY的值依然是1/1, 可是pod已是从新生成的pod了,表示pod内的数据将会所有丢失。
若是加上探测机制的话,会探测容器内你指定的文件或其余应用是否存在,若是达到你指定的条件,则探测成功,则会对你的pod进行更新,若是探测失败则会设置pod(容器)为不可用,虽然探测失败的容器不可用了,但至少该模块中还有其余以前版本的pod可用,确保该公司该服务的正常运行。可见探测机制是多么的重要啊。

———————— 本文至此结束,感谢阅读 ————————

相关文章
相关标签/搜索