K8S--资源控制器&Pod详解&探针

一、资源控制器

  K8S中内建了很多的控制器,这些控制器都是用来空指Pod的具体状态和行为。从控制器的角度来说,Pod可以分为自主式Pod和控制器管理的Pod。自主式的Pod一旦退出,该类型的Pod就不会被重新创建,而控制器管理的Pod,在控制器的生命周期里,始终要维持Pod的副本数量。

  常用的控制器,在K8S--架构及基本概念中已经说过,主要有ReplicationController(旧版本)、ReplaSet、Deployment、DaemonSet、Job、CronJob,具体的概念就不再说多,直接上代码示例。

  对于RC、RS、Deployment的配置可以参见K8S--实战

(一)DaemonSet

  DaemonSet确保全部Node上运行一个Pod副本,当有Node加入集群时,也会为他们新增一个pod,当有Node从集群中被移除时,这些pod也会被回收,删除DaemonSet将会删除其创建的所有pod。最典型的场景就是每个Pod里面都有服务在运行,需要收集服务运行日志,但是Pod是由K8S自动创建或删除的,因此需要使用DaemonSet来设定在每一个Pod中进行日志收集。

#确保只运行一个副本,运行在集群中每一个节点上。(也可以部分节点上只运行一个且只有一个pod副本,如监控ssd硬盘)
# kubectl explain ds
# vim  filebeat.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: my-deamon
  namespace: default
  labels: 
    app: daemonset
spec:
  selector:
    matchLabels:
      app: my-daemonset
  template:
    metadata:
      labels:
        app: my-daemonset
    spec:
      containers:
      - name: daemon-app
        image: nginx:1.16

  使用:kubectl apply -f xxx.yaml执行该配置文件即可,就会在每个节点中创建一个名为my-deamon的pod。

  然后可以使用:kubectl get daemonset查看在运行的daemonset
      

  实际上,K8S自己就在用deamonSet在运行组件系统。

      

 (二)Job

  Job负责处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束。而CronJob则就是在Job上加上了时间调度。

# 我们用Job这个资源对象来创建一个任务,我们定一个Job来执行一个倒计时的任务,定义YAML文件:
apiVersion: batch/v1
kind: Job
metadata:
  name: job-demo
spec:
  template:
    metadata:
      name: job-demo
    spec:
      restartPolicy: Never
      containers:
      - name: counter
        image: busybox
        command:
        - "bin/sh"
        - "-c"
        - "for i in 9 8 7 6 5 4 3 2 1; do echo $i; done"

  上面的配置文件是创建了一个job,并从9输出到1。

  使用命令执行配置文件: kubectl apply -f job.yaml

  查看pod:

      

   可以看到job已经执行完成,然后查看输出日志:

      

   可以看到已经正常打印。

(三)CronJob

  CronJob其实就是在Job的基础上加上了时间调度,我们可以:在给定的时间点运行一个任务,也可以周期性地在给定时间点运行。这个实际上和我们Linux中的crontab就非常类似了。

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: cronjob-demo
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
          - name: hello
            image: busybox
            args:
            - "bin/sh"
            - "-c"
            - "for i in 9 8 7 6 5 4 3 2 1; do echo $i; done"

  执行该配置文件: kubectl apply -f cronjob.yaml

  可以使用以下命令查看:

# 查询cronjob
kubectl get cronjob
# 查询jon ,cronjon会循环多个job
kubectl get job 
# 实时监控查询job 
kubectl get job -w

二、Pod

(一)Pod生命周期

  Pod的status属性描述了Pod处于生命周期的阶段。

阶段 描述
Pending Pod 已被 Kubernetes 接受,但尚未创建一个或多个容器镜像。这包括被调度之前的时间以及通过网络下载镜像所花费的时间,执行需要一段时间。
Running Pod 已经被绑定到了一个节点,所有容器已被创建。至少一个容器正在运行,或者正在启动或重新启动。
Succeeded 所有容器成功终止,也不会重启。
Failed 所有容器终止,至少有一个容器以失败方式终止。也就是说,这个容器要么已非 0 状态退出,要么被系统终止。
Unknown 由于一些原因,Pod 的状态无法获取,通常是与 Pod 通信时出错导致的。

  重启策略:

  对于Pod的重启策略,有Always、OnFailure、Never三种,默认为Always,其中Always表示容器失败时,kubectl会自动重启该容器,Onfailure表示容器终止运行且退出码不为0时重启,Never表示无论什么状态,kubectl都不会重启该容器。

  失败的容器由kubectl以五分钟为上限的指数延迟重新启动(10秒、20秒、40秒),并在成功执行十分钟后重置。

  Pod的生命周期如下图所示:

       

     流程说明:

      (1)初始化容器阶段,初始化Pod中的每一个容器,他们是串行执行的,执行完就退出了。

      (2)启动主容器main container

      (3)在main container刚刚启动之后可以执行post start命令(勾子程序)

      (4)在整个main container执行的过程中可以做两类探测:liveness probe(存活探测)和readiness probe(就绪探测)

      (5)在main container结束前可以执行pre stop命令(勾子程序)

    配置启动后勾子(post start)和终止前勾子(pre stop):

      post start:容器创建之后立即执行,如果失败了就会按照重启策略重启容器

      pre stop:容器终止前立即执行,执行完成后容器将成功终止

    可以使用以下命令查看post start和pre stop的设置格式:

kubectl explain pod.spec.containers.lifecycle.preStop
kubectl explain pod.spec.containers.lifecycle.postStart

(二)Pod init

  1、init容器

  Pod能够持有多个容器,应用运行在容器里面,但是它也可能有一个或多个先于应用程序启动的init容器,init容器与普通容器非常相似,只有以下两点区别:

    (1)init容器总是运行到成功完成为止

    (2)每个init容器都必须在下一个init容器启动之前成功完成

  如果pod的init容器失败,K8S会不断的重启该Pod,直到init容器成功为止,不过也有特里,就是如果将Pod的重启策略restartPolicy设置为Never,他就不会重启了。

  2、init的作用

  因为init容器与应用程序容器的镜像是分离的,所以他们启动相关代码具有以下优势:

    (1)它们可以包含并运行实用工具,但是处于安全考虑,一般不建议在应用程序容器镜像中包含这些实用工具

    (2)他们可以包含实用工具和定制化代码来安装,但是不能出现在现有应用程序镜像中,例如创建镜像没有必要FROM另一个镜像,只需要在安装过程中使用类似sed、awk、python或dig这样的工具

    (3)应用程序镜像可以分离出创建和部署的角色,而没有必要联合他们构建一个单独的镜像。

    (4)init容器使用LinuxNamespace,所以相对应用程序来说,其具有不同文件系统视图,因此,他们能够具有访问Secret的权限,而应用程序容器则不能。

    (5)他们必须在应用程序启动之前运行完成,而应用程序是并行运行的,所以init容器能够提供一种简单的阻塞或延迟应用容器启动的方法,直到满足了一组先决条件。

  3、特殊说明

    (1)在pod启动过程中,init容器会按照顺序在网络和数据卷初始化之后启动(网络和数据卷初始化是在pause容器中),每个容器必须在下一个容器启动前成功退出

    (2)如果由于运行时或失败退出,将导致容器启动失败,它会根据Pod的restartPolicy指定的重启策略来进行处理

    (3)在所有的init容器没有成功之前,Pod将不会变成Ready状态,init容器的端口将不会在Service中进行聚集,正在初始化的Pod处于Pending状态,但应该会将Initializing状态设置为true

    (4)如果Pod重启,所有的Init容器必须重新执行

    (5)对init容器spec的修改被限制在容器的image字段,修改其他字段都不会生效,更改init容器的image字段,等价于重启了Pod

    (6)Init容器具有应用容器的所有字段,除了readinessProbe(就绪检测),因为init容器无法定义不同于完成(Completion)的就绪(readiness)之外的其他状态,这会在验证过程中强制执行。

    (7)在Pod中的每个app和init容器的名称必须唯一,与任何其他容器共享一个名称,会在验证时抛出错误。

  4、演示

  创建一个init容器的配置文件,在该配置文件中,创建了一个initPod叫init-mydb,该initpod需要执行一个连接inint-db的pod

#init-pod.yaml
apiVersion: v1
kind: Pod
metadata:
 name: init-pod
 labels:
   app: nginx
spec:
 containers:
 - name: myapp
   image: nginx
   command: ['sh', '-c', 'echo -n "running at " && date +%T && sleep 600']
 initContainers:
 - name: init-mydb
   image: nginx
   command: ['sh', '-c', 'until nslookup init-db; do echo waiting for init-db;date +%T; sleep 2;echo; done;']

  创建:

#创建
kubectl apply -f init-pod.yaml
#查看pod状态 init没成功
kubectl get pod
#查看log
kubectl logs init-pod -c init-mydb

    

  使用上述命令可以看到,上面创建的容器一直连不上db,导致一直不能完成。

  然后创建db容器

#init-db.yaml
kind: Service
apiVersion: v1
metadata:
 name: init-db
spec:
 ports:
   - protocol: TCP
     port: 80
     targetPort: 3366

  创建

#创建svr
kubectl create -f init-db.yaml
#查看
kubectl get svc

#svc有ip地址,等待init容器运行成功
kubectl get pod

  显示原来的容器已经启动成功。

  删除容器

#删除
kubectl delete -f init-pod.yaml
kubectl delete -f init-db.yaml

三、容器探针

(一)概述  

  探针是由kubectl对容器执行的定期诊断,要执行诊断,kubelet调用由容器实现的Handler,探测的诊断结果有成功、失败和未知三种情况,探测类型有以下三种:

    1、ExecAction:在容器内执行指定命令,如果命令退出时返回码为0则认为诊断成功

    2、TCPSocketAction:对指定端口上的容器的IP地址进行TCP检查,如果端口打开,则认为诊断成功

    3、HTTPGetAction:对指定的端口和路径上的容器IP执行http get请求,如果响应状态码大于200小于400,则认为诊断成功。

  上面提到了存活探测和就绪探测,那么对于两种探测的方式做个解释:

    1、livenessProbe(存活探测):存活探测是用来探测容器是否正在运行,如果探测失败,lubelet会杀死容器,并且容器将受到重启策略的影响。如果容器不提供存活探测,则默认为状态一直为Success。

    2、readinessProbe(就绪探测):就绪探测是用来探测容器是否准备好接收服务请求,如果探测失败,端点控制器将从与Pod匹配的所有Service的端点中删除该Pod的IP地址。初始延迟之前的就绪状态默认为Failure,如果容器不提供就绪探针,则默认状态一直为Success。

(二)就绪探针

  就绪探针配置:

#readinessProbe-httpget
apiVersion: v1 
kind: Pod 
metadata:
  name: readiness-httpget-pod 
  namespace: default
spec:
  containers:
  - name: readiness-httpget-container 
    image: nginx
    imagePullPolicy: IfNotPresent
    readinessProbe:
      httpGet:
        port: 80
        path: /index1.html 
      initialDelaySeconds: 1
      periodSeconds: 3

  以上的配置文件表示创建一个名字为readiness-httpget-pod的就绪探针,readinessProbe的配置就是就绪探针的具体配置,首先使用的是httpget的方式访问80端口,访问路径是/index1.html,延迟一秒访问,每三秒探测一次。

  执行以上yaml文件,查看结果:

      

   可以看到,虽然这个Pod状态为Running,但是却为就绪,使用命令查看原因:

kubectl describe pod readiness-httpget-pod

      

   可以看到是就绪探测结果为404。

  那么就为该pod创建一个/index1.html配置文件

# 进入pod
kubectl exec -it readiness-httpget-pod sh
# 进入nginx默认访问目录
cd /usr/share/nginx/html
# 创建index1.html
 echo 'hello lcl' >> index1.html
# 从pod中退出
exit

  重新查看,该pod已经正常运行

    

   说明:实际生产中,访问的路径一般都是健康检查的路径,这里只是为了做个演示。

(三)存活检测--livenessProbe-exec

  配置文件:

apiVersion: v1 
kind: Pod 
metadata:
  name: liveness-exec-pod
  namespace: default 
spec:
  containers: 
  - name: liveness-exec-container 
    image: hub.lcl.cn/library/busybox:v1
    imagePullPolicy: IfNotPresent 
    command: ["/bin/sh","-c","touch /tmp/live;sleep 60;rm -rf /tmp/live;sleep 3600"] 
    livenessProbe:
      exec:
        command: ["test","-e","/tmp/live"]
      initialDelaySeconds: 1
      periodSeconds: 3

  配置文件简单说明:

    容器(liveness-exec-container)的command命令,创建一个/tmp/live文件,然后休眠60秒,然后将该文件删除,然后再休眠3600秒

    创建了一个存活探针(livenessProbe),检测/tmp/live文件,延迟一秒开始检测,每三秒探测一次。

  执行yaml文件,查看pod运行情况

      

   可以看到,Pod在一段时间后,检测不到/tmp/live文件,自动重启。

(四)存活检测--livenessProbe-Httpget

  yaml文件

apiVersion: v1
kind: Pod
metadata:
  name: liveness-httpget-pod
  namespace: default
spec:
  containers:
  - name: liveness-httpget-container
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    livenessProbe:
      httpGet:
        port: http
        path: /index.html
      initialDelaySeconds: 1
      periodSeconds: 3
      timeoutSeconds: 10

  配置文件说明:

    创建了一个存活探针(livenessProbe),使用httpget方式请求/index.html,检测/tmp/live文件,延迟3秒开始检测,每10秒探测一次。

  运行yaml文件:因为nginx默认就有index.html文件,因此pod状态正常

      

   进入pod中,将index.html删除

# 进入容器
kubectl exec -it liveness-httpget-pod sh
# 切换到nginx默认访问目录
cd /usr/share/nginx/html
# 删除文件
rm -f index.html

      

   可以看到pod就开始重启了。

(五)存活检测-livenessProbe-TCP

  yaml文件

apiVersion: v1
kind: Pod
metadata:
  name: probe-tcp
spec:
  containers:
  - name: probetcp
    image: nginx
    livenessProbe:
      initialDelaySeconds: 5
      timeoutSeconds: 1
      tcpSocket:
        port: 80
      periodSeconds: 3

  配置文件说明:使用tcp检测,延迟5秒开始检测,检测超时时间为1秒,检测端口80,每3秒检测一次。

(六)存活探测和就绪探测

  在实际生产中,一个Pod中应该同时存在就绪探测和存活探测,yaml样例如下所示

apiVersion: v1 
kind: Pod 
metadata:
  name: liveness-httpget-pod 
  namespace: default 
spec:
  containers: 
  - name: liveness-httpget-container 
    image: hub.lcl.com/library/myapp:v1 
    imagePullPolicy: IfNotPresent 
    ports:
    - name: http 
      containerPort: 80 
    readinessProbe:
      httpGet: 
        port: 80
        path: /index1.html 
      initialDelaySeconds: 1 
      periodSeconds: 3 
    livenessProbe:
      httpGet:
        port: http 
        path: /index.html 
      initialDelaySeconds: 1
      periodSeconds: 3
      timeoutSeconds: 10

(七)勾子函数  

  在前面说Pod的生命周期中有start勾子函数和stop勾子函数,就是在启动前和停止后分别要做哪些事情,这里做个演示:

apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-startstop
spec:
  containers:
  - name: lifecycle-container
    image: nginx
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh","-c","echo Hello from the postStart handler > /usr/share/message"]
      preStop:
        exec:
          command: ["/bin/sh","-c","echo Hello container stop"]

   配置文件也比较简单,就是在启动的时候输出一句话到message文件,在pod停止时,再输出一句话

  执行yaml文件,待pod运行后,进入pod,查看message文件

      

   停止的由于已经停止,就看不了~~~

  

posted @ 2021-08-04 15:18  李聪龙  阅读(587)  评论(0编辑  收藏  举报